Skip to content

Commit a04c990

Browse files
committed
fix(sdk-review): FP-H/I/J — lockfiles, .env templates, LIC baseline auto-detect
Three new FP classes discovered in the post-remediation dry-run (85 real Python PRs, 10 Java PRs). Empirical validation showed the initial fix wave left gaps that produced 1000+ noise findings on subsequent PRs. - FP-H-01: HC-01 no longer scans lockfiles (uv.lock, poetry.lock, Pipfile.lock, package-lock.json, yarn.lock, Cargo.lock, Gemfile.lock, *.lock). These are generated files full of package registry URLs. Impact: eliminates ~800 false BLOCKs on PRs that touch uv.lock. - FP-I-01: HC-01 no longer scans .env / .env.* / .env_* / .env-* files. These are convention/template files carrying placeholder URLs like 'your-api-url-here'. Impact: eliminates ~14 false BLOCKs. - FP-J-01: check-license-spdx auto-detects whether the repo has consistent SPDX adoption. If < 20% of existing files carry SPDX headers, LIC-01/02 is held (returns PASS with a pass_criteria_met explanation) rather than penalizing every new file for a debt the repo itself carries. Impact: eliminates 12 false BLOCKs on cloud-sdk-java PR #6 (Number Range module). Regression tests: +5 bats tests in test_fp_remediation.bats (76 total, all green in both repos).
1 parent dcd50d7 commit a04c990

3 files changed

Lines changed: 181 additions & 2 deletions

File tree

.claude/scripts/check-hardcode.sh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@ diff_content=$(cat "$DIFF_FILE" 2>/dev/null || echo "")
2222
# Determine ignore patterns per language
2323
# FP-B-01: HC-01 must not fire on XML/YAML/POM files where URL-like strings
2424
# are namespace declarations (http://maven.apache.org/POM/4.0.0 etc.).
25+
# FP-H-01: lockfiles are generated + full of package URLs; never scan them.
26+
# FP-I-01: .env.example files carry placeholder URLs (your-…-here); templates.
27+
LOCKFILE_PATTERNS='.*\.lock$|(.*/)?uv\.lock$|(.*/)?poetry\.lock$|(.*/)?Pipfile\.lock$|(.*/)?package-lock\.json$|(.*/)?yarn\.lock$|(.*/)?Cargo\.lock$|(.*/)?Gemfile\.lock$'
28+
# .env, .env.X, .env_X, .env-X — any file whose basename starts with .env
29+
ENV_EXAMPLE_PATTERNS='(.*/)?\.env(\..*|_.*|-.*)?$'
2530
if [ "$LANGUAGE" = "python" ]; then
26-
ignore_files='^(tests?/|mocks?/|docs?/|.*/spec/|.*/constants\.py|.*/user-guide\.md|README\.md|.*\.md$|.*\.ya?ml$|.*\.xml$|.*\.properties$|.*pom\.xml$)'
31+
ignore_files="^(tests?/|mocks?/|docs?/|.*/spec/|.*/constants\.py|.*/user-guide\.md|README\.md|.*\.md$|.*\.ya?ml$|.*\.xml$|.*\.properties$|.*pom\.xml$|${LOCKFILE_PATTERNS}|${ENV_EXAMPLE_PATTERNS})"
2732
else
28-
ignore_files='^(src/test/|mocks?/|docs?/|.*Constants\.java|.*/constants/|.*/user-guide\.md|README\.md|.*\.md$|.*\.ya?ml$|.*\.xml$|.*\.properties$|.*pom\.xml$)'
33+
ignore_files="^(src/test/|mocks?/|docs?/|.*Constants\.java|.*/constants/|.*/user-guide\.md|README\.md|.*\.md$|.*\.ya?ml$|.*\.xml$|.*\.properties$|.*pom\.xml$|${LOCKFILE_PATTERNS}|${ENV_EXAMPLE_PATTERNS})"
2934
fi
3035

3136
echo "$diff_content" | awk '

.claude/scripts/check-license-spdx.sh

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,39 @@ trap 'rm -f "$findings"' EXIT
2020
# Predicate: REUSE.toml aggregate present?
2121
reuse_present=$(reuse_toml_aggregate_present "$REPO_ROOT")
2222

