Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
39 changes: 3 additions & 36 deletions repo-config/configure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,44 +68,11 @@ settings_file="$script_dir/settings.json"
# Absence keeps the About panel following the README.
description=""
if [ -f "$registry" ]; then
# Fails loud on a duplicate name (already a validate.py DEFECT) rather than picking one entry over the other.
if ! match_count="$(jq -r --arg n "$name" '[.repos[] | select(.name==$n)] | length' "$registry")"; then
echo "Failed to read $registry (invalid JSON?)." >&2
# Delegates to spec/resolve_description.py rather than a third hand-rolled copy of description_errors().
# A description that passes that check can never contain a newline, so command substitution has nothing to strip.
if ! description="$(python3 "$script_dir/../spec/resolve_description.py" "$registry" "$name")"; then
exit 1
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
fi
if [ "$match_count" -gt 1 ]; then
echo "$match_count registry entries named $name in $registry. Resolve the duplicate before its description can be read (spec/validate.py rejects this once run)." >&2
exit 1
fi
if ! declared="$(jq -r --arg n "$name" '.repos[] | select(.name==$n) | has("description")' "$registry")"; then
echo "Failed to read $registry (invalid JSON?)." >&2
exit 1
fi
if [ "$declared" = "true" ]; then
# Exactly one match is already established above, so select() itself yields exactly one value here.
# No trim: this only ever validates the value against spec/validate.py's contract, never normalizes it.
# A non-string value (including an explicit null) resolves to empty here, caught by the same guard.
# -j plus the trailing sentinel keeps command substitution from stripping a genuine trailing newline.
if ! description="$(jq -j --arg n "$name" \
'(.repos[] | select(.name==$n) | .description) | if type == "string" then . else empty end' \
"$registry" && printf x)"; then
echo "Failed to read description from $registry (invalid JSON?)." >&2
exit 1
fi
description="${description%x}"
case "$description" in
"" | [[:space:]]* | *[[:space:]])
echo "The declared description for $name in $registry is not a non-empty string with no leading or trailing whitespace. Fix it there (spec/validate.py rejects this once run)." >&2
exit 1
;;
esac
case "$description" in
*$'\n'* | *$'\r'*)
echo "The declared description for $name in $registry carries an embedded newline. Fix it there (spec/validate.py rejects this once run)." >&2
exit 1
;;
esac
fi
fi

# ----- Ruleset id lookup (shared by apply and check) -----
Expand Down
8 changes: 7 additions & 1 deletion spec/audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1309,7 +1309,7 @@ def description_findings(doc_texts, entry, live, slug):
if "description" in entry:
# Delegates to validate.py's own contract instead of re-checking a second, easily-incomplete copy of it
# (an earlier version here missed the link and length rules, accepting either as canonical).
shape_errors = validate.description_errors("registry", entry["description"])
shape_errors = validate.description_errors(slug, entry["description"])
if shape_errors:
findings += [
(
Expand Down Expand Up @@ -4301,6 +4301,12 @@ def _selftest():
print(f" FAIL description: null-declared-field DEFECT contract -> {null_declared}")
else:
print(" ok description: a null declared field is a DEFECT via validate.py's contract")
# The DEFECT names the actual repo, not a generic "registry" label - actionable across a fleet-wide run.
if not any(k == "DEFECT" and t.startswith("owner/Fixture:") for k, t in null_declared):
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
Outdated
ok = False
print(f" FAIL description: DEFECT does not name the repo -> {null_declared}")
else:
print(" ok description: a declared-field DEFECT names the repo, not a generic label")
# The declared field, once present, is what the wording names as the source - not "the README".
declared_mismatch = description_findings(
desc_readme,
Expand Down
58 changes: 58 additions & 0 deletions spec/resolve_description.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env python3
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
"""Resolve one repo's declared registry/repos.json description, for repo-config/configure.sh.

Delegates to description_errors() (validate.py) so configure.sh validates a declared description
against the exact same contract spec/audit.py's description_findings() does, rather than a third
hand-rolled copy of the same rules.
Comment thread
qodo-code-review[bot] marked this conversation as resolved.

Prints the declared description to stdout and exits 0 when the repo has no declared description
(nothing printed) or exactly one valid one. Exits 1 with a message on stderr for anything
configure.sh should fail loud on: a malformed registry, more than one entry named NAME, or a
declared description description_errors() rejects.
Comment thread
Copilot marked this conversation as resolved.
Outdated

Usage: resolve_description.py REGISTRY_PATH NAME
"""

from __future__ import annotations
Comment thread
qodo-code-review[bot] marked this conversation as resolved.

import json
import sys
from pathlib import Path

import validate # sibling, import-safe (its main is guarded)


def main() -> int:
if len(sys.argv) != 3:
print("usage: resolve_description.py REGISTRY_PATH NAME", file=sys.stderr)
return 1
registry_path, name = sys.argv[1], sys.argv[2]
Comment thread
ptr727 marked this conversation as resolved.
try:
registry = json.loads(Path(registry_path).read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as e:
print(f"Failed to read {registry_path}: {e}", file=sys.stderr)
return 1
matches = [
r for r in registry.get("repos", []) if isinstance(r, dict) and r.get("name") == name
]
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
Outdated
Comment thread
ptr727 marked this conversation as resolved.
Outdated
if len(matches) > 1:
print(
f"{len(matches)} registry entries named {name} in {registry_path}. Resolve the "
"duplicate before its description can be read (spec/validate.py rejects this once run).",
file=sys.stderr,
)
return 1
if not matches or "description" not in matches[0]:
return 0
desc = matches[0]["description"]
errors = validate.description_errors(name, desc)
if errors:
for msg in errors:
print(f"{msg} (spec/validate.py rejects this once run).", file=sys.stderr)
return 1
sys.stdout.write(desc)
return 0


if __name__ == "__main__":
sys.exit(main())
4 changes: 4 additions & 0 deletions spec/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,10 @@ def check_secret_set(label, entry, need_kind):
if not isinstance(repo.get("name"), str) or not repo["name"].strip():
errors.append(f"repo #{i}: missing or empty 'name'")
continue
if name != name.strip():
# Both configure.sh and audit.py key their per-repo lookup off an exact match on name, so a padded value would make the entry unresolvable there rather than merely cosmetic here.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
errors.append(f"repo #{i}: name '{name}' carries leading/trailing whitespace")
continue
if name in seen_names:
errors.append(f"{name}: duplicate registry entry for name '{name}'")
seen_names.add(name)
Expand Down