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
141 changes: 131 additions & 10 deletions scripts/close-lock.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,149 @@
# closure, and adding the record but not its nested refs' records did not cure
# it. metadatastician/burble's working lockfile has zero dangling edges.
#
# Leaf records are written without a nested `uses:` list, so one pass suffices.
# Records for actions are written as leaves, without a nested `uses:` list.
#
# A record for a REUSABLE WORKFLOW is not a leaf. MEASURED on
# hyperpolymath/palimpsest-license#177 (2026-10-14): with the job-level
# `hyperpolymath/standards@<sha>` refs listed and LEAF records for them, GitHub
# refused Governance, Hypatia Security Scan and Secret Scanner at startup
# (startup_failure, no jobs) while every step-only workflow started. In the
# estate locks whose reusable callers do start (hyperpolymath/my-lang,
# metadatastician/burble), that record's nested `uses:` is exactly the union of
# the external `uses:` of the workflow files called at that ref, each written as
# the lock key `owner/repo@ref` (a sub-path such as `/init` dropped; local `./`,
# `$/` and `docker://` refs excluded). So every job-level call
# `owner/repo/.github/workflows/<file>@<ref>` in this repository, and every such
# call inside a called file, is read at <ref>, and the record `owner/repo@<ref>`
# is written, or completed where an earlier run left it a leaf or short, with
# that union. The refs it names are then closed by the passes like any other
# edge. A called file that cannot be read is SKIPPED: no record is written or
# changed for its ref and the exit is 3, so a leaf is never written where a list
# is owed.
#
# Lock repair order: gh actions-lock → relock-sha-keys.sh → complete-job-refs.sh
# → close-lock.sh → prune-stale.sh (see complete-job-refs.sh).
#
# Every value taken from the API is SHAPE-checked before it is written: a 40-hex
# commit and two integer ids. On an HTTP error `gh api` can put the error body
# on stdout, and a record built from `{"message"…` would be a present-but-
# unresolvable entry, which is fatal where an absent one is merely dangling.
# A ref that cannot be resolved is SKIPPED, reported, and makes the exit 3.
# commit, two integer ids, and a workflow file with a top-level `jobs:`. On an
# HTTP error `gh api` can put the error body on stdout, and a record built from
# `{"message"…` would be a present-but-unresolvable entry, which is fatal where
# an absent one is merely dangling. A ref that cannot be resolved is SKIPPED,
# reported, and makes the exit 3.
# GH_BIN overrides the `gh` binary (the test suite uses an offline stub).
set -euo pipefail
WF="${1:-.github/workflows}"
L="$WF/actions.lock"
GH_BIN="${GH_BIN:-gh}"
[ -f "$L" ] || { echo "close-lock: no $L" >&2; exit 1; }
SC="$(mktemp -d)"; trap 'rm -rf "$SC"' EXIT
TAB="$(printf '\t')"
# keys: list the dependency record keys already present in the lock.
keys() { awk '/^dependencies:/{f=1;next} f&&match($0,/^ '\''[^'\'']+'\'':$/){k=$0;sub(/^ '\''/,"",k);sub(/'\'':$/,"",k);print k}' "$L" | LC_ALL=C sort -u; }
# nested: list the refs that dependency records themselves depend on.
nested() { awk '/^dependencies:/{f=1} f&&match($0,/^ - '\''[^'\'']+'\''/){k=$0;sub(/^ - '\''/,"",k);sub(/'\''.*$/,"",k);print k}' "$L" | LC_ALL=C sort -u; }
# wfrefs: list every ref named under the workflows: section.
wfrefs() { awk '/^workflows:/{f=1;next} f&&/^[a-z_]+:/{f=0} f&&match($0,/^ - '\''[^'\'']+'\''/){k=$0;sub(/^ - '\''/,"",k);sub(/'\''.*$/,"",k);print k}' "$L" | LC_ALL=C sort -u; }
# uses_values FILE: every `uses:` value in FILE, with a trailing comment, YAML
# quotes and a KYAML trailing comma stripped (the same reading as
# complete-job-refs.sh).
uses_values() {
{ sed 's/[[:space:]]\+#.*$//' "$1" \

Check warning on line 62 in scripts/close-lock.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=AaE5z6UAXJXk7tk-Xg7k&open=AaE5z6UAXJXk7tk-Xg7k&pullRequest=1247
| grep -E '^[[:space:]]*(-[[:space:]]+)?uses:[[:space:]]' \
| sed -E 's/^[[:space:]]*(-[[:space:]]+)?uses:[[:space:]]+//' \
| tr -d '"'"'"'' | awk '{print $1}' | sed 's/,$//'; } || true
}
# external_refs: read `uses:` values on stdin; print each external one as its
# lock key owner/repo@ref.
external_refs() {
awk '/^\.\// || /^\$\// || /^docker:\/\// || !/@/ { next }
{ at = index($0, "@"); n = split(substr($0, 1, at - 1), a, "/")
if (n >= 2 && a[1] != "" && a[2] != "") print a[1] "/" a[2] "@" substr($0, at + 1) }'
}
# reusable_calls: read `uses:` values on stdin; print "owner/repo@ref<TAB>path"
# for each call of a workflow file in another repository.
reusable_calls() {
awk '{ at = index($0, "@"); if (!at) next; p = substr($0, 1, at - 1)
if (p !~ /^[^.\/$][^\/]*\/[^\/]+\/\.github\/workflows\/[^\/]+\.ya?ml$/) next
split(p, a, "/"); print a[1] "/" a[2] "@" substr($0, at + 1) "\t" substr(p, length(a[1]) + length(a[2]) + 3) }'
}
# keyfile KEY: a file name for KEY's owed nested refs.
keyfile() { printf '%s' "$1" | sha256sum | cut -c1-32; }

