Files
fips/testing/check-comment-refs.sh
Johnathan Corgan 5119b0f5f3 Add a workspace with an empty no_std fips-core crate
Start the no_std core as a second workspace member. The crate is empty:
it holds the rule that code in it builds for any target with an
allocator (no std, no async runtime, no OS calls, no target cfg), and
the root crate does not depend on it yet, so nothing that builds or
ships changes. The root package stays first in Cargo.toml with its
version line untouched, since the packaging scripts read the release
version from it, and the core is fixed at 0.0.0 with publish = false so
releases keep a single bump site.

default-members names both crates, so the bare cargo clippy and test
commands in local CI and GitHub CI cover the core as well as the root
package.

Add a fence to both runners: clippy and the tests of the core on its
own, so a dependency feature that only the root crate enables cannot
hide one the core needs.

Pin the privileged interface-binding step to the fips package's lib
test binary. With two lib test executables, `tail -1` picked whichever
cargo listed last, and the core's binary passes the ethernet filter
having run nothing. The step now also runs under bash with pipefail and
fails unless at least one test passed.

Widen the comment-reference, portable-atomics and log-string guards to
core/src/, and add core/ to the stale-binary checks of the mdns,
native-api and deb-install harnesses, so code that later moves into the
core stays checked. Copy core/ into the two nostr relay example images,
whose build would otherwise fail to load the workspace manifest, and
give the standalone BLE spike under testing/ble an empty workspace table
of its own, so cargo keeps loading it as its own project rather than
refusing it as an unlisted member of the root workspace.


Add core/README.md for anyone reading or adding code under core/: what the crate is for, the rules its code follows, how to add a dependency without letting workspace feature unification hide a missing feature, how tests work under no_std, a checklist for moving a module in from the root crate, and the checks to run before a change.
2026-10-11 17:08:56 +00:00

219 lines
11 KiB
Bash
Executable File

#!/bin/bash
# ── Comment and document reference guard ────────────────────────────────────
# Every reference a source comment or committed document makes must resolve
# for a reader who has only this repository.
#
# A comment that names a private planning artifact — by identifier, by file
# path, or in programme vocabulary that has no in-repo referent — is dead text
# to everyone outside the workspace that holds the artifact, and it publishes
# the existence and shape of that workspace to everyone else. A hand-run grep
# closes the population that exists on the day it runs; this closes it for
# every commit after.
#
# Three checks, each a `git grep` at HEAD rather than over the working tree,
# because the thing being gated is what is committed:
#
# 1. identifiers, repo-wide. A local item identifier anywhere in the tree.
# Repo-wide because packaging/, testing/ and the workflow files are as
# public as src/ — more so in the packaging case, which ships to users.
# 2. document paths, scoped to the crate sources (src/ and core/src/). A
# comment there citing an *.md path that does not exist in the tree at
# the checked commit. This is a resolvability rule rather than a
# denylist, so it catches private documents nobody has thought of.
# Scoped to the crate sources because resolving the whole tree's
# relative documentation links against the repository root is a
# different checker with its own population to triage first.
# 3. programme vocabulary, repo-wide in two scopes. Phase, rung,
# milestone and step labels, and phrases such as "architectural plan",
# that name a plan a reader cannot open. VOCAB_PAT runs over the whole
# tree except this file, which would match itself. SRC_VOCAB_PAT adds
# two alternatives that run over the crate sources (src/ and core/src/)
# only, because outside them they are legitimate prose: "in Step N" is
# the documentation's own step cross-referencing, and "this PR" is how
# CONTRIBUTING.md and PR-REVIEW.md talk about the PR under review. This
# file is the only copy of both patterns.
#
# The tree-wide alternatives had no hit outside src/ when the scope was
# widened. The one most likely to catch legitimate prose later is
# \b[RQ][0-9]\b, which matches "Q4" or "R2" as words. If it does,
# rephrase the text or move that alternative to SRC_VOCAB_PAT; do not
# exclude the file or directory, which drops every other alternative
# with it.
#
# Known coverage gaps, recorded rather than discovered:
# - a bare "milestone" in some other phrasing (the narrow alternatives keep
# the Tor bootstrap loop in src/transport/tor/mod.rs out of check 3);
# - the CATEGORY_D / CATEGORY_E code identifiers and test names, which
# check 3's case-sensitive Category-[A-Z] deliberately does not match;
# - a document path outside the crate sources. Check 2 resolves a token
# against the repository root, but documentation links elsewhere are
# relative to the citing file, so widening it means a different resolver
# and a triage of the links that fail it;
# - a private-workspace directory cited in lowercase (an issues/... or
# tasks/... path with no .md token). Check 1's identifier prefix is
# case-sensitive and check 2 only resolves *.md tokens;
# - programme phrasing too common to deny, such as "a later step" or
# "the plan": an alternative for it would red legitimate text, so it
# passes check 3 by design;
# - bare commit hashes. Whether a hash resolves depends on the clone's
# object database, and GitHub CI clones are shallow, so a check would
# read differently on different hosts. The rule applied by hand is that
# a comment cites a commit only if a trunk branch contains it;
# - a reference to a private artifact made in free prose with no marker at
# all, at any scope: no check here matches it;
# - a pathspec typo introduced after this file lands. git grep returns 1
# with empty output for a pathspec that matches nothing, which is
# indistinguishable from health. The non-empty-population assertion below
# narrows that for the crate-source checks and closes nothing for check 1.
#
# Exit 0 = every reference resolves. Exit 1 = one or more do not; every hit is
# printed, not just the first. Exit 2 = the check could not look (not in a work
# tree, wrong directory, empty pathspec, or a git-level failure); never treated
# as a pass.
# ─────────────────────────────────────────────────────────────────────────────
set -uo pipefail
# A pathspec is resolved against the current directory even when a rev is
# supplied, and a run from the wrong directory returns rc 1 with empty output
# on every check — the same shape as a clean tree. Assert the directory, then
# assert the post-condition rather than trusting the cd: `cd ""` succeeds and
# does not move, so a one-line form silently leaves the script where it began
# whenever the command substitution comes back empty.
ROOT=$(git rev-parse --show-toplevel 2>/dev/null) \
|| { echo "check-comment-refs: not inside a git work tree" >&2; exit 2; }
[[ -n "$ROOT" ]] \
|| { echo "check-comment-refs: empty work-tree root" >&2; exit 2; }
cd "$ROOT" || exit 2
[[ -z "$(git rev-parse --show-prefix)" ]] \
|| { echo "check-comment-refs: not at the work-tree root" >&2; exit 2; }
# Each crate-source pathspec must select something. wc -l is deliberate where
# the rest of this script preserves exit statuses: it always exits 0, so the
# decision is made on n and never on a status, and a failing git ls-tree yields
# n=0 and fires the assertion. This covers checks 2 and 3 only; check 1's
# pathspec is "." and stays non-empty from anywhere, so its wrong-directory
# case is covered by the --show-prefix assertion above and its
# mistyped-pathspec case by nothing. Check 3's tree-wide half uses "." with
# exclusions and is in the same position as check 1.
SRC_DIRS=(src/ core/src/)
for dir in "${SRC_DIRS[@]}"; do
n=$(git ls-tree -r --name-only HEAD -- "$dir" | wc -l)
(( n > 0 )) || { echo "check-comment-refs: pathspec $dir matched no files" >&2; exit 2; }
done
# Deliberately broad: the year group is optional, so the three-digit form is
# caught as well, and the separator is optional so underscores and spaces are
# caught alongside hyphens. Narrowing this is how a whole class goes unguarded
# while every break-check still passes.
ID_PAT='(TASK|ISSUE|IDEA|QUICK|RECUR)[-_ ]?(20[0-9]{2}[-_ ])?[0-9]{3,4}'
# VOCAB_PAT runs tree-wide. This text matches itself, so the tree-wide run
# excludes this one file by name; never exclude testing/, which holds real
# hits a directory-wide exclusion would drop. SRC_VOCAB_PAT is VOCAB_PAT
# plus the alternatives that are legitimate prose outside the crate sources.
VOCAB_PAT='\b[RQ][0-9]\b|Category-[A-Z]|\bumbrella\b|refactor steps?|\bpre-scopes\b|R0 stub|read-isolation|cut over yet|Cutover begins|(the|this) milestone|Milestone-|[Aa]rchitectural plan|[Ff]ollow-up wiring'
SRC_VOCAB_PAT="$VOCAB_PAT"'|in Step [0-9]|\b[Tt]his PR\b'
MD_PAT='[A-Za-z0-9_./-]+\.md\b'
FAILED=0
# ── Check 1: local item identifiers, repo-wide ──────────────────────────────
# The capture preserves git grep's status instead of flattening it with
# `|| true`: a legitimate no-hit run exits 1, but so would a malformed
# pathspec magic, an unresolvable rev or a bad regex exit 128, and collapsing
# both into "clean" is the single likeliest way this script reports green
# while checking nothing. The hit decision is made on the output; the
# could-not-look decision is made on the status.
rc=0
out=$(git grep -nEI "$ID_PAT" HEAD -- .) || rc=$?
if (( rc > 1 )); then
echo "check-comment-refs: check 1 grep failed (rc=$rc)" >&2
exit 2
fi
if [[ -n "$out" ]]; then
printf '%s\n' "$out" \
| sed -E 's|^HEAD:([^:]*):([0-9]+):|\1:\2: names a local work item: |'
FAILED=1
fi
# ── Check 2: document paths in the crate sources must resolve in-repo ───────
rc=0
md_lines=$(git grep -nI '\.md' HEAD -- "${SRC_DIRS[@]}") || rc=$?
if (( rc > 1 )); then
echo "check-comment-refs: check 2 grep failed (rc=$rc)" >&2
exit 2
fi
# Drop any line carrying a URL before extracting a token from it. Keying the
# skip on the extracted token cannot work: ':' is outside the token character
# class, so the scheme is stripped first and what survives does not begin with
# "http". Inert on today's tree, and kept so a future URL citation does not red.
cited=$(printf '%s\n' "$md_lines" | grep -vE 'https?://')
declare -A CITES=()
while IFS= read -r line; do
[[ -n "$line" ]] || continue
loc=${line#HEAD:}
loc=$(printf '%s' "$loc" | sed -E 's|^([^:]*):([0-9]+):.*|\1:\2|')
content=$(printf '%s' "$line" | sed -E 's|^HEAD:[^:]*:[0-9]+:||')
while IFS= read -r tok; do
[[ -n "$tok" ]] || continue
CITES["$tok"]+="$loc "
done < <(printf '%s\n' "$content" | grep -oE "$MD_PAT")
done <<< "$cited"
if (( ${#CITES[@]} > 0 )); then
while IFS= read -r tok; do
[[ -n "$tok" ]] || continue
lrc=0
lsout=$(git ls-tree HEAD -- "$tok" 2>/dev/null) || lrc=$?
# A '../'-prefixed or absolute token makes git ls-tree exit 128 with
# "is outside repository". That is neither a hit nor clean: the check
# could not look, and reporting it as a hit would red a legitimate
# citation while reporting it as clean would hide one.
if (( lrc != 0 )); then
echo "check-comment-refs: could not resolve '$tok' (git ls-tree rc=$lrc)" >&2
exit 2
fi
if [[ -z "$lsout" ]]; then
for loc in ${CITES["$tok"]}; do
printf '%s: cites %s, which does not exist in this repository\n' \
"$loc" "$tok"
done
FAILED=1
fi
done < <(printf '%s\n' "${!CITES[@]}" | sort)
fi
# ── Check 3: programme vocabulary, crate sources and the rest of the tree ───
vocab_check() {
local pat=$1
shift
local rc=0 out
out=$(git grep -nEI "$pat" HEAD -- "$@") || rc=$?
if (( rc > 1 )); then
echo "check-comment-refs: check 3 grep failed (rc=$rc)" >&2
exit 2
fi
if [[ -n "$out" ]]; then
printf '%s\n' "$out" \
| sed -E 's|^HEAD:([^:]*):([0-9]+):|\1:\2: names a plan this repository does not carry: |'
FAILED=1
fi
return 0
}
vocab_check "$SRC_VOCAB_PAT" "${SRC_DIRS[@]}"
vocab_check "$VOCAB_PAT" . ':(exclude)src/' ':(exclude)core/src/' \
':(exclude)testing/check-comment-refs.sh'
if (( FAILED != 0 )); then
echo "" >&2
echo "check-comment-refs: a comment or document references something a reader holding" >&2
echo "only this repository cannot resolve. Rewrite the comment to say what the" >&2
echo "code does, citing nothing outside the tree." >&2
exit 1
fi
exit 0