Skip to content
Open
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
36 changes: 28 additions & 8 deletions scripts/relock-standards-pin.sh
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@
# succeeds; a file read error propagates awk's non-zero status.
rec_body() { awk -v k=" ${q}$1${q}:" '$0==k{f=1;print;next} f&&/^ [^ ]/{exit} f' "$2"; }

# GitHub's lockfile parser folds owner/repo case and keeps the ref as written:
# 'Swatinem/rust-cache@X' and 'swatinem/rust-cache@X' are one key, and two
# records for it with different metadata make the whole lock unparseable
# ("duplicate action key ... after canonicalization"). Lookups and the closure
# check compare keys that way.
# fold — read owner/repo@ref lines; print each with owner/repo lower-cased.
fold() { awk '{ i = index($0, "@"); if (i) print tolower(substr($0, 1, i - 1)) substr($0, i); else print }'; }
# lock_key KEY FILE — print the dependency key in FILE naming the same pin as
# KEY, in FILE's own spelling; nothing if FILE has none.
lock_key() {
local want; want=$(printf '%s\n' "$1" | fold)
awk -v q="$q" -v w="$want" 'index($0, " " q) == 1 && /@/ && /:$/ {
k = substr($0, 6, length($0) - 7); i = index(k, "@")
if (tolower(substr(k, 1, i - 1)) substr(k, i) == w) { print k; exit } }' "$2"

Check warning on line 111 in scripts/relock-standards-pin.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaFWhPD9RKjspNR8r5Gx&open=AaFWhPD9RKjspNR8r5Gx&pullRequest=1314
}

# Actions the called reusables use at TARGET, normalised to owner/repo@ref.
: > "$tmp/uses"
for p in $full; do
Expand Down Expand Up @@ -130,13 +146,16 @@
git -C "$SROOT" show "${TARGET}:.github/workflows/actions.lock" > "$tmp/slock" 2>/dev/null || : > "$tmp/slock"
while read -r u; do
[ -n "$u" ] || continue
existing=$(rec_body "$u" "$tmp/lock")
# The consumer's record may spell owner/repo differently; it is still this pin's.
key=$(lock_key "$u" "$tmp/lock")
existing=""; [ -z "$key" ] || existing=$(rec_body "$key" "$tmp/lock")

Check failure on line 151 in scripts/relock-standards-pin.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaFWhPD9RKjspNR8r5Gy&open=AaFWhPD9RKjspNR8r5Gy&pullRequest=1314
Comment on lines +150 to +151

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Apply case folding when copying source records

When the consumer has no matching record and the target Standards lock keys the needed action under different owner/repo casing, this case-insensitive lookup finds nothing locally, but the fallback at line 177 still calls rec_body "$u" "$tmp/slock" with exact casing. For example, a reusable edge acme/tool@<sha> with a valid source record ACME/Tool@<sha> is refused as “no record” rather than copied. Use lock_key for the normal source-lock fallback as well as for the self-SHA repair path.

Useful? React with 👍 / 👎.

