Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,32 @@ jobs:

- name: cargo test (shipped Windows crates)
run: cargo test -p gl -p git-remote-gitlawb

# gitlawb-core is embedded by every consumer (gl, git-remote-gitlawb, the node
# daemon), so it must stay lean. This gate fails if gitlawb-core's normal
# (non-dev, non-build) dependency tree gains any crate not on the allowlist in
# ci/gitlawb-core-allowed-deps.txt. Exhaustive-by-construction: a new heavy
# dependency reds CI whether or not anyone thought to ban it, which a denylist
# cannot do. Regen instructions live in the allowlist header.
core-deps-purity:
name: gitlawb-core dependency purity
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check out repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- name: Set up Rust toolchain
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # stable
with:
toolchain: stable

- name: Cache cargo
uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
with:
key: core-deps-purity

- name: Check gitlawb-core dependency allowlist
run: bash scripts/check-gitlawb-core-deps.sh
112 changes: 112 additions & 0 deletions ci/gitlawb-core-allowed-deps.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Dependency allowlist for the `gitlawb-core` crate.
#
# gitlawb-core is the shared-primitives crate every consumer embeds (the `gl`
# CLI, git-remote-gitlawb, the node daemon). It must stay lean so those
# consumers do not inherit daemon-weight dependencies. This file is the source
# of truth for the crates gitlawb-core's NORMAL (non-dev, non-build) transitive
# dependency closure is allowed to contain. CI (`scripts/check-gitlawb-core-deps.sh`,
# wired into the `core-deps-purity` job in .github/workflows/pr-checks.yml)
# fails if gitlawb-core's tree contains any crate not listed here.
#
# The allowlist is exhaustive-by-construction: a NEW dependency reds CI whether

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the dependency-gate wording.

reds CI should be rewritten as turns CI red for grammatical correctness.

Proposed fix
-# of construction: a NEW dependency reds CI whether
+# of construction: a NEW dependency turns CI red whether
🧰 Tools
🪛 LanguageTool

[style] ~11-~11: Consider shortening this phrase to just ‘whether’, unless you mean ‘regardless of whether’.
Context: ...-construction: a NEW dependency reds CI whether # or not anyone thought to ban it, which a denyl...

(WHETHER)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ci/gitlawb-core-allowed-deps.txt` at line 11, Update the allowlist comment
describing new dependency behavior to replace “reds CI” with “turns CI red,”
preserving the rest of the wording unchanged.

Source: Linters/SAST tools

# or not anyone thought to ban it, which a denylist cannot do.
#
# Measured in-workspace, so feature unification across the workspace can, in
# rare cases, surface a crate here that gitlawb-core would not pull standalone.
# An unexpected new entry is a prompt to check what pulled it in, not noise to
# rubber-stamp.
#
# Regenerate (from repo root, after an INTENTIONAL dependency change):
# cargo tree -p gitlawb-core --edges normal --prefix none \
# | sed -E 's/ v[0-9].*$//' \
# | grep -v '^gitlawb-core$' \
# | sort -u
# then paste the result below this header block. (The checker snapshots and
# restores Cargo.lock; a manual regen may refresh it — `git checkout Cargo.lock`
# afterward if you did not intend that.)
#
# Lines starting with `#` and blank lines are ignored by the checker.
aead
anyhow
base-x
base256emoji
base64
base64ct
block-buffer
cfg-if
chacha20
chacha20poly1305
chrono
cid
cipher
const-oid
const-str
core2
cpufeatures
crypto-common
crypto_box
crypto_secretbox
curve25519-dalek
curve25519-dalek-derive
data-encoding
data-encoding-macro
data-encoding-macro-internal
der
digest
ed25519
ed25519-dalek
equivalent
generic-array
getrandom
hashbrown
hex
iana-time-zone
indexmap
inout
itoa
libc
match-lookup
memchr
multibase
multihash
multihash-codetable
multihash-derive
multihash-derive-impl
num-traits
opaque-debug
pem-rfc7468
pkcs8
poly1305
ppv-lite86
proc-macro-crate
proc-macro2
quote
rand
rand_chacha
rand_core
salsa20
serde
serde_core
serde_derive
serde_json
sha2
signature
spki
subtle
syn
synstructure
thiserror
thiserror-impl
toml_datetime
toml_edit
toml_parser
typenum
unicode-ident
universal-hash
unsigned-varint
uuid
winnow
zerocopy
zeroize
zeroize_derive
zmij
71 changes: 71 additions & 0 deletions scripts/check-gitlawb-core-deps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env bash
#
# Dependency-purity gate for the `gitlawb-core` crate.
#
# gitlawb-core is embedded by every consumer (the gl CLI, git-remote-gitlawb,
# the node daemon), so it must stay lean. This script recomputes gitlawb-core's
# NORMAL (non-dev, non-build) transitive dependency set and fails if it contains
# any crate not present in ci/gitlawb-core-allowed-deps.txt.
#
# Hard-fail direction: a crate present now but NOT allowlisted. That is the case
# the gate exists to catch (core silently gaining a heavy dependency).
# Informational only: an allowlisted crate no longer present (stale entry) — a
# legitimate dependency removal should not red CI, so it is reported, not failed.
#
# Runnable from anywhere in the repo.
set -euo pipefail