23+
# FP-J-01: if the repo itself doesn't consistently have SPDX headers, don't
24+
# penalize new files for a missing header that no existing file has. Sample
25+
# up to 20 existing source files of the target language. If < 20% carry an
26+
# SPDX-License-Identifier header, we treat LIC-01/02 as SHADOW (report but
27+
# do not block).
28+
repo_has_spdx="unknown"
29+
if [ "$reuse_present" != "true" ]; then
30+
if [ "$LANGUAGE" = "python" ]; then
31+
src_root="$REPO_ROOT/src"
32+
ext="py"
33+
else
34+
src_root="$REPO_ROOT/src/main/java"
35+
ext="java"
36+
fi
37+
if [ -d "$src_root" ]; then
38+
total=0; with_spdx=0
39+
while IFS= read -r f; do
40+
total=$((total+1))
41+
if head -10 "$f" 2>/dev/null | grep -q "SPDX-License-Identifier"; then
42+
with_spdx=$((with_spdx+1))
43+
fi
44+
done < <(find "$src_root" -type f -name "*.${ext}" 2>/dev/null | head -20)
45+
if [ "$total" -gt 0 ]; then
46+
# Percent threshold: <20% adoption means the repo hasn't converged yet
47+
if [ $((with_spdx * 100 / total)) -lt 20 ]; then
48+
repo_has_spdx="no-consistent-adoption"
49+
else
50+
repo_has_spdx="yes"
51+
fi
52+
fi
53+
fi
54+
fi
55+
2356
diff_content=$(cat "$DIFF_FILE" 2>/dev/null || echo "")
2457

2558
if [ "$reuse_present" = "true" ]; then
@@ -66,6 +99,31 @@ else
6699
fi
67100
# REUSE-IgnoreEnd
68101

102+
# FP-J-01: if the repo hasn't converged on SPDX headers, downgrade LIC-01/02
103+
# emissions to a single summary FLAG (or skip entirely) rather than BLOCKing
104+
# each new file for a debt the repo itself carries.
105+
if [ "$repo_has_spdx" = "no-consistent-adoption" ]; then
106+
jq -n --arg check "license-spdx" --arg lang "$LANGUAGE" --arg started "$STARTED" \
107+
'{
108+
check: $check,
109+
version: "1.0.0",
110+
language: $lang,
111+
status: "PASS",
112+
started_at: $started,
113+
duration_ms: 0,
114+
modules_analysed: [],
115+
findings: [],
116+
summary: {
117+
block_count: 0,
118+
flag_count: 0,
119+
suppressed_by_baseline: 0,
120+
pass_criteria_met: ["Repo has no consistent SPDX adoption (<20% of existing files) — LIC-01/02 held until repo-wide migration"],
121+
pass_criteria_failed: []
122+
}
123+
}'
124+
exit 0
125+
fi
126+
69127
while IFS= read -r f; do
70128
[ -z "$f" ] && continue
71129
if ! echo "$f" | grep -qE "$ext_match"; then continue; fi

