@biffo/cli 0.246.4 → 0.246.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -105,16 +105,29 @@ audit_dir() {
105
105
  # trusting it — the workspace audit had silently stopped working.)
106
106
  # shellcheck disable=SC2086
107
107
  out="$(cd "$dir" 2>/dev/null && pnpm audit --json $extra 2>/dev/null)"
108
+ # Stamped the instant the registry answered, not when the run started.
109
+ # `pnpm audit` asks the LIVE registry, so its verdict is a function of what
110
+ # had been ingested at this moment — two runs of the same tree minutes apart
111
+ # can legitimately disagree (#1269). Without this stamp a green is not
112
+ # falsifiable, and a red appearing hours after a merge reads as "someone
113
+ # broke dev" when nothing in the tree moved.
114
+ seen_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
108
115
 
109
116
  if printf '%s' "$out" | jq -e '.metadata.vulnerabilities' >/dev/null 2>&1; then
110
117
  high="$(printf '%s' "$out" | jq '.metadata.vulnerabilities.high // 0')"
111
118
  crit="$(printf '%s' "$out" | jq '.metadata.vulnerabilities.critical // 0')"
119
+ mod="$(printf '%s' "$out" | jq '.metadata.vulnerabilities.moderate // 0')"
120
+ low="$(printf '%s' "$out" | jq '.metadata.vulnerabilities.low // 0')"
121
+ total="$(printf '%s' "$out" | jq '.metadata.totalDependencies // 0')"
112
122
  if [ "$((high + crit))" -gt 0 ]; then
113
- echo "::error::${label}: ${crit} critical + ${high} high advisory(ies)."
123
+ echo "::error::${label}: ${crit} critical + ${high} high advisory(ies) across ${total} package(s); registry answered ${seen_at}."
114
124
  printf '%s' "$out" | jq '.advisories // .metadata.vulnerabilities' 2>/dev/null | head -c 4000
115
125
  return 1
116
126
  fi
117
- echo "${label}: no high/critical advisories."
127
+ # A bare "no advisories" is not falsifiable. State the population, the
128
+ # severities that did NOT block, and when the registry was asked, so a
129
+ # reader can tell a clean tree from a tree nobody looked at properly.
130
+ echo "${label}: 0 critical, 0 high across ${total} package(s) (${mod} moderate, ${low} low — reported, not blocking); registry answered ${seen_at}."
118
131
  return 0
119
132
  fi
120
133
 
@@ -123,7 +136,7 @@ audit_dir() {
123
136
  [ "$attempt" -lt "$attempts" ] && sleep "$((attempt * 3))"
124
137
  done
125
138
 
126
- echo "::warning::${label}: audit could not run after ${attempts} attempts (the registry returned a non-JSON/error response); treating as INCONCLUSIVE and not blocking. Advisory scanning was NOT performed for this tree — see #591."
139
+ echo "::error::${label}: audit could not run after ${attempts} attempts (the registry returned a non-JSON/error response). Advisory scanning was NOT performed for this tree, so this is INCONCLUSIVE and BLOCKS a gate that cannot see its input must not report clean (#1269, #591)."
127
140
  inconclusive=$((inconclusive + 1))
128
141
  return 0
129
142
  }
@@ -209,7 +222,14 @@ if [ "$failed" -ne 0 ]; then
209
222
  fi
210
223
 
211
224
  if [ "$inconclusive" -ne 0 ]; then
212
- echo "${inconclusive} tree(s) could not be audited; see warnings above."
225
+ # Exit 2, not 1: "could not determine" is a different fact from "found a real
226
+ # advisory", and conflating them sends whoever reads the red looking for a
227
+ # vulnerability that may not exist. Same three-valued contract as
228
+ # scripts/claim.sh (0 free / 1 taken / 2 cannot tell) and the zero-trees exit
229
+ # above. Until #1269 this returned 0 -- biffo-plugin-ideation rode that path
230
+ # on EVERY run, permanently green while scanning nothing.
231
+ echo "::error::${inconclusive} tree(s) could not be audited; see the errors above. Failing closed."
232
+ exit 2
213
233
  fi
214
234
 
215
235
  echo "js-dependency-audit: audited ${tree_count} tree(s), 0 blocking findings."
@@ -91,6 +91,11 @@ audit_deps() {
91
91
  for attempt in $(seq 1 "$attempts"); do
92
92
  # shellcheck disable=SC2086
93
93
  out="$(uv run pip-audit -f json $extra 2>/dev/null)"
94
+ # Stamped when the advisory source answered, not when the run started —
95
+ # pip-audit queries PyPI/OSV live, so its verdict is time-dependent in the
96
+ # same way pnpm audit's is (#1269). Without the stamp a pass cannot be
97
+ # distinguished from a pass taken before an advisory was published.
98
+ seen_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
94
99
 
95
100
  # printf, never echo: the CI step runs `sh scripts/...` i.e. dash, whose
96
101
  # `echo` interprets backslash escapes. Advisory payloads contain them, so
@@ -101,12 +106,16 @@ audit_deps() {
101
106
  # had been doing exactly that on every run.
102
107
  if printf '%s' "$out" | jq -e '.dependencies' >/dev/null 2>&1; then
103
108
  vuln_count="$(printf '%s' "$out" | jq '[.dependencies[].vulns[]?] | length')"
109
+ pkg_count="$(printf '%s' "$out" | jq '.dependencies | length')"
104
110
  if [ "$vuln_count" -gt 0 ]; then
105
111
  echo "::error::${label}: ${vuln_count} vulnerability(ies)."
106
112
  printf '%s' "$out" | jq '[.dependencies[] | select(.vulns | length > 0)]' 2>/dev/null | head -c 4000
107
113
  return 1
108
114
  fi
109
- echo "${label}: no vulnerabilities found."
115
+ # State the population and the moment, so the green is falsifiable: a
116
+ # pass over 0 packages and a pass over 92 look identical otherwise, and
117
+ # the first is the failure this whole file exists to prevent.
118
+ echo "${label}: 0 vulnerabilities across ${pkg_count} package(s); advisory source answered ${seen_at}."
110
119
  return 0
111
120
  fi
112
121
 
@@ -114,7 +123,7 @@ audit_deps() {
114
123
  [ "$attempt" -lt "$attempts" ] && sleep "$((attempt * 3))"
115
124
  done
116
125
 
117
- echo "::warning::${label}: could not produce parseable output after ${attempts} attempts (a transient network/registry error); treating as INCONCLUSIVE and not blocking. Advisory scanning was NOT performed for this tree see #591."
126
+ echo "::error::${label}: could not produce parseable output after ${attempts} attempts. Advisory scanning was NOT performed for this tree, so this is INCONCLUSIVE and BLOCKS — a gate that cannot see its input must not report clean (#1269, #591). If this is a missing tool rather than a network fault, the fix is to declare it: biffo-plugin-ideation rode this path on every run, permanently green while scanning nothing."
118
127
  inconclusive=$((inconclusive + 1))
119
128
  return 0
120
129
  }
@@ -201,7 +210,7 @@ for lock in $ALL_LOCKS; do
201
210
  else
202
211
  # An export failure is "couldn't run", not "clean" — same discipline as a
203
212
  # transient pip-audit error, and it must never read as a pass.
204
- echo "::warning::pip-audit (${rel}): could not export requirements from ${lock}; treating as INCONCLUSIVE and not blocking. Advisory scanning was NOT performed for this tree see #719."
213
+ echo "::error::pip-audit (${rel}): could not export requirements from ${lock}. Advisory scanning was NOT performed for this tree, so this is INCONCLUSIVE and BLOCKS (#1269, #719)."
205
214
  inconclusive=$((inconclusive + 1))
206
215
  fi
207
216
 
@@ -213,7 +222,12 @@ if [ "$failed" -ne 0 ]; then
213
222
  fi
214
223
 
215
224
  if [ "$inconclusive" -ne 0 ]; then
216
- echo "${inconclusive} tree(s) could not be audited; see warnings above."
225
+ # Exit 2, not 1: "could not determine" is a different fact from "found a real
226
+ # advisory". Conflating them sends whoever reads the red hunting a
227
+ # vulnerability that may not exist. Same three-valued contract as
228
+ # scripts/claim.sh (0 free / 1 taken / 2 cannot tell).
229
+ echo "::error::${inconclusive} tree(s) could not be audited; see the errors above. Failing closed."
230
+ exit 2
217
231
  fi
218
232
 
219
233
  echo "py-dependency-audit: audited ${tree_count} tree(s), 0 blocking findings."
@@ -105,16 +105,29 @@ audit_dir() {
105
105
  # trusting it — the workspace audit had silently stopped working.)
106
106
  # shellcheck disable=SC2086
107
107
  out="$(cd "$dir" 2>/dev/null && pnpm audit --json $extra 2>/dev/null)"
108
+ # Stamped the instant the registry answered, not when the run started.
109
+ # `pnpm audit` asks the LIVE registry, so its verdict is a function of what
110
+ # had been ingested at this moment — two runs of the same tree minutes apart
111
+ # can legitimately disagree (#1269). Without this stamp a green is not
112
+ # falsifiable, and a red appearing hours after a merge reads as "someone
113
+ # broke dev" when nothing in the tree moved.
114
+ seen_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
108
115
 
109
116
  if printf '%s' "$out" | jq -e '.metadata.vulnerabilities' >/dev/null 2>&1; then
110
117
  high="$(printf '%s' "$out" | jq '.metadata.vulnerabilities.high // 0')"
111
118
  crit="$(printf '%s' "$out" | jq '.metadata.vulnerabilities.critical // 0')"
119
+ mod="$(printf '%s' "$out" | jq '.metadata.vulnerabilities.moderate // 0')"
120
+ low="$(printf '%s' "$out" | jq '.metadata.vulnerabilities.low // 0')"
121
+ total="$(printf '%s' "$out" | jq '.metadata.totalDependencies // 0')"
112
122
  if [ "$((high + crit))" -gt 0 ]; then
113
- echo "::error::${label}: ${crit} critical + ${high} high advisory(ies)."
123
+ echo "::error::${label}: ${crit} critical + ${high} high advisory(ies) across ${total} package(s); registry answered ${seen_at}."
114
124
  printf '%s' "$out" | jq '.advisories // .metadata.vulnerabilities' 2>/dev/null | head -c 4000
115
125
  return 1
116
126
  fi
117
- echo "${label}: no high/critical advisories."
127
+ # A bare "no advisories" is not falsifiable. State the population, the
128
+ # severities that did NOT block, and when the registry was asked, so a
129
+ # reader can tell a clean tree from a tree nobody looked at properly.
130
+ echo "${label}: 0 critical, 0 high across ${total} package(s) (${mod} moderate, ${low} low — reported, not blocking); registry answered ${seen_at}."
118
131
  return 0
119
132
  fi
120
133
 
@@ -123,7 +136,7 @@ audit_dir() {
123
136
  [ "$attempt" -lt "$attempts" ] && sleep "$((attempt * 3))"
124
137
  done
125
138
 
126
- echo "::warning::${label}: audit could not run after ${attempts} attempts (the registry returned a non-JSON/error response); treating as INCONCLUSIVE and not blocking. Advisory scanning was NOT performed for this tree — see #591."
139
+ echo "::error::${label}: audit could not run after ${attempts} attempts (the registry returned a non-JSON/error response). Advisory scanning was NOT performed for this tree, so this is INCONCLUSIVE and BLOCKS a gate that cannot see its input must not report clean (#1269, #591)."
127
140
  inconclusive=$((inconclusive + 1))
128
141
  return 0
129
142
  }
@@ -209,7 +222,14 @@ if [ "$failed" -ne 0 ]; then
209
222
  fi
210
223
 
211
224
  if [ "$inconclusive" -ne 0 ]; then
212
- echo "${inconclusive} tree(s) could not be audited; see warnings above."
225
+ # Exit 2, not 1: "could not determine" is a different fact from "found a real
226
+ # advisory", and conflating them sends whoever reads the red looking for a
227
+ # vulnerability that may not exist. Same three-valued contract as
228
+ # scripts/claim.sh (0 free / 1 taken / 2 cannot tell) and the zero-trees exit
229
+ # above. Until #1269 this returned 0 -- biffo-plugin-ideation rode that path
230
+ # on EVERY run, permanently green while scanning nothing.
231
+ echo "::error::${inconclusive} tree(s) could not be audited; see the errors above. Failing closed."
232
+ exit 2
213
233
  fi
214
234
 
215
235
  echo "js-dependency-audit: audited ${tree_count} tree(s), 0 blocking findings."
@@ -91,6 +91,11 @@ audit_deps() {
91
91
  for attempt in $(seq 1 "$attempts"); do
92
92
  # shellcheck disable=SC2086
93
93
  out="$(uv run pip-audit -f json $extra 2>/dev/null)"
94
+ # Stamped when the advisory source answered, not when the run started —
95
+ # pip-audit queries PyPI/OSV live, so its verdict is time-dependent in the
96
+ # same way pnpm audit's is (#1269). Without the stamp a pass cannot be
97
+ # distinguished from a pass taken before an advisory was published.
98
+ seen_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
94
99
 
95
100
  # printf, never echo: the CI step runs `sh scripts/...` i.e. dash, whose
96
101
  # `echo` interprets backslash escapes. Advisory payloads contain them, so
@@ -101,12 +106,16 @@ audit_deps() {
101
106
  # had been doing exactly that on every run.
102
107
  if printf '%s' "$out" | jq -e '.dependencies' >/dev/null 2>&1; then
103
108
  vuln_count="$(printf '%s' "$out" | jq '[.dependencies[].vulns[]?] | length')"
109
+ pkg_count="$(printf '%s' "$out" | jq '.dependencies | length')"
104
110
  if [ "$vuln_count" -gt 0 ]; then
105
111
  echo "::error::${label}: ${vuln_count} vulnerability(ies)."
106
112
  printf '%s' "$out" | jq '[.dependencies[] | select(.vulns | length > 0)]' 2>/dev/null | head -c 4000
107
113
  return 1
108
114
  fi
109
- echo "${label}: no vulnerabilities found."
115
+ # State the population and the moment, so the green is falsifiable: a
116
+ # pass over 0 packages and a pass over 92 look identical otherwise, and
117
+ # the first is the failure this whole file exists to prevent.
118
+ echo "${label}: 0 vulnerabilities across ${pkg_count} package(s); advisory source answered ${seen_at}."
110
119
  return 0
111
120
  fi
112
121
 
@@ -114,7 +123,7 @@ audit_deps() {
114
123
  [ "$attempt" -lt "$attempts" ] && sleep "$((attempt * 3))"
115
124
  done
116
125
 
117
- echo "::warning::${label}: could not produce parseable output after ${attempts} attempts (a transient network/registry error); treating as INCONCLUSIVE and not blocking. Advisory scanning was NOT performed for this tree see #591."
126
+ echo "::error::${label}: could not produce parseable output after ${attempts} attempts. Advisory scanning was NOT performed for this tree, so this is INCONCLUSIVE and BLOCKS — a gate that cannot see its input must not report clean (#1269, #591). If this is a missing tool rather than a network fault, the fix is to declare it: biffo-plugin-ideation rode this path on every run, permanently green while scanning nothing."
118
127
  inconclusive=$((inconclusive + 1))
119
128
  return 0
120
129
  }
@@ -201,7 +210,7 @@ for lock in $ALL_LOCKS; do
201
210
  else
202
211
  # An export failure is "couldn't run", not "clean" — same discipline as a
203
212
  # transient pip-audit error, and it must never read as a pass.
204
- echo "::warning::pip-audit (${rel}): could not export requirements from ${lock}; treating as INCONCLUSIVE and not blocking. Advisory scanning was NOT performed for this tree see #719."
213
+ echo "::error::pip-audit (${rel}): could not export requirements from ${lock}. Advisory scanning was NOT performed for this tree, so this is INCONCLUSIVE and BLOCKS (#1269, #719)."
205
214
  inconclusive=$((inconclusive + 1))
206
215
  fi
207
216
 
@@ -213,7 +222,12 @@ if [ "$failed" -ne 0 ]; then
213
222
  fi
214
223
 
215
224
  if [ "$inconclusive" -ne 0 ]; then
216
- echo "${inconclusive} tree(s) could not be audited; see warnings above."
225
+ # Exit 2, not 1: "could not determine" is a different fact from "found a real
226
+ # advisory". Conflating them sends whoever reads the red hunting a
227
+ # vulnerability that may not exist. Same three-valued contract as
228
+ # scripts/claim.sh (0 free / 1 taken / 2 cannot tell).
229
+ echo "::error::${inconclusive} tree(s) could not be audited; see the errors above. Failing closed."
230
+ exit 2
217
231
  fi
218
232
 
219
233
  echo "py-dependency-audit: audited ${tree_count} tree(s), 0 blocking findings."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.246.4",
3
+ "version": "0.246.5",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",