Check warning on line 82 in scripts/close-lock.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=AaE5z6UAXJXk7tk-Xg7l&open=AaE5z6UAXJXk7tk-Xg7l&pullRequest=1247

# ── reusable workflows: read each called file once, transitively ─────────────
mkdir -p "$SC/u"; : > "$SC/read"; : > "$SC/bad"; : > "$SC/more"
for f in "$WF"/*.yml "$WF"/*.yaml; do
[ -e "$f" ] || continue

Check failure on line 87 in scripts/close-lock.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=AaE5z6UAXJXk7tk-Xg7m&open=AaE5z6UAXJXk7tk-Xg7m&pullRequest=1247
uses_values "$f" | reusable_calls
done | LC_ALL=C sort -u > "$SC/calls"
while :; do
LC_ALL=C comm -23 "$SC/calls" "$SC/read" > "$SC/todo"
[ -s "$SC/todo" ] || break

Check failure on line 92 in scripts/close-lock.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=AaE5z6UAXJXk7tk-Xg7n&open=AaE5z6UAXJXk7tk-Xg7n&pullRequest=1247
while IFS="$TAB" read -r k p; do
[ -n "$k" ] || continue

Check failure on line 94 in scripts/close-lock.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=AaE5z6UAXJXk7tk-Xg7o&open=AaE5z6UAXJXk7tk-Xg7o&pullRequest=1247
printf '%s\t%s\n' "$k" "$p" >> "$SC/read"
owner="${k%%/*}"; rest="${k#*/}"; name="${rest%@*}"; ref="${k##*@}"
if "$GH_BIN" api "repos/$owner/$name/contents/$p?ref=$ref" -H 'Accept: application/vnd.github.raw' > "$SC/body" 2>/dev/null \
&& grep -qE '^[[:space:]]*\{?[[:space:]]*"?jobs"?[[:space:]]*:' "$SC/body"; then
uses_values "$SC/body" | external_refs >> "$SC/u/$(keyfile "$k")"
uses_values "$SC/body" | reusable_calls >> "$SC/more"
else
echo " SKIP $k (cannot read $p at $ref)"; echo "$k" >> "$SC/bad"
fi
done < "$SC/todo"
LC_ALL=C sort -u -o "$SC/read" "$SC/read"
cat "$SC/calls" "$SC/more" | LC_ALL=C sort -u > "$SC/calls.new"; mv "$SC/calls.new" "$SC/calls"; : > "$SC/more"
done
LC_ALL=C sort -u -o "$SC/bad" "$SC/bad"
# owed: "key<TAB>ref" per nested ref a readable reusable record must list, plus
# "key<TAB>" for each such key, so a reusable that uses no external action is
# still known (its record correctly stays a leaf).
: > "$SC/owed"
cut -f1 "$SC/calls" | LC_ALL=C sort -u | while read -r k; do
grep -qxF "$k" "$SC/bad" && continue
printf '%s\t\n' "$k"
uf="$SC/u/$(keyfile "$k")"
if [ -f "$uf" ]; then

Check failure on line 117 in scripts/close-lock.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=AaE5z6UAXJXk7tk-Xg7p&open=AaE5z6UAXJXk7tk-Xg7p&pullRequest=1247
LC_ALL=C sort -u "$uf" | while read -r r; do printf '%s\t%s\n' "$k" "$r"; done
fi
done | LC_ALL=C sort -u > "$SC/owed"
skipped=$(grep -c . "$SC/bad" || true)

# uses_block KEY: print the nested `uses:` lines owed by KEY's record (none for
# an action, or for a reusable that uses no external action).
uses_block() {
awk -F'\t' -v k="$1" '$1 == k && $2 != "" { if (!h++) print " uses:"; print " - '\''" $2 "'\''" }' "$SC/owed"

Check warning on line 126 in scripts/close-lock.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=AaE5z6UAXJXk7tk-Xg7q&open=AaE5z6UAXJXk7tk-Xg7q&pullRequest=1247
}

skipped=0
for pass in 1 2 3 4 5; do
# ── complete existing reusable records whose nested uses: are short or absent ─
awk -F'\t' -v owedf="$SC/owed" -v logf="$SC/rewritten" '
BEGIN { while ((getline l < owedf) > 0) { split(l, w, "\t"); R[w[1]] = 1
if (w[2] != "") OW[w[1]] = OW[w[1]] " - '\''" w[2] "'\''\n" } }
# flush: close the current reusable record, writing the owed uses: block.
function flush() {
if (cur == "") return
if (OW[cur] != "") printf " uses:\n%s", OW[cur]
if (old != OW[cur]) print cur > logf
cur = ""; old = ""
}
/^dependencies:[[:space:]]*$/ { print; indep = 1; next }
indep && /^[a-z_]+:/ { flush(); indep = 0; print; next }
indep && /^ '\''[^'\'']+'\'':$/ {
flush(); k = $0; sub(/^ '\''/, "", k); sub(/'\'':$/, "", k)
if (k in R) cur = k
print; next
}
cur != "" && /^ uses:[[:space:]]*$/ { next }
cur != "" && /^ - / { old = old $0 "\n"; next }
{ print }
END { flush() }' "$L" > "$SC/completed.lock"
if [ -s "$SC/rewritten" ]; then

Check failure on line 151 in scripts/close-lock.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=AaE5z6UAXJXk7tk-Xg7r&open=AaE5z6UAXJXk7tk-Xg7r&pullRequest=1247
while read -r k; do echo " ~ $k (nested uses: completed from its called workflow)"; done < "$SC/rewritten"
cat "$SC/completed.lock" > "$L"
fi

# ── close every dangling edge ─────────────────────────────────────────────────
for pass in 1 2 3 4 5 6; do
keys > "$SC/have"
{ nested; wfrefs; } | LC_ALL=C sort -u > "$SC/want"
LC_ALL=C comm -23 "$SC/want" "$SC/have" > "$SC/miss"
Expand All @@ -47,6 +164,9 @@
: > "$SC/new"
while read -r k; do
[ -n "$k" ] || continue
if grep -qxF "$k" "$SC/bad"; then
echo " SKIP $k (its called workflow is unreadable; no leaf record written)"; continue
fi
owner="${k%%/*}"; rest="${k#*/}"; name="${rest%@*}"; ref="${k##*@}"
ids=$("$GH_BIN" api "repos/$owner/$name" --jq '"\(.owner.id) \(.id)"') || ids=""
if ! printf '%s' "$ids" | grep -qxE '[0-9]+ [0-9]+'; then
Expand All @@ -58,8 +178,9 @@
if ! printf '%s' "$sha" | grep -qxE '[0-9a-f]{40}'; then
echo " SKIP $k (cannot resolve commit)"; skipped=$((skipped + 1)); continue
fi
printf " '%s':\n ref: '%s'\n commit: 'sha1-%s'\n owner_id: %s\n repo_id: %s\n" \
"$k" "$ref" "$sha" "${ids%% *}" "${ids##* }" >> "$SC/new"
{ printf " '%s':\n ref: '%s'\n commit: 'sha1-%s'\n owner_id: %s\n repo_id: %s\n" \
"$k" "$ref" "$sha" "${ids%% *}" "${ids##* }"
uses_block "$k"; } >> "$SC/new"
echo " + $k"
done < "$SC/miss"
[ -s "$SC/new" ] || break
Expand All @@ -76,7 +197,7 @@
END { if (indep) for (i=1;i<=nn;i++) if (!used[i]) print NB[i] }' "$L" > "$SC/new.lock" && cat "$SC/new.lock" > "$L"
done
if [ "$skipped" -gt 0 ]; then
echo "close-lock: $skipped dangling ref(s) could not be resolved; lock is NOT closed" >&2
echo "close-lock: $skipped ref(s) could not be resolved or read; lock is NOT closed" >&2
exit 3
fi
echo "close-lock: done"
3 changes: 2 additions & 1 deletion scripts/complete-job-refs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
# (GitHub compares lock and YAML as LITERAL strings); complete-job-refs adds the
# job-level reusable refs the tool cannot see, and the refs used through local
# composite actions (standards#1122); close-lock adds a record for every
# dangling edge; prune-stale drops per-workflow refs nothing uses.
# dangling edge, and gives each job-level reusable ref's record the `uses:` of
# the workflow it calls; prune-stale drops per-workflow refs nothing uses.
set -euo pipefail
WF="${1:-.github/workflows}"
L="$WF/actions.lock"
Expand Down
125 changes: 124 additions & 1 deletion scripts/tests/close-lock-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,17 @@

# Stub: repos/<o>/<n> → "7 9"; commits/v1 → $C; anything under o/missing → an
# HTTP error body on stdout, exit 1; anything under o/garbled → a truncated body
# on stdout, exit 0 (the {"messa shape AGENTS.md §5 records).
# on stdout, exit 0 (the {"messa shape AGENTS.md §5 records). A contents/ call
# serves the file planted under $WORK/contents (its path with / ? = as _), or a
# 404 body with exit 1 when none is planted.
mkdir -p "$WORK/contents"
cat > "$WORK/gh" <<EOF
#!/usr/bin/env bash
case "\$2" in
repos/o/garbled/contents/*) echo '{"messa'; exit 0 ;;
repos/*/contents/*)
f="$WORK/contents/\$(printf '%s' "\$2" | tr '/?=' '___')"
if [ -f "\$f" ]; then cat "\$f"; else echo '{"message":"Not Found","status":"404"}'; exit 1; fi ;;
repos/o/missing*) echo '{"message":"Not Found","status":"404"}'; exit 1 ;;
repos/o/garbled*) echo '{"messa'; exit 0 ;;
repos/o/*/commits/v1) echo $C ;;
Expand Down Expand Up @@ -91,6 +98,122 @@
[ "$st" = 3 ] && ! grep -qF "o/c@nosuchtag':" "$d/actions.lock" \
&& ok "unresolvable tag → SKIP, exit 3, no record" || bad "unresolvable tag → SKIP, exit 3, no record — st=$st"

# mkwf <dir> <uses-values...>: a caller workflow ci.yml with one job-level
# reusable call per value.
mkwf() {

Check warning on line 103 in scripts/tests/close-lock-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaE5z6P2XJXk7tk-Xg7T&open=AaE5z6P2XJXk7tk-Xg7T&pullRequest=1247
local d="$WORK/$1/.github/workflows"; shift; mkdir -p "$d"
{ echo 'jobs:'; i=0; for u in "$@"; do i=$((i + 1)); printf ' j%s:\n uses: %s\n' "$i" "$u"; done; } > "$d/ci.yml"
}
# plant <owner/repo> <path> <ref>: serve stdin as that file at that ref.
plant() { cat > "$WORK/contents/$(printf 'repos/%s/contents/%s?ref=%s' "$1" "$2" "$3" | tr '/?=' '___')"; }

Check warning on line 108 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7V&open=AaE5z6P2XJXk7tk-Xg7V&pullRequest=1247

Check warning on line 108 in scripts/tests/close-lock-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaE5z6P2XJXk7tk-Xg7X&open=AaE5z6P2XJXk7tk-Xg7X&pullRequest=1247

Check warning on line 108 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7W&open=AaE5z6P2XJXk7tk-Xg7W&pullRequest=1247

Check warning on line 108 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7U&open=AaE5z6P2XJXk7tk-Xg7U&pullRequest=1247
# record <lock> <key>: print the record for key, header to last line.
record() { awk -v k=" '$2':" '/^dependencies:/{f=1} f && $0==k {p=1; print; next} f && p && /^ '\''/{p=0} p' "$1"; }

Check warning on line 110 in scripts/tests/close-lock-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaE5z6P2XJXk7tk-Xg7a&open=AaE5z6P2XJXk7tk-Xg7a&pullRequest=1247

Check warning on line 110 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7Z&open=AaE5z6P2XJXk7tk-Xg7Z&pullRequest=1247

Check warning on line 110 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7Y&open=AaE5z6P2XJXk7tk-Xg7Y&pullRequest=1247

plant o/r .github/workflows/w.yml "$A" <<EOF
on: workflow_call
jobs:
a:
runs-on: ubuntu-latest
steps:
- uses: o/b@$B
- uses: "o/c/sub@$C" # a sub-path and a comment
- uses: ./local-action
- uses: docker://alpine:3
EOF
WANT_R=" 'o/r@$A':
ref: '$A'
commit: 'sha1-$A'
owner_id: 7
repo_id: 9
uses:
- 'o/b@$B'
- 'o/c@$C'"

echo "=== a reusable-workflow record lists its called workflow's uses: ==="
d=$(mklock t8 "o/r@$A" </dev/null); mkwf t8 "o/r/.github/workflows/w.yml@$A"
out=$(run "$d"); st=$?
[ "$st" = 0 ] && [ "$(record "$d/actions.lock" "o/r@$A")" = "$WANT_R" ] \

Check failure on line 135 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7b&open=AaE5z6P2XJXk7tk-Xg7b&pullRequest=1247

Check failure on line 135 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7c&open=AaE5z6P2XJXk7tk-Xg7c&pullRequest=1247
&& ok "new reusable record carries the external uses:, keyed owner/repo@ref" || bad "new reusable record carries the external uses: — st=$st $out"
grep -qxF " 'o/b@$B':" "$d/actions.lock" && grep -qxF " 'o/c@$C':" "$d/actions.lock" \
&& ok "the refs it lists are closed" || bad "the refs it lists are closed"
cp "$d/actions.lock" "$WORK/t8.before"; out=$(run "$d")
grep -qF 'dangling refs: 0' <<<"$out" && cmp -s "$WORK/t8.before" "$d/actions.lock" \
&& ok "second run leaves the lock byte-identical" || bad "second run leaves the lock byte-identical — $out"

echo "=== a leaf record left by an earlier run is completed ==="
d=$(mklock t9 "o/r@$A" <<EOF
'o/r@$A':
ref: '$A'
commit: 'sha1-$A'
owner_id: 7
repo_id: 9
EOF
)
mkwf t9 "o/r/.github/workflows/w.yml@$A"
out=$(run "$d"); st=$?
[ "$st" = 0 ] && [ "$(record "$d/actions.lock" "o/r@$A")" = "$WANT_R" ] && grep -qF "~ o/r@$A" <<<"$out" \

Check failure on line 154 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7d&open=AaE5z6P2XJXk7tk-Xg7d&pullRequest=1247

Check failure on line 154 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7e&open=AaE5z6P2XJXk7tk-Xg7e&pullRequest=1247
&& ok "leaf reusable record completed and reported" || bad "leaf reusable record completed and reported — st=$st $out"
grep -qxF " 'o/c@$C':" "$d/actions.lock" && ok "completed record's refs are closed" || bad "completed record's refs are closed"

echo "=== a reusable called from a reusable is read too ==="
plant o/r .github/workflows/w2.yml "$A" <<EOF
jobs:
inner:
uses: o/r2/.github/workflows/v.yml@$B
lint:
runs-on: ubuntu-latest
steps:
- uses: o/b@$B
EOF
plant o/r2 .github/workflows/v.yml "$B" <<EOF
jobs:
a:
runs-on: ubuntu-latest
steps:
- uses: o/c@$C
EOF
d=$(mklock t10 "o/r@$A" </dev/null); mkwf t10 "o/r/.github/workflows/w2.yml@$A"
out=$(run "$d"); st=$?
[ "$st" = 0 ] && record "$d/actions.lock" "o/r@$A" | grep -qxF " - 'o/r2@$B'" \

Check failure on line 177 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7f&open=AaE5z6P2XJXk7tk-Xg7f&pullRequest=1247
&& record "$d/actions.lock" "o/r2@$B" | grep -qxF " - 'o/c@$C'" \
&& grep -qxF " 'o/c@$C':" "$d/actions.lock" \
&& ok "nested reusable gets its own uses: list, and its refs are closed" || bad "nested reusable gets its own uses: list — st=$st $out"

echo "=== a reusable that uses no external action stays a leaf ==="
plant o/r .github/workflows/plain.yml "$A" <<EOF
jobs:
a:
runs-on: ubuntu-latest
steps:
- run: echo hi
EOF
d=$(mklock t11 "o/r@$A" </dev/null); mkwf t11 "o/r/.github/workflows/plain.yml@$A"
out=$(run "$d"); st=$?
[ "$st" = 0 ] && grep -qxF " 'o/r@$A':" "$d/actions.lock" && ! grep -qF 'uses:' "$d/actions.lock" \

Check failure on line 192 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7g&open=AaE5z6P2XJXk7tk-Xg7g&pullRequest=1247
&& ok "no external uses → leaf record (exit 0)" || bad "no external uses → leaf record — st=$st $out"

echo "=== planted positives: an unreadable called workflow writes and changes nothing ==="
d=$(mklock t12 "o/r@$A" </dev/null); mkwf t12 "o/r/.github/workflows/gone.yml@$A"
out=$(run "$d"); st=$?
[ "$st" = 3 ] && grep -qF "SKIP o/r@$A" <<<"$out" && ! grep -qxF " 'o/r@$A':" "$d/actions.lock" \

Check failure on line 198 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7h&open=AaE5z6P2XJXk7tk-Xg7h&pullRequest=1247
&& ok "404 on the called file → SKIP, exit 3, no leaf record" || bad "404 on the called file → SKIP, exit 3, no leaf record — st=$st $out"
d=$(mklock t13 "o/r@$A" <<EOF
'o/r@$A':
ref: '$A'
commit: 'sha1-$A'
owner_id: 7
repo_id: 9
EOF
)
mkwf t13 "o/r/.github/workflows/gone.yml@$A"; cp "$d/actions.lock" "$WORK/t13.before"
out=$(run "$d"); st=$?
[ "$st" = 3 ] && cmp -s "$WORK/t13.before" "$d/actions.lock" \

Check failure on line 210 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7i&open=AaE5z6P2XJXk7tk-Xg7i&pullRequest=1247
&& ok "unreadable called file leaves an existing record untouched (exit 3)" || bad "unreadable called file leaves an existing record untouched — st=$st $out"
d=$(mklock t14 "o/garbled@$A" </dev/null); mkwf t14 "o/garbled/.github/workflows/w.yml@$A"
out=$(run "$d"); st=$?
[ "$st" = 3 ] && ! grep -qxF " 'o/garbled@$A':" "$d/actions.lock" \

Check failure on line 214 in scripts/tests/close-lock-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=AaE5z6P2XJXk7tk-Xg7j&open=AaE5z6P2XJXk7tk-Xg7j&pullRequest=1247
&& ok "malformed called file (exit 0, no jobs:) → SKIP, exit 3" || bad "malformed called file → SKIP, exit 3 — st=$st $out"

echo "=== structural ==="
mkdir -p "$WORK/t7/.github/workflows"
(cd "$WORK/t7" && GH_BIN="$WORK/gh" bash "$TARGET") >/dev/null 2>&1; st=$?
Expand Down
Loading