tests/sdk-review/test_fp_remediation.bats

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,3 +317,119 @@ EOF
317317
[ "$pt01_count" = "0" ]
318318
rm -rf "$tmpd"
319319
}
320+
321+
@test "FP-H-01: HC-01 does not fire on uv.lock" {
322+
[ -f "$SCRIPT_DIR/check-hardcode.sh" ] || skip "check-hardcode.sh not in this batch"
323+
tmpd=$(mktemp -d)
324+
cat > "$tmpd/diff" <<'DIFF'
325+
diff --git a/uv.lock b/uv.lock
326+
new file mode 100644
327+
--- /dev/null
328+
+++ b/uv.lock
329+
@@ -0,0 +1,3 @@
330+
+url = "https://files.pythonhosted.org/packages/aa/bb/foo-1.0.tar.gz"
331+
+url = "https://files.pythonhosted.org/packages/cc/dd/bar-2.0.tar.gz"
332+
+other = "value"
333+
DIFF
334+
result=$(DIFF_FILE="$tmpd/diff" LANGUAGE=python bash "$SCRIPT_DIR/check-hardcode.sh" 2>/dev/null)
335+
hc01_count=$(echo "$result" | jq '[.findings[] | select(.rule=="HC-01")] | length')
336+
[ "$hc01_count" = "0" ]
337+
rm -rf "$tmpd"
338+
}
339+
340+
@test "FP-H-01: HC-01 does not fire on poetry.lock / package-lock.json" {
341+
[ -f "$SCRIPT_DIR/check-hardcode.sh" ] || skip "check-hardcode.sh not in this batch"
342+
tmpd=$(mktemp -d)
343+
cat > "$tmpd/diff" <<'DIFF'
344+
diff --git a/poetry.lock b/poetry.lock
345+
new file mode 100644
346+
--- /dev/null
347+
+++ b/poetry.lock
348+
@@ -0,0 +1,1 @@
349+
+url = "https://files.pythonhosted.org/packages/foo.tar.gz"
350+
diff --git a/package-lock.json b/package-lock.json
351+
new file mode 100644
352+
--- /dev/null
353+
+++ b/package-lock.json
354+
@@ -0,0 +1,1 @@
355+
+"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
356+
DIFF
357+
result=$(DIFF_FILE="$tmpd/diff" LANGUAGE=python bash "$SCRIPT_DIR/check-hardcode.sh" 2>/dev/null)
358+
hc01_count=$(echo "$result" | jq '[.findings[] | select(.rule=="HC-01")] | length')
359+
[ "$hc01_count" = "0" ]
360+
rm -rf "$tmpd"
361+
}
362+
363+
@test "FP-I-01: HC-01 does not fire on .env.example templates" {
364+
[ -f "$SCRIPT_DIR/check-hardcode.sh" ] || skip "check-hardcode.sh not in this batch"
365+
tmpd=$(mktemp -d)
366+
cat > "$tmpd/diff" <<'DIFF'
367+
diff --git a/.env_integration_tests.example b/.env_integration_tests.example
368+
new file mode 100644
369+
--- /dev/null
370+
+++ b/.env_integration_tests.example
371+
@@ -0,0 +1,3 @@
372+
+API_URL=https://your-api-url-here.com
373+
+AUTH_URL=https://your-auth-url.example.com
374+
+OTHER=value
375+
DIFF
376+
result=$(DIFF_FILE="$tmpd/diff" LANGUAGE=python bash "$SCRIPT_DIR/check-hardcode.sh" 2>/dev/null)
377+
hc01_count=$(echo "$result" | jq '[.findings[] | select(.rule=="HC-01")] | length')
378+
[ "$hc01_count" = "0" ]
379+
rm -rf "$tmpd"
380+
}
381+
382+
@test "FP-J-01: LIC-01/02 skips when repo lacks SPDX in existing files" {
383+
[ -f "$SCRIPT_DIR/check-license-spdx.sh" ] || skip "check-license-spdx.sh not in this batch"
384+
tmpd=$(mktemp -d)
385+
mkdir -p "$tmpd/src/main/java/com/sap"
386+
# Create 5 existing java files, none with SPDX
387+
for i in 1 2 3 4 5; do
388+
echo "package com.sap;" > "$tmpd/src/main/java/com/sap/Foo${i}.java"
389+
echo "public class Foo${i} {}" >> "$tmpd/src/main/java/com/sap/Foo${i}.java"
390+
done
391+
cat > "$tmpd/diff" <<'DIFF'
392+
diff --git a/src/main/java/com/sap/NewClient.java b/src/main/java/com/sap/NewClient.java
393+
new file mode 100644
394+
--- /dev/null
395+
+++ b/src/main/java/com/sap/NewClient.java
396+
@@ -0,0 +1,2 @@
397+
+package com.sap;
398+
+public class NewClient {}
399+
DIFF
400+
result=$(REPO_ROOT="$tmpd" DIFF_FILE="$tmpd/diff" LANGUAGE=java bash "$SCRIPT_DIR/check-license-spdx.sh" 2>/dev/null)
401+
lic_count=$(echo "$result" | jq '[.findings[] | select(.rule | startswith("LIC-"))] | length')
402+
[ "$lic_count" = "0" ]
403+
# Should have a pass_criteria_met entry mentioning no consistent adoption
404+
no_adoption=$(echo "$result" | jq '.summary.pass_criteria_met | any(contains("no consistent SPDX adoption"))')
405+
[ "$no_adoption" = "true" ]
406+
rm -rf "$tmpd"
407+
}
408+
409+
@test "FP-J-01: LIC-01/02 still fires when repo has SPDX in existing files" {
410+
[ -f "$SCRIPT_DIR/check-license-spdx.sh" ] || skip "check-license-spdx.sh not in this batch"
411+
tmpd=$(mktemp -d)
412+
mkdir -p "$tmpd/src/main/java/com/sap"
413+
# Create 5 existing files, all with SPDX
414+
for i in 1 2 3 4 5; do
415+
cat > "$tmpd/src/main/java/com/sap/Foo${i}.java" <<HDR
416+
// SPDX-License-Identifier: Apache-2.0
417+
// SPDX-FileCopyrightText: 2026 SAP SE
418+
package com.sap;
419+
public class Foo${i} {}
420+
HDR
421+
done
422+
cat > "$tmpd/diff" <<'DIFF'
423+
diff --git a/src/main/java/com/sap/NewClient.java b/src/main/java/com/sap/NewClient.java
424+
new file mode 100644
425+
--- /dev/null
426+
+++ b/src/main/java/com/sap/NewClient.java
427+
@@ -0,0 +1,2 @@
428+
+package com.sap;
429+
+public class NewClient {}
430+
DIFF
431+
result=$(REPO_ROOT="$tmpd" DIFF_FILE="$tmpd/diff" LANGUAGE=java bash "$SCRIPT_DIR/check-license-spdx.sh" 2>/dev/null)
432+
lic01=$(echo "$result" | jq '[.findings[] | select(.rule=="LIC-01")] | length')
433+
[ "$lic01" = "1" ]
434+
rm -rf "$tmpd"
435+
}

0 commit comments

Comments
 (0)