Skip to content

Commit c35fbc0

Browse files
committed
tooling(scripts): classifiers consume list-workflow-paths.sh TSV output
Each classify-*.sh now auto-detects input format and emits the sweep-target path as an explicit column. Input formats (auto-detected from first byte): - JSONL (legacy): {repo, path?, sha} — from gh /search/code paginate - TSV (preferred): repo\tpath\tsha\tscope — from list-workflow-paths.sh Output (all 4 classifiers, 7 columns): repo \t path \t sha \t class \t reason \t lines \t details The path column carries the file's location inside the repo, so sweeps can target nested copies as first-class wrapper sites (not just root-level workflows). When path is empty (legacy JSONL without .path field), it defaults to "". Validated: - classify-mirror.sh /tmp/drift-survey/mirror-full.json (JSONL): 267 TRIVIAL + 22 NEEDS_REVIEW, matches prior sweep-report.md. - classify-mirror.sh /tmp/drift-survey/scorecard-tuples.tsv (TSV): fetches blobs and emits per-(repo, path) rows correctly. Shared `normalize_input` extracted into _lib.sh; each classifier sources it. Reduces per-script duplication. Refs: #199 (campaign), #204 (helper script).
1 parent ca5497a commit c35fbc0

5 files changed

Lines changed: 70 additions & 26 deletions

File tree

scripts/sweep-classifiers/_lib.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env bash
2+
# SPDX-License-Identifier: PMPL-1.0-or-later
3+
# _lib.sh — Shared helpers for classify-*.sh scripts.
4+
#
5+
# Sourced by every classifier. Not directly executable.
6+
#
7+
# Provides: normalize_input <file>
8+
#
9+
# Emits one TSV row per workflow file: "<repo>\t<path>\t<sha>".
10+
# Accepts two input shapes auto-detected from the first line:
11+
#
12+
# 1. JSONL from `gh api /search/code` (legacy):
13+
# {"repo":"foo","sha":"abc123"}
14+
# Emitted path is empty (no nested-copy info available).
15+
#
16+
# 2. TSV from `list-workflow-paths.sh` (preferred — handles nested):
17+
# foo<TAB><path><TAB>abc123<TAB>top-level|nested
18+
# Emitted path is the original `<path>` value; the scope column
19+
# is dropped.
20+
21+
normalize_input() {
22+
local file="$1"
23+
if [[ "$(head -c1 "$file")" == "{" ]]; then
24+
jq -r '[.repo, (.path // ""), .sha] | @tsv' "$file"
25+
else
26+
awk -F'\t' 'NF >= 3 { print $1 "\t" $2 "\t" $3 }' "$file"
27+
fi
28+
}

scripts/sweep-classifiers/classify-codeql.sh

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
# NEEDS_REVIEW — NONE language matrix, or large custom workflow
1313

1414
set -euo pipefail
15-
REPOS_JSON="${1:-/tmp/drift-survey/codeql-full.json}"
15+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16+
# shellcheck source=_lib.sh
17+
. "$SCRIPT_DIR/_lib.sh"
18+
19+
INPUT="${1:-/tmp/drift-survey/codeql-full.json}"
1620
BLOBS_DIR="${BLOBS_DIR:-/tmp/drift-survey/codeql-blobs}"
1721
mkdir -p "$BLOBS_DIR"
1822

@@ -37,10 +41,10 @@ classify_blob() {
3741
}
3842

3943
echo "[fetch] retrieving unique blobs..." >&2
40-
jq -r '.sha' "$REPOS_JSON" | sort -u | grep -v '^null$' | while read -r sha; do
44+
normalize_input "$INPUT" | awk -F'\t' '{print $3 "\t" $1}' | sort -u | while IFS=$'\t' read -r sha repo; do
45+
[ -z "$sha" ] || [ "$sha" = "null" ] && continue
4146
blob_file="$BLOBS_DIR/$sha.yml"
4247
[ -s "$blob_file" ] && continue
43-
repo=$(jq -r --arg s "$sha" 'select(.sha == $s) | .repo' "$REPOS_JSON" | head -1)
4448
gh api "/repos/hyperpolymath/$repo/git/blobs/$sha" --jq '.content' 2>/dev/null \
4549
| base64 -d > "$blob_file" || echo "::warn fetch failed for $sha ($repo)" >&2
4650
done
@@ -53,7 +57,7 @@ for blob in "$BLOBS_DIR"/*.yml; do
5357
SHA_CLASS[$sha]=$(classify_blob "$blob")
5458
done
5559

56-
jq -r '"\(.repo)\t\(.sha)"' "$REPOS_JSON" | while IFS=$'\t' read -r repo sha; do
57-
[ -z "$sha" ] || [ "$sha" = "null" ] && { printf '%s\t%s\tNEEDS_REVIEW\tnull_sha\t-\t-\n' "$repo" "$sha"; continue; }
58-
printf '%s\t%s\t%s\n' "$repo" "$sha" "${SHA_CLASS[$sha]:-NEEDS_REVIEW fetch_failed - -}"
60+
normalize_input "$INPUT" | while IFS=$'\t' read -r repo path sha; do
61+
[ -z "$sha" ] || [ "$sha" = "null" ] && { printf '%s\t%s\t%s\tNEEDS_REVIEW\tnull_sha\t-\t-\n' "$repo" "$path" "$sha"; continue; }
62+
printf '%s\t%s\t%s\t%s\n' "$repo" "$path" "$sha" "${SHA_CLASS[$sha]:-NEEDS_REVIEW fetch_failed - -}"
5963
done

scripts/sweep-classifiers/classify-hypatia-scan.sh

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
# or self-source like hypatia/standards repos)
1515

1616
set -euo pipefail
17-
REPOS_JSON="${1:-/tmp/drift-survey/hypatia-scan-full.json}"
17+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18+
# shellcheck source=_lib.sh
19+
. "$SCRIPT_DIR/_lib.sh"
20+
21+
INPUT="${1:-/tmp/drift-survey/hypatia-scan-full.json}"
1822
BLOBS_DIR="${BLOBS_DIR:-/tmp/drift-survey/hypatia-blobs}"
1923
mkdir -p "$BLOBS_DIR"
2024

@@ -36,10 +40,10 @@ classify_blob() {
3640
}
3741

3842
echo "[fetch] retrieving unique blobs..." >&2
39-
jq -r '.sha' "$REPOS_JSON" | sort -u | grep -v '^null$' | while read -r sha; do
43+
normalize_input "$INPUT" | awk -F'\t' '{print $3 "\t" $1}' | sort -u | while IFS=$'\t' read -r sha repo; do
44+
[ -z "$sha" ] || [ "$sha" = "null" ] && continue
4045
blob_file="$BLOBS_DIR/$sha.yml"
4146
[ -s "$blob_file" ] && continue
42-
repo=$(jq -r --arg s "$sha" 'select(.sha == $s) | .repo' "$REPOS_JSON" | head -1)
4347
gh api "/repos/hyperpolymath/$repo/git/blobs/$sha" --jq '.content' 2>/dev/null \
4448
| base64 -d > "$blob_file" || echo "::warn fetch failed for $sha ($repo)" >&2
4549
done
@@ -52,7 +56,7 @@ for blob in "$BLOBS_DIR"/*.yml; do
5256
SHA_CLASS[$sha]=$(classify_blob "$blob")
5357
done
5458

55-
jq -r '"\(.repo)\t\(.sha)"' "$REPOS_JSON" | while IFS=$'\t' read -r repo sha; do
56-
[ -z "$sha" ] || [ "$sha" = "null" ] && { printf '%s\t%s\tNEEDS_REVIEW\tnull_sha\t-\t-\n' "$repo" "$sha"; continue; }
57-
printf '%s\t%s\t%s\n' "$repo" "$sha" "${SHA_CLASS[$sha]:-NEEDS_REVIEW fetch_failed - -}"
59+
normalize_input "$INPUT" | while IFS=$'\t' read -r repo path sha; do
60+
[ -z "$sha" ] || [ "$sha" = "null" ] && { printf '%s\t%s\t%s\tNEEDS_REVIEW\tnull_sha\t-\t-\n' "$repo" "$path" "$sha"; continue; }
61+
printf '%s\t%s\t%s\t%s\n' "$repo" "$path" "$sha" "${SHA_CLASS[$sha]:-NEEDS_REVIEW fetch_failed - -}"
5862
done

scripts/sweep-classifiers/classify-mirror.sh

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717

1818
set -euo pipefail
1919

20-
REPOS_JSON="${1:-/tmp/drift-survey/mirror-full.json}"
20+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21+
# shellcheck source=_lib.sh
22+
. "$SCRIPT_DIR/_lib.sh"
23+
24+
INPUT="${1:-/tmp/drift-survey/mirror-full.json}"
2125
BLOBS_DIR="${BLOBS_DIR:-/tmp/drift-survey/blobs}"
2226
mkdir -p "$BLOBS_DIR"
2327

@@ -69,10 +73,10 @@ classify_blob() {
6973

7074
# 1. Fetch each unique SHA's blob (cached).
7175
echo "[fetch] unique SHAs to retrieve..." >&2
72-
jq -r '.sha' "$REPOS_JSON" | sort -u | grep -v '^null$' | while read -r sha; do
76+
normalize_input "$INPUT" | awk -F'\t' '{print $3 "\t" $1}' | sort -u | while IFS=$'\t' read -r sha repo; do
77+
[ -z "$sha" ] || [ "$sha" = "null" ] && continue
7378
blob_file="$BLOBS_DIR/$sha.yml"
7479
[ -s "$blob_file" ] && continue
75-
repo=$(jq -r --arg s "$sha" 'select(.sha == $s) | .repo' "$REPOS_JSON" | head -1)
7680
gh api "/repos/hyperpolymath/$repo/git/blobs/$sha" --jq '.content' 2>/dev/null \
7781
| base64 -d > "$blob_file" || echo "::warn fetch failed for $sha ($repo)" >&2
7882
done
@@ -86,8 +90,8 @@ for blob in "$BLOBS_DIR"/*.yml; do
8690
SHA_CLASS[$sha]=$(classify_blob "$blob")
8791
done
8892

89-
# 3. Emit per-repo TSV.
90-
jq -r '"\(.repo)\t\(.sha)"' "$REPOS_JSON" | while IFS=$'\t' read -r repo sha; do
91-
[ -z "$sha" ] || [ "$sha" = "null" ] && { printf '%s\t%s\tNEEDS_REVIEW\tnull_sha\t-\t-\n' "$repo" "$sha"; continue; }
92-
printf '%s\t%s\t%s\n' "$repo" "$sha" "${SHA_CLASS[$sha]:-NEEDS_REVIEW fetch_failed - -}"
93+
# 3. Emit per-(repo, path) TSV: repo \t path \t sha \t class \t reason \t lines \t forges
94+
normalize_input "$INPUT" | while IFS=$'\t' read -r repo path sha; do
95+
[ -z "$sha" ] || [ "$sha" = "null" ] && { printf '%s\t%s\t%s\tNEEDS_REVIEW\tnull_sha\t-\t-\n' "$repo" "$path" "$sha"; continue; }
96+
printf '%s\t%s\t%s\t%s\n' "$repo" "$path" "$sha" "${SHA_CLASS[$sha]:-NEEDS_REVIEW fetch_failed - -}"
9397
done

scripts/sweep-classifiers/classify-secret-scanner.sh

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515

1616
set -euo pipefail
1717

18-
REPOS_JSON="${1:-/tmp/drift-survey/secret-scanner-full.json}"
18+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19+
# shellcheck source=_lib.sh
20+
. "$SCRIPT_DIR/_lib.sh"
21+
22+
INPUT="${1:-/tmp/drift-survey/secret-scanner-full.json}"
1923
BLOBS_DIR="${BLOBS_DIR:-/tmp/drift-survey/secret-blobs}"
2024
mkdir -p "$BLOBS_DIR"
2125

@@ -50,10 +54,10 @@ classify_blob() {
5054

5155
# 1. Fetch unique blobs (cached).
5256
echo "[fetch] retrieving unique blobs..." >&2
53-
jq -r '.sha' "$REPOS_JSON" | sort -u | grep -v '^null$' | while read -r sha; do
57+
normalize_input "$INPUT" | awk -F'\t' '{print $3 "\t" $1}' | sort -u | while IFS=$'\t' read -r sha repo; do
58+
[ -z "$sha" ] || [ "$sha" = "null" ] && continue
5459
blob_file="$BLOBS_DIR/$sha.yml"
5560
[ -s "$blob_file" ] && continue
56-
repo=$(jq -r --arg s "$sha" 'select(.sha == $s) | .repo' "$REPOS_JSON" | head -1)
5761
gh api "/repos/hyperpolymath/$repo/git/blobs/$sha" --jq '.content' 2>/dev/null \
5862
| base64 -d > "$blob_file" || echo "::warn fetch failed for $sha ($repo)" >&2
5963
done
@@ -67,8 +71,8 @@ for blob in "$BLOBS_DIR"/*.yml; do
6771
SHA_CLASS[$sha]=$(classify_blob "$blob")
6872
done
6973

70-
# 3. Per-repo TSV.
71-
jq -r '"\(.repo)\t\(.sha)"' "$REPOS_JSON" | while IFS=$'\t' read -r repo sha; do
72-
[ -z "$sha" ] || [ "$sha" = "null" ] && { printf '%s\t%s\tNEEDS_REVIEW\tnull_sha\t-\t-\n' "$repo" "$sha"; continue; }
73-
printf '%s\t%s\t%s\n' "$repo" "$sha" "${SHA_CLASS[$sha]:-NEEDS_REVIEW fetch_failed - -}"
74+
# 3. Per-(repo, path) TSV.
75+
normalize_input "$INPUT" | while IFS=$'\t' read -r repo path sha; do
76+
[ -z "$sha" ] || [ "$sha" = "null" ] && { printf '%s\t%s\t%s\tNEEDS_REVIEW\tnull_sha\t-\t-\n' "$repo" "$path" "$sha"; continue; }
77+
printf '%s\t%s\t%s\t%s\n' "$repo" "$path" "$sha" "${SHA_CLASS[$sha]:-NEEDS_REVIEW fetch_failed - -}"
7478
done

0 commit comments

Comments
 (0)