if [[ -n "$existing" ]]; then
pin=${u##*@}
if [[ "$pin" =~ ^[0-9a-f]{40}$ ]] && printf '%s\n' "$existing" | grep -qxF " ref: '$pin'"; then
# A consumer can retain a poisoned copy after Standards repairs its own
# record. Refresh only ref:, and only with identical commit and IDs.
repaired=$(rec_body "$u" "$tmp/slock")
skey=$(lock_key "$u" "$tmp/slock")
repaired=""; [ -z "$skey" ] || repaired=$(rec_body "$skey" "$tmp/slock")

Check failure on line 158 in scripts/relock-standards-pin.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaFWhPD9RKjspNR8r5Gz&open=AaFWhPD9RKjspNR8r5Gz&pullRequest=1314
symbolic=$(printf '%s\n' "$repaired" | sed -n "s/^ ref: '\([^']*\)'$/\1/p")
[[ -n "$symbolic" && ! "$symbolic" =~ ^[0-9a-fA-F]{40}$ ]] \
|| refuse "no symbolic repair for $u in target Standards lock"
Expand All @@ -145,7 +164,7 @@
[[ "$local_identity" == "$source_identity" \
&& "$(printf '%s\n' "$source_identity" | wc -l)" -eq 3 ]] \
|| refuse "identity mismatch while repairing $u"
awk -v k=" '$u':" -v replacement=" ref: '$symbolic'" '
awk -v k=" '$key':" -v replacement=" ref: '$symbolic'" '
$0 == k { selected = 1; print; next }
/^ [^ ]/ { selected = 0 }
selected && /^ ref:/ { print replacement; next }
Expand All @@ -166,12 +185,13 @@
deps_line() { grep -n '^dependencies:$' "$1" | cut -d: -f1; }
while :; do
n=$(deps_line "$tmp/lock")
grep -oE "^ {8,12}- '[^']+'" "$tmp/lock" | sed -E "s/^ +- '|'$//g" | LC_ALL=C sort -u > "$tmp/edges"
grep -oE "^ {8,12}- '[^']+'" "$tmp/lock" | sed -E "s/^ +- '|'$//g" | fold | LC_ALL=C sort -u > "$tmp/edges"
pruned=0
while read -r c; do
[ -n "$c" ] || continue
grep -qxF "$c" "$tmp/edges" && continue
tail -n +"$((n+1))" "$tmp/lock" | grep -qxF " '$c':" || continue
printf '%s\n' "$c" | fold | grep -qxFf - "$tmp/edges" && continue
tail -n +"$((n+1))" "$tmp/lock" > "$tmp/deps"
c=$(lock_key "$c" "$tmp/deps"); [ -n "$c" ] || continue

Check failure on line 194 in scripts/relock-standards-pin.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaFWhPD9RKjspNR8r5G0&open=AaFWhPD9RKjspNR8r5G0&pullRequest=1314
rec_body "$c" "$tmp/lock" | grep -oE "^ - '[^']+'" | sed -E "s/^ +- '|'$//g" >> "$tmp/cand" || true
awk -v k=" ${q}$c${q}:" '$0==k{s=1;next} s&&/^ [^ ]/{s=0} !s' "$tmp/lock" > "$tmp/l" && mv "$tmp/l" "$tmp/lock"
pruned=1
Expand All @@ -188,8 +208,8 @@

# Closure: every ref the lock names must have a record of its own.
n=$(deps_line "$tmp/out")
grep -oE "^ {8,12}- '[^']+'" "$tmp/out" | sed -E "s/^ +- '|'$//g" | LC_ALL=C sort -u > "$tmp/edges"
tail -n +"$((n+1))" "$tmp/out" | grep -oE "^ '[^']+':" | sed -E "s/^ '|':$//g" | LC_ALL=C sort -u > "$tmp/recs"
grep -oE "^ {8,12}- '[^']+'" "$tmp/out" | sed -E "s/^ +- '|'$//g" | fold | LC_ALL=C sort -u > "$tmp/edges"
tail -n +"$((n+1))" "$tmp/out" | grep -oE "^ '[^']+':" | sed -E "s/^ '|':$//g" | fold | LC_ALL=C sort -u > "$tmp/recs"
dangling=$(LC_ALL=C comm -23 "$tmp/edges" "$tmp/recs")
[ -z "$dangling" ] || refuse "result would have dangling edges: ${dangling//$'\n'/ }"

Expand Down
38 changes: 38 additions & 0 deletions scripts/tests/relock-standards-pin-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,42 @@
echo " PASS $length-hex pin prefixing the target: left as it is, full record from full pins only"
done


# 6. GitHub's lockfile parser folds owner/repo case: 'ACME/tool@<sha>' and
# 'acme/tool@<sha>' are one key, and two records for it with different
# metadata are a parse error ("duplicate action key ... after
# canonicalization"), which fails every run. A record the consumer already
# holds under another owner/repo spelling is the needed record: it is kept,
# never copied a second time. Measured on hyperpolymath/januskey, whose
# 'Swatinem/rust-cache@6323deb…' met standards' 'swatinem/rust-cache@6323deb…'.
# case_variant DIR REF — give DIR's lock a 'ACME/Tool' spelling of the record
# NEW's reusable needs, with ref: REF.
case_variant() {
cat >> "$1/actions.lock" <<Y

Check warning on line 284 in scripts/tests/relock-standards-pin-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaFWhO5_RKjspNR8r5Gt&open=AaFWhO5_RKjspNR8r5Gt&pullRequest=1314
'ACME/Tool@3333333333333333333333333333333333333333':
ref: '$2'
commit: 'sha1-3333333333333333333333333333333333333333'
owner_id: 30
repo_id: 31
Y
}
# acme_keys LOCK — count the dependency keys naming acme/tool@333…, any case.
acme_keys() { grep -ciE "^ 'acme/tool@3333333333333333333333333333333333333333':\$" "$1" || true; }

Check warning on line 293 in scripts/tests/relock-standards-pin-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaFWhO5_RKjspNR8r5Gu&open=AaFWhO5_RKjspNR8r5Gu&pullRequest=1314
D=$(consumer case-kept); case_variant "$D" 'v3.0.1'
bash "$RELOCK" --to "$NEW" --standards "$S" "$D" >/dev/null || fail "case variant: relock refused"
L="$D/actions.lock"
[ "$(acme_keys "$L")" = 1 ] || fail "case variant: the record is keyed $(acme_keys "$L") times (the parser rejects a duplicate)"

Check failure on line 297 in scripts/tests/relock-standards-pin-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaFWhO5_RKjspNR8r5Gv&open=AaFWhO5_RKjspNR8r5Gv&pullRequest=1314
grep -q "^ 'ACME/Tool@3333333333333333333333333333333333333333':\$" "$L" || fail "case variant: the consumer's spelling was not kept"
grep -q "ref: 'v3.0.1'" "$L" || fail "case variant: the consumer's symbolic ref was overwritten"
echo " PASS record held under another owner/repo case is kept, not duplicated"

D=$(consumer case-self-sha); case_variant "$D" '3333333333333333333333333333333333333333'
bash "$RELOCK" --to "$NEW" --standards "$S" "$D" >/dev/null || fail "case variant self-SHA: relock refused"
L="$D/actions.lock"
[ "$(acme_keys "$L")" = 1 ] || fail "case variant self-SHA: the record is keyed $(acme_keys "$L") times"

Check failure on line 305 in scripts/tests/relock-standards-pin-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaFWhO5_RKjspNR8r5Gw&open=AaFWhO5_RKjspNR8r5Gw&pullRequest=1314
grep -q "ref: '3333333333333333333333333333333333333333'" "$L" && fail "case variant self-SHA: the self-SHA ref survived"
awk "/^ 'ACME\\/Tool@3333333333333333333333333333333333333333':\$/{f=1;next} f&&/^ [^ ]/{exit} f" "$L" | grep -qx " ref: 'v3'" \
|| fail "case variant self-SHA: not repaired to standards' symbolic ref"
echo " PASS self-SHA record held under another owner/repo case is repaired in place"

echo "PASS: relock-standards-pin.sh"
Loading