Skip to content

Commit 5efd4a5

Browse files
committed
tests: hold the component metadata vocabulary to one list
discloses: was checked against a fixed set of values, method: only for presence, so any word at all passed as a technique category. The two vocabularies were also written in three places -- this check, the KASLD_META reference in api.h, and the metadata table in CONTRIBUTING.md -- with nothing holding them together, and they discriminate only while all three agree. Both directions had drifted: a value shipped components carry that neither document named, and a name borrowed from the confidence ladder documented as a method, where it says nothing about a technique. Neither surfaces at runtime, because only detection is branched on and every other value is printed verbatim. The two sets are now named once and are the source of truth. method: is checked against its set per component as discloses: already was, both documents must name exactly the same sets, and every allowed value must be carried by at least one component -- which is what catches a name imported from a neighbouring vocabulary, since such a value has no component to point at. Retiring the last component of a category now means dropping the value in the same change. The documents are read as text, so their present shape is load-bearing: the api.h method entry lists its values after "Values:" and ends the sentence with a period, its discloses entry quotes each value, and CONTRIBUTING.md carries one table row per key with the values last. Rewriting either away from that shape fails this check rather than passing silently.
1 parent a93503b commit 5efd4a5

1 file changed

Lines changed: 105 additions & 2 deletions

File tree

tests/check-component-meta

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,32 @@
1313
# This check FAILS if any src/components/*.c lacks a KASLD_META(...) declaration,
1414
# or carries one with no method: key (the field that classifies the component), or
1515
# no discloses: key naming what it leaks.
16+
#
17+
# It also holds the method:/discloses: VOCABULARY together. The same list is
18+
# written in three places -- the allowed sets below, the KASLD_META key reference
19+
# in src/include/kasld/api.h, and the metadata table in CONTRIBUTING.md -- and it
20+
# discriminates only while all three agree. Both failure directions have been
21+
# seen: a value carried by shipped components that neither document named, and a
22+
# name borrowed from the confidence ladder documented as a method, where it means
23+
# nothing (the ladder grades a RECORD's trust, this names a TECHNIQUE, and the one
24+
# component emitting CONF_DERIVED records parses a file). Neither is visible at
25+
# runtime, because only "detection" is ever branched on and every other value is
26+
# printed verbatim.
27+
#
28+
# So the sets below are the source of truth, and three things are asserted about
29+
# each: every component carries a value from it, both documents name exactly it,
30+
# and every value in it is carried by at least one component.
31+
#
32+
# That last one is what catches a name imported from a neighbouring vocabulary:
33+
# such a value has no component to point at, so it cannot be added to the list and
34+
# then documented. The cost is that retiring the last component of a category
35+
# means dropping the value in the same change, which is the correct prompt.
36+
#
37+
# The documents are read as text, so their present shape is load-bearing: the
38+
# api.h method entry lists its values after "Values:" and closes the sentence with
39+
# a period, its discloses entry quotes each value, and CONTRIBUTING.md carries one
40+
# table row per key with the values in the last column. Rewriting either away from
41+
# that shape fails this check rather than passing silently.
1642
# ---
1743
# <bcoles@gmail.com>
1844

@@ -28,8 +54,24 @@ else
2854
RED=; GREEN=; RESET=
2955
fi
3056

57+
# The two closed vocabularies. Source of truth for the documents and for the
58+
# per-component checks alike; see the note above before adding a value.
59+
METHOD_VALUES='parsed heuristic inferred timing brute detection'
60+
DISCLOSES_VALUES='virtual physical both facts'
61+
62+
meth_alt=$(printf '%s' "$METHOD_VALUES" | tr ' ' '|')
63+
disc_alt=$(printf '%s' "$DISCLOSES_VALUES" | tr ' ' '|')
64+
65+
# Space- or comma-separated words -> sorted and space-separated, so two
66+
# vocabularies can be compared as sets regardless of how either was written.
67+
norm() {
68+
printf '%s' "$1" | tr ',' ' ' | tr -s ' ' '\n' | grep -v '^$' | sort -u |
69+
tr '\n' ' '
70+
}
71+
3172
rc=0
3273
missing=""
74+
badmethod=""
3375
nomethod=""
3476
badhw=""
3577
nodisc=""
@@ -44,6 +86,9 @@ for f in "$COMP"/*.c; do
4486
elif ! grep -qE 'method:' "$f"; then
4587
nomethod="$nomethod $base"
4688
rc=1
89+
elif ! grep -qE '"method:('"$meth_alt"')\\n"' "$f"; then
90+
badmethod="$badmethod $base"
91+
rc=1
4792
fi
4893

4994
# discloses: names what the TECHNIQUE discloses -- a static property, distinct
@@ -65,7 +110,7 @@ for f in "$COMP"/*.c; do
65110
if ! grep -qE '"discloses:' "$f"; then
66111
nodisc="$nodisc $base"
67112
rc=1
68-
elif ! grep -qE '"discloses:(virtual|physical|both|facts)\\n"' "$f"; then
113+
elif ! grep -qE '"discloses:('"$disc_alt"')\\n"' "$f"; then
69114
baddisc="$baddisc $base"
70115
rc=1
71116
fi
@@ -83,6 +128,60 @@ for f in "$COMP"/*.c; do
83128
fi
84129
done
85130

131+
# ---- Vocabulary parity: the sets above against the tree and the documents ---
132+
API="$ROOT/src/include/kasld/api.h"
133+
MD="$ROOT/CONTRIBUTING.md"
134+
135+
used_method=$(grep -ho '"method:[a-z]*' "$COMP"/*.c | sed 's/"method://')
136+
used_disc=$(grep -ho '"discloses:[a-z]*' "$COMP"/*.c | sed 's/"discloses://')
137+
138+
want_method=$(norm "$METHOD_VALUES")
139+
want_disc=$(norm "$DISCLOSES_VALUES")
140+
141+
api_method=$(norm "$(sed -n '/^ \* method:/,/^ \* phase:/p' "$API" |
142+
tr '\n' ' ' | sed -E 's/.*Values:([^.]*)\..*/\1/' | tr -d '*')")
143+
api_disc=$(norm "$(sed -n '/^ \* discloses:/,/^ \* live:/p' "$API" |
144+
grep -o '"[a-z]*"' | tr -d '"' | tr '\n' ' ')")
145+
# The backticks are literal table markup, not command substitution, so both
146+
# patterns must stay single-quoted.
147+
# shellcheck disable=SC2016
148+
md_method=$(norm "$(grep -E '^\| `method` \|' "$MD" |
149+
awk -F'|' '{ print $(NF - 1) }' | tr -d '` ')")
150+
# shellcheck disable=SC2016
151+
md_disc=$(norm "$(grep -E '^\| `discloses` \|' "$MD" |
152+
awk -F'|' '{ print $(NF - 1) }' | tr -d '` ')")
153+
154+
# <key> <document> <documented set> <expected set>
155+
vocab_cmp() {
156+
[ "$3" = "$4" ] && return 0
157+
printf '%scheck-component-meta: FAIL%s — %s: vocabulary in %s is not the one this check allows:\n' \
158+
"$RED" "$RESET" "$1" "$2"
159+
printf ' documented: %s\n' "$3"
160+
printf ' allowed: %s\n' "$4"
161+
return 1
162+
}
163+
164+
vocab_cmp method "src/include/kasld/api.h" "$api_method" "$want_method" || rc=1
165+
vocab_cmp discloses "src/include/kasld/api.h" "$api_disc" "$want_disc" || rc=1
166+
vocab_cmp method "CONTRIBUTING.md" "$md_method" "$want_method" || rc=1
167+
vocab_cmp discloses "CONTRIBUTING.md" "$md_disc" "$want_disc" || rc=1
168+
169+
# A value no component carries names a category the tree does not have.
170+
unused=""
171+
for v in $METHOD_VALUES; do
172+
printf '%s\n' "$used_method" | grep -qx "$v" || unused="$unused method:$v"
173+
done
174+
for v in $DISCLOSES_VALUES; do
175+
printf '%s\n' "$used_disc" | grep -qx "$v" || unused="$unused discloses:$v"
176+
done
177+
if [ -n "$unused" ]; then
178+
printf '%scheck-component-meta: FAIL%s — allowed value no component carries:\n' "$RED" "$RESET"
179+
for c in $unused; do printf ' %s\n' "$c"; done
180+
printf ' either a component should declare it, or drop it here and from both\n'
181+
printf ' api.h and CONTRIBUTING.md\n'
182+
rc=1
183+
fi
184+
86185
if [ -n "$missing" ]; then
87186
printf '%scheck-component-meta: FAIL%s — missing KASLD_META:\n' "$RED" "$RESET"
88187
for c in $missing; do printf ' %s\n' "$c"; done
@@ -91,6 +190,10 @@ if [ -n "$nomethod" ]; then
91190
printf '%scheck-component-meta: FAIL%s — KASLD_META without a method: key:\n' "$RED" "$RESET"
92191
for c in $nomethod; do printf ' %s\n' "$c"; done
93192
fi
193+
if [ -n "$badmethod" ]; then
194+
printf '%scheck-component-meta: FAIL%s — method: must be one of %s:\n' "$RED" "$RESET" "$METHOD_VALUES"
195+
for c in $badmethod; do printf ' %s\n' "$c"; done
196+
fi
94197
if [ -n "$nodisc" ]; then
95198
printf '%scheck-component-meta: FAIL%s — KASLD_META without a discloses: key:\n' "$RED" "$RESET"
96199
for c in $nodisc; do printf ' %s\n' "$c"; done
@@ -106,6 +209,6 @@ fi
106209
if [ "$rc" -eq 0 ]; then
107210
guard_scope "check-component-meta" "$n" 80
108211

109-
printf '%scheck-component-meta: OK%s (%d components, all declare KASLD_META with method: and discloses:)\n' "$GREEN" "$RESET" "$n"
212+
printf '%scheck-component-meta: OK%s (%d components, all declare KASLD_META with method: and discloses:; vocabulary matches api.h and CONTRIBUTING.md)\n' "$GREEN" "$RESET" "$n"
110213
fi
111214
exit $rc

0 commit comments

Comments
 (0)