vike
Developer

Supply chain

What CI may download and run on the boxes that sign real orders, how much unsafe code the workspace holds, and the single transport stack cargo-deny enforces.

Vike Trader's whole workspace compiles into one order-signing binary, and every workflow in the product repository runs on self-hosted runners — the machines that hold the credential store and run the live trading daemons. Three gates carry the consequences.

What CI may fetch

crates/vike-ops/tests/supply_chain_gate.rs opens with the fact that shapes it: the runners use clean: false and a persistent per-runner CARGO_HOME, so a tool fetched by a CI step "lands on the trading box and stays there" — and both tools it governs then execute everything. cargo-nextest runs every test binary in the workspace; sccache is installed as RUSTC_WRAPPER and wraps every rustc invocation on that runner thereafter. The policy predated the gate and was already false in two places when the gate was written, which is the whole argument for gating it.

  • every_action_reference_is_sha_pinned — every third-party uses: names a full 40-character commit SHA. Two references had floating tags while ~25 others were SHAs. A major-version tag is retagged on every point release, and even a patch-specific tag "is only a POINTER: a tag can be force-moved onto any commit, so it names an intent, not an artifact."
  • every_downloaded_archive_is_checksum_verified — a downloaded tool archive needs a sha256sum -c in the same file. cargo-nextest was fetched from a mutable URL piped straight into tar; sccache was version-pinned but unverified. A curl | tar "cannot be verified even in principle: the bytes are extracted before anything can look at them." The failure message adds the part people get wrong — take the sum from the vendor's published .sha256 asset, because hashing the file you just downloaded verifies nothing.
  • no_tool_download_resolves_a_mutable_pointer — no /latest/. Kept separate because a /latest/ URL with a hard-coded sum is the worst combination: it breaks CI the moment upstream publishes, "which reads as flakiness and invites deleting the sum."

Detection is on shape, not spelling. is_tool_fetch records that its first draft keyed on a .tar.gz suffix and so would not have caught the very line the change removed — that URL has no extension at all. It now matches bytes piped into an extractor or interpreter, a URL that is plainly an archive, or an output flag naming one.

What the gate does not prove

It proves a download is version-pinned and sum-checked. It cannot prove the sum is the right one, and it says nothing about staleness: Dependabot maintains uses: SHA pins but cannot see a URL inside a run: block, so those pins are manual maintenance forever.

How much unsafe code exists

crates/vike-ops/tests/unsafe_and_toolchain_gate.rs turns "how much unsafe is in this binary" into a number. The root manifest declares unsafe_code = "forbid", but cargo applies a workspace lint table to a member only if that member opts in — so a crate that never wrote those two lines sits silently outside the policy. One crate did exactly that; it had no unsafe in it, "which is precisely why no human was ever going to find it."

So the gate walks the derived member roster, asks each manifest whether it inherits, and ratchets. UNSAFE_EXEMPT may shrink, never grow, and holds two argued rows: the FXCM bridge, whose sys.rs is a C++ FFI shim, and vike-core, which uses deny rather than the workspace forbid so a per-site #[allow(unsafe_code)] can carve out audited OS-mmap entry points while every other unsafe stays denied. UNSAFE_SITES is the literal answer — 15 sites, 4 files, 2 crates — counted per file rather than flagged, because the interesting regression is an already-blessed file growing a fifteenth site, which a boolean cannot see. UNSAFE_ALLOW_SITES is the separate carve-out ledger, and the two agreeing is itself the check.

The same file pins the toolchain: the channel is written in six places, and the_toolchain_version_has_exactly_one_value makes them agree by test. Measured 2026-08-06, the boxes did not agree on their default toolchain, so the pin is the only reason those environments compile the same code with the same compiler.

One transport stack

deny.toml is the single scanner over every locked package, run with all-features = true so it sees the full attack surface rather than the default build. [advisories] runs stricter than cargo-deny's defaults — yanked = "deny", unmaintained = "all" — with ignore entries as the only escape hatch, each carrying a reason and a recheck trigger; [sources] denies unknown registries and git dependencies outright.

[bans] denies wildcard versions and carries the machine-enforced "ONE transport stack" list: no second HTTP client (reqwest, isahc, curl → ureq), no second WebSocket (tokio-tungstenite, async-tungstenite → tungstenite), no alternative TLS (native-tls, openssl → rustls; aws-lc-rs → ring), no second curve implementation (secp256k1 → k256). Every entry is green today and was proven to bite by temporarily adding a second client and reverting. Shared HTTP type and parse libraries are deliberately not banned — banning them would redden the gate rather than catch a real second stack.

[licenses] sets private = { ignore = true }, and that exemption is what keeps the gate green: the licence is source-available rather than OSI-approved, so it has no SPDX identifier and could never appear in the allow list. Free. Source-available under FSL-1.1; every release becomes Apache-2.0 two years on.

just deny audits the source lockfile at merge. Its release-time twin just audit-bin builds a shipped binary with an embedded SBOM via cargo-auditable and scans the artifact against RustSec — what the distributable actually links.

Related: Release gates · Drift gates · Architecture

On this page