ROOT="$(git rev-parse --show-toplevel)"
ALLOW="$ROOT/ci/gitlawb-core-allowed-deps.txt"

if [ ! -f "$ALLOW" ]; then
echo "ERROR: allowlist not found at $ALLOW" >&2
exit 1
fi

# `cargo tree` resolves like the build/test jobs (no --locked): the committed
# Cargo.lock can lag the manifests, and --locked would red this gate for
# lock-staleness reasons unrelated to gitlawb-core's dependencies. Resolving can
# refresh Cargo.lock as a side effect, so snapshot and restore it — this check
# must never leave the working tree dirty when run locally.
lock_backup="$(mktemp)"
cp "$ROOT/Cargo.lock" "$lock_backup"
restore_lock() { cp "$lock_backup" "$ROOT/Cargo.lock"; rm -f "$lock_backup"; }
trap restore_lock EXIT

# Current normal-dependency closure of gitlawb-core, one crate name per line.
# Must match the regen command documented in the allowlist header exactly.
current="$(
cargo tree -p gitlawb-core --edges normal --prefix none --manifest-path "$ROOT/Cargo.toml" \
| sed -E 's/ v[0-9].*$//' \
| grep -v '^gitlawb-core$' \
| sort -u
Comment on lines +39 to +42

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
git ls-files scripts/check-gitlawb-core-deps.sh ci/gitlawb-core-allowed-deps.txt

printf '\n== script excerpt ==\n'
cat -n scripts/check-gitlawb-core-deps.sh | sed -n '30,55p'

printf '\n== allowlist excerpt ==\n'
cat -n ci/gitlawb-core-allowed-deps.txt | sed -n '1,40p'

Repository: Gitlawb/node

Length of output: 3420


🌐 Web query:

cargo tree --target all default host target dependencies documentation

💡 Result:

The cargo tree command in Rust is used to visualize the dependency graph of a project [1][2]. By default, when no target is specified, cargo tree displays the dependencies for the host platform [1][3]. The --target flag allows you to filter the dependency graph based on a specific target triple [1][4]. When you provide the value all—specifically using --target all—cargo tree includes all platform-specific dependencies in the graph, regardless of the host platform [1][2]. This is particularly useful for identifying dependencies that are only pulled in when building for specific operating systems or architectures (e.g., dependencies guarded by platform-specific cfg attributes) [5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== cargo tree help (if available) ==\n'
cargo tree --help | sed -n '1,220p'

Repository: Gitlawb/node

Length of output: 142


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
for p in [Path("scripts/check-gitlawb-core-deps.sh"), Path("ci/gitlawb-core-allowed-deps.txt")]:
    print(f"\n### {p}")
    text = p.read_text()
    for needle in ["--target all", "cargo tree -p gitlawb-core", "Regenerate (from repo root"]:
        print(needle, "=>", needle in text)
PY

Repository: Gitlawb/node

Length of output: 142


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== references ==\n'
rg -n "gitlawb-core-allowed-deps|check-gitlawb-core-deps|cargo tree -p gitlawb-core" -S .

printf '\n== package metadata relevant to target-specific deps ==\n'
cat -n Cargo.toml | sed -n '1,220p'

Repository: Gitlawb/node

Length of output: 142


Include all Cargo targets in the dependency allowlist check.

cargo tree here only walks the host platform, so target-specific crates can bypass the allowlist. Add --target all to the checker and the regeneration command in ci/gitlawb-core-allowed-deps.txt.

📍 Affects 2 files
  • scripts/check-gitlawb-core-deps.sh#L39-L42 (this comment)
  • ci/gitlawb-core-allowed-deps.txt#L19-L23
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-gitlawb-core-deps.sh` around lines 39 - 42, Add --target all to
the cargo tree command in scripts/check-gitlawb-core-deps.sh and to the
regeneration command documented in ci/gitlawb-core-allowed-deps.txt, ensuring
both dependency allowlist checks include every Cargo target.

Source: MCP tools

)"

# Allowlist with comments and blank lines stripped.
allowed="$(grep -vE '^[[:space:]]*(#|$)' "$ALLOW" | sort -u)"
Comment on lines +38 to +46

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail

printf '--- file outline ---\n'
git ls-files scripts/check-gitlawb-core-deps.sh
printf '\n--- relevant lines ---\n'
cat -n scripts/check-gitlawb-core-deps.sh | sed -n '1,140p'

printf '\n--- pipeline behavior probe ---\n'
tmpdir="$(mktemp -d)"
cat >"$tmpdir/probe.sh" <<'SH'
#!/usr/bin/env bash
set -o pipefail

probe() {
  label="$1"
  shift
  if out="$("$@")"; then
    printf '%s: ok, out=%q, status=%s\n' "$label" "$out" "$?"
  else
    st=$?
    printf '%s: fail, out=%q, status=%s\n' "$label" "$out" "$st"
  fi
}

probe grep_all_filtered bash -lc "printf 'a\nb\n' | grep -v . | cat"
probe grep_some_left bash -lc "printf 'a\nb\n' | grep -v '^a$' | cat"
probe sed_all_filtered bash -lc "printf 'a\nb\n' | sed '/./d' | cat"
probe count_empty bash -lc "current=''; if [ -n \"\$current\" ]; then dep_count=\"\$(printf '%s\n' \"\$current\" | wc -l | tr -d ' ')\"; else dep_count=0; fi; printf 'dep_count=%s\n' \"\$dep_count\""
probe count_nonempty bash -lc "current='x
y'; if [ -n \"\$current\" ]; then dep_count=\"\$(printf '%s\n' \"\$current\" | wc -l | tr -d ' ')\"; else dep_count=0; fi; printf 'dep_count=%s\n' \"\$dep_count\""
SH
bash "$tmpdir/probe.sh"

Repository: Gitlawb/node

Length of output: 241


🏁 Script executed:

set -euo pipefail
cat -n scripts/check-gitlawb-core-deps.sh | sed -n '1,140p'
python3 - <<'PY'
import subprocess, textwrap, os, tempfile, pathlib

def run(cmd):
    p = subprocess.run(cmd, shell=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
    print(f"$ {cmd}\nstatus={p.returncode}\n{p.stdout}")

run("bash -lc \"set -o pipefail; printf 'a\\nb\\n' | grep -v . | cat\"")
run("bash -lc \"set -o pipefail; printf 'a\\nb\\n' | grep -v '^a$' | cat\"")
run("bash -lc \"set -o pipefail; printf 'a\\nb\\n' | sed '/./d' | cat\"")
run("bash -lc \"current=''; if [ -n \\\"$current\\\" ]; then dep_count=\\\"$(printf '%s\\n' \\\"$current\\\" | wc -l | tr -d ' ')\\\"; else dep_count=0; fi; printf 'dep_count=%s\\n' \\\"$dep_count\\\"\"")
PY

Repository: Gitlawb/node

Length of output: 3942


🏁 Script executed:

python3 - <<'PY'
import subprocess, textwrap

cases = [
    ("grep pipeline, all filtered", r"""bash -lc 'set -euo pipefail; current="$(printf "gitlawb-core\n" | grep -v "^gitlawb-core$" | sort -u)"; printf "current=%q\n" "$current"'"""),
    ("grep pipeline, one dep remains", r"""bash -lc 'set -euo pipefail; current="$(printf "gitlawb-core\nfoo\n" | grep -v "^gitlawb-core$" | sort -u)"; printf "current=%q\n" "$current"'"""),
    ("count empty current", r"""bash -lc 'current=""; printf "%s\n" "$current" | wc -l | tr -d " "'"""),
]
for label, cmd in cases:
    p = subprocess.run(cmd, shell=True, executable="/bin/bash", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
    print(f"== {label} ==")
    print(f"status={p.returncode}")
    print(p.stdout)
PY

Repository: Gitlawb/node

Length of output: 291


Avoid grep -v in these command substitutions. With set -o pipefail, current/allowed can fail when the filter removes every line, and the summary count prints 1 for an empty current value. scripts/check-gitlawb-core-deps.sh:38-46,71

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-gitlawb-core-deps.sh` around lines 38 - 46, Update the current
and allowed dependency command substitutions in the script to avoid grep -v
pipelines that return failure when all lines are filtered under pipefail; use
filtering that preserves successful empty output. Also update the summary count
near the dependency comparison to report zero for an empty current value instead
of counting it as one.


# comm needs sorted input; both sides are sorted above.
offenders="$(comm -23 <(printf '%s\n' "$current") <(printf '%s\n' "$allowed"))"
stale="$(comm -13 <(printf '%s\n' "$current") <(printf '%s\n' "$allowed"))"

if [ -n "$stale" ]; then
echo "NOTE: allowlisted crates no longer in gitlawb-core's dependency tree"
echo " (safe to prune from ci/gitlawb-core-allowed-deps.txt):"
printf ' %s\n' $stale
echo
fi

if [ -n "$offenders" ]; then
{
echo "ERROR: gitlawb-core gained dependencies not on the allowlist:"
printf ' %s\n' $offenders
echo
echo "gitlawb-core must stay embeddable and lean. If a new dependency is"
echo "intentional, add it to ci/gitlawb-core-allowed-deps.txt (regen command"
echo "is in that file's header). Otherwise, drop the dependency."
} >&2
exit 1
fi

echo "gitlawb-core dependency purity: OK ($(printf '%s\n' "$current" | wc -l | tr -d ' ') normal deps, all allowlisted)."
Loading