#!/usr/bin/env bash # Structural gates that need no compiler, so they run first and finish instantly. # # Both of these exist because the repository has already been wrong in exactly # these two ways, and in both cases the mistake was invisible: the build stayed # green while the code was not being built. # # scripts/workspace-guard.sh set -euo pipefail root="$(cd "$(dirname "$0")/.." && pwd)" cd "$root" status=0 # --------------------------------------------------------------------------- # 1. Every crate is a member or is explicitly excluded. # # A crate directory named in neither list is not a build error. Cargo simply # never looks at it: no lints, no tests, no compilation. lumbridge-devices sat # that way with 1,127 lines, 19 tests that had never run, and a `mod` statement # pointing at a file that did not exist. Decision 0017 records the same failure # a month earlier with the GPUI shell in `spikes/`. Neither was caught by a # human reading a diff, so it is caught here instead. members="$(sed -n '/^members = \[/,/^]/p' Cargo.toml)" excludes="$(sed -n '/^exclude = \[/,/^]/p' Cargo.toml)" # A single-line `exclude = [...]` does not match the range above; catch it too. excludes="$excludes$(grep -E '^exclude = \[.*\]' Cargo.toml || true)" while IFS= read -r manifest; do dir="$(dirname "$manifest")" dir="${dir#./}" # A crate carrying its own [workspace] table is deliberately independent. if grep -qE '^\[workspace\]' "$manifest"; then continue fi if printf '%s' "$members" | grep -qF "\"$dir\""; then continue fi if printf '%s' "$excludes" | grep -qF "\"$dir\""; then continue fi echo "workspace-guard: $dir/Cargo.toml is in neither workspace.members nor workspace.exclude." >&2 echo " Cargo will never build it, lint it, or run its tests. See AGENTS.md." >&2 status=1 done < <(find apps crates tools -mindepth 2 -maxdepth 2 -name Cargo.toml 2>/dev/null | sort) # --------------------------------------------------------------------------- # 2. The GPUI dependency is the one the decision record chose. # # Checked against Cargo.lock rather than the manifest, because the manifest # states an intent and the lockfile states what would actually be compiled -- # and a manifest `rev` can drift from the revision that was actually resolved, # just as the caret requirement it replaced silently accepted a version nobody # decided on. Asserted in the fast headless job so it gates every push, and not # in the UI job, which is `continue-on-error` and therefore cannot fail one. # # Decision 0023 moved this from published crates.io 0.2.2 to a full-SHA # revision of Zed. Two packages arrive from it, and they must arrive from the # SAME revision: `gpui` is the framework, `gpui_platform` is the entry point and # the Linux backends that the publishable crate no longer contains. A pair that # disagreed would compile against two different framework snapshots. Their # `version` fields differ (0.2.2 and 0.1.0) and mean nothing here -- neither has # been bumped upstream in ten months -- so the revision is what is asserted. # # Changing these lines means writing a decision record. See AGENTS.md, # "Dependencies that are not an agent's decision". expected_gpui_git='https://github.com/zed-industries/zed.git' expected_gpui_rev='ce48461eaadd16c65c31f835511ab96bd3b6e746' expected_gpui_source="git+$expected_gpui_git?rev=$expected_gpui_rev#$expected_gpui_rev" for pkg in gpui gpui_platform; do block="$(awk -v pkg="$pkg" '$0 == "name = \"" pkg "\""{found=1} found{print} found&&/^$/{exit}' Cargo.lock)" if [ -z "$block" ]; then echo "workspace-guard: no $pkg package in Cargo.lock; the shell cannot build." >&2 status=1 continue fi actual_source="$(printf '%s' "$block" | sed -n 's/^source = "\(.*\)"$/\1/p')" if [ "$actual_source" != "$expected_gpui_source" ]; then echo "workspace-guard: the $pkg dependency is not the one the decision record chose." >&2 echo " expected $expected_gpui_source" >&2 echo " found ${actual_source:-}" >&2 echo " Both gpui crates must carry rev $expected_gpui_rev." >&2 echo " A bump is a decision record, not a commit. See AGENTS.md." >&2 status=1 fi done # --------------------------------------------------------------------------- # 3. No GPL crate has come back into the graph. # # `gpui` depends on `ztracing` unconditionally, and `ztracing` -- with the # `zlog` and `ztracing_macro` it pulls -- is GPL-3.0-or-later. That is a # licence problem for an Apache-2.0 product, and it is in the ordinary Linux # build, not behind a feature. The root manifest's # `[patch."https://github.com/zed-industries/zed.git"]` table redirects # `ztracing` at crates/lumbridge-ztracing-shim, a first-party no-op, and the # other two leave the graph with it. # # `cargo deny check licenses` already catches this, so why assert it here as # well? Because deny is a gate a runner can skip. scripts/ci.sh downgrades a # missing cargo-deny to a warning unless LUMBRIDGE_CI_STRICT=1, and that exact # arrangement is how the licence closure went ungated once already -- reported # green on a runner that had never installed the tool. This check needs no # tool, runs in milliseconds, and is what makes deleting the patch table a # failure rather than a quiet relicensing of the product. # # Asserted against Cargo.lock for the same reason as the gate above: the # manifest states an intent, and a `[patch]` whose URL does not match the # source character for character applies to nothing while still looking # correct in a diff. The lockfile states what would actually be compiled. for pkg in ztracing zlog ztracing_macro; do block="$(awk -v pkg="$pkg" '$0 == "name = \"" pkg "\""{found=1} found{print} found&&/^$/{exit}' Cargo.lock)" [ -n "$block" ] || continue actual_source="$(printf '%s' "$block" | sed -n 's/^source = "\(.*\)"$/\1/p')" case "$actual_source" in "") # No source line: a path package, which is the patched shim. Correct. ;; *) echo "workspace-guard: $pkg resolves to $actual_source, not the local shim." >&2 echo " That crate is GPL-3.0-or-later and Lumbridge is Apache-2.0." >&2 echo " The [patch] table in Cargo.toml is missing, misspelled, or" >&2 echo " no longer matches the source it is meant to replace." >&2 echo " See crates/lumbridge-ztracing-shim/src/lib.rs." >&2 status=1 ;; esac done if ! grep -qF '[patch."https://github.com/zed-industries/zed.git"]' Cargo.toml; then echo "workspace-guard: the Zed [patch] table is gone from Cargo.toml." >&2 echo " Without it gpui compiles GPL-3.0-or-later ztracing." >&2 status=1 fi if [ "$status" = 0 ]; then echo "workspace-guard: crate membership, the pinned UI dependency, and the GPL patch are as recorded." fi exit "$status"