@biffo/cli 0.246.1 → 0.246.3

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.
@@ -30,6 +30,23 @@
30
30
  # the gate was green because it was not looking, and "we checked and it is
31
31
  # clean" read identically to "we never checked".
32
32
  #
33
+ # ## Discovery, not a fixed path list (#1270)
34
+ #
35
+ # A fixed sweep of "workspace root + `_skeletons/**`" is itself the same shape
36
+ # of gap, one level further down: it reports clean on any pnpm-lock.yaml
37
+ # outside that pair, and an INSTANCE grows trees this repo never has —
38
+ # vendored plugin frontends under `services/*/web/`, a second app under
39
+ # `web-admin/`, or any other nested pnpm project. Found live:
40
+ # `services/ideation/web/pnpm-lock.yaml` sat on two advisory-range packages
41
+ # (one high) while this exact gate stayed green, because it never looked
42
+ # there. Ten lockfiles in that repo; a fixed sweep covered nine.
43
+ #
44
+ # So every pnpm-lock.yaml under the repo is DISCOVERED by walking from the git
45
+ # root, rather than assumed from a hardcoded list — see "Discover the trees"
46
+ # below. Nothing here still means the estate's layouts differ; discovery
47
+ # covers a repo the day it grows a new one, instead of the day someone
48
+ # remembers to add a path.
49
+ #
33
50
  # ## This file is distributed verbatim (#743)
34
51
  #
35
52
  # Both skeletons and every existing sibling/plugin repo hold a BYTE-IDENTICAL
@@ -39,10 +56,9 @@
39
56
  # every satellite was born with the original defect and reddened its required JS
40
57
  # check on any registry hiccup.
41
58
  #
42
- # It therefore takes its target from the CURRENT WORKING DIRECTORY — the CI
43
- # job's `working-directory` — rather than assuming a repo layout: `.` is the
44
- # root workspace here, `apps/frontend` in a sibling, and the `_skeletons/**`
45
- # sweep below simply finds nothing outside this repo. Keep it layout-agnostic,
59
+ # It therefore takes its WORKSPACE tree from the CURRENT WORKING DIRECTORY —
60
+ # the CI job's `working-directory` — rather than assuming a repo layout: `.` is
61
+ # the root workspace here, `apps/frontend` in a sibling. Keep it layout-agnostic,
46
62
  # or the copies stop being interchangeable and `shared-sync.sh --check` starts
47
63
  # reporting drift that is really divergence.
48
64
  #
@@ -112,14 +128,80 @@ audit_dir() {
112
128
  return 0
113
129
  }
114
130
 
115
- # The workspace itself.
116
- audit_dir "." "pnpm audit (workspace)" "" || failed=1
131
+ # ## Discover the trees (#1270)
132
+ #
133
+ # Walk from the git root — not the CWD this script happens to run from — so a
134
+ # vendored tree anywhere in the repo is found regardless of where the CI job's
135
+ # `working-directory` points. Excludes `node_modules` (installed, not source),
136
+ # `.git`, and `.worktrees` (other agents' in-progress checkouts, git-ignored
137
+ # and not part of this run).
138
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
139
+ if [ -z "$REPO_ROOT" ]; then
140
+ echo "::error::js-dependency-audit: not inside a git repository ('git rev-parse --show-toplevel' failed). Discovery cannot walk a tree it cannot find." >&2
141
+ exit 2
142
+ fi
143
+
144
+ WORKSPACE_ABS=$(pwd -P)
145
+
146
+ # shellcheck disable=SC2016
147
+ ALL_LOCKS=$(find "$REPO_ROOT" \
148
+ \( -name node_modules -o -name .git -o -name .worktrees \) -prune -o \
149
+ -type f -name pnpm-lock.yaml -print 2>/dev/null | sort)
150
+
151
+ # Fail CLOSED, not open, on an empty discovery (#1270). Zero trees — including
152
+ # no lockfile at the workspace root itself — means discovery is broken (a
153
+ # wrong root, an over-eager prune, a repo layout this script has never seen),
154
+ # not that the repo has nothing to audit. Every repo this script is wired into
155
+ # ships at least one pnpm-lock.yaml, so an empty result here is a configuration
156
+ # error, not a clean pass — the same posture as `verify.sh`'s `ci_has()`
157
+ # (#1218) and `ci-wiring-audit.sh`'s empty-map check: "This audit checked
158
+ # nothing. That is a configuration error, not a pass." Exit 2 (not 1), the
159
+ # estate's "cannot tell" code, distinct from "found a vulnerability" (1) and
160
+ # "clean" (0) — CI treats any non-zero as a failed step either way.
161
+ if [ -z "$ALL_LOCKS" ]; then
162
+ printf '::error::js-dependency-audit: discovered ZERO pnpm-lock.yaml trees under %s.\n' "$REPO_ROOT" >&2
163
+ printf 'This audit checked nothing. That is a configuration error, not a pass — see #1270.\n' >&2
164
+ exit 2
165
+ fi
166
+
167
+ # Print what was scanned BEFORE auditing, so the list survives even if a later
168
+ # tree crashes the run — a bare green must be a falsifiable claim, not
169
+ # something a reader has to infer or re-enumerate by hand.
170
+ tree_count=$(printf '%s\n' "$ALL_LOCKS" | wc -l | tr -d ' ')
171
+ printf 'js-dependency-audit: discovered %s pnpm-lock.yaml tree(s):\n' "$tree_count"
172
+ for lock in $ALL_LOCKS; do
173
+ dir=$(dirname "$lock")
174
+ dir_abs=$(cd "$dir" 2>/dev/null && pwd -P)
175
+ case "$dir_abs" in
176
+ "$REPO_ROOT") rel=. ;;
177
+ "$REPO_ROOT"/*) rel=${dir_abs#"$REPO_ROOT"/} ;;
178
+ *) rel="$dir_abs" ;;
179
+ esac
180
+ if [ "$dir_abs" = "$WORKSPACE_ABS" ]; then
181
+ printf ' - %s (workspace)\n' "$rel"
182
+ else
183
+ printf ' - %s\n' "$rel"
184
+ fi
185
+ done
117
186
 
118
- # Every scaffolding tree with its own lockfile. Discovered rather than listed,
119
- # so a new skeleton is covered the day it lands instead of the day someone
120
- # remembers to add it here.
121
- for lock in $(find _skeletons -name pnpm-lock.yaml -not -path '*/node_modules/*' 2>/dev/null | sort); do
122
- audit_dir "$(dirname "$lock")" "pnpm audit ($(dirname "$lock"))" "--ignore-workspace" || failed=1
187
+ # Audit each discovered tree. The workspace's own lockfile is audited WITHOUT
188
+ # --ignore-workspace, so pnpm resolves it normally; every other discovered
189
+ # lockfile is a separate, vendored project and needs the flag, or pnpm walks
190
+ # up, finds the workspace, and silently audits THAT instead reporting clean
191
+ # for a tree it never looked at, which is this exact defect one level down.
192
+ for lock in $ALL_LOCKS; do
193
+ dir=$(dirname "$lock")
194
+ dir_abs=$(cd "$dir" 2>/dev/null && pwd -P)
195
+ case "$dir_abs" in
196
+ "$REPO_ROOT") rel=. ;;
197
+ "$REPO_ROOT"/*) rel=${dir_abs#"$REPO_ROOT"/} ;;
198
+ *) rel="$dir_abs" ;;
199
+ esac
200
+ if [ "$dir_abs" = "$WORKSPACE_ABS" ]; then
201
+ audit_dir "$dir" "pnpm audit (workspace: ${rel})" "" || failed=1
202
+ else
203
+ audit_dir "$dir" "pnpm audit (${rel})" "--ignore-workspace" || failed=1
204
+ fi
123
205
  done
124
206
 
125
207
  if [ "$failed" -ne 0 ]; then
@@ -130,4 +212,5 @@ if [ "$inconclusive" -ne 0 ]; then
130
212
  echo "${inconclusive} tree(s) could not be audited; see warnings above."
131
213
  fi
132
214
 
215
+ echo "js-dependency-audit: audited ${tree_count} tree(s), 0 blocking findings."
133
216
  exit 0
@@ -30,11 +30,23 @@
30
30
  # and it is clean" read identically to "we never checked".
31
31
  #
32
32
  # Unlike `pnpm audit --ignore-workspace`, pip-audit cannot simply be run inside
33
- # a skeleton directory: the skeleton is not an installed environment, and
34
- # pip-audit's default mode audits an environment. So we export `--frozen`
35
- # requirements from the skeleton's own lockfile (a read of the committed lock,
36
- # no re-resolution) and audit those with `-r`, from the workspace, which is
37
- # where pip-audit is actually installed.
33
+ # a nested directory: it is not an installed environment, and pip-audit's
34
+ # default mode audits an environment. So we export `--frozen` requirements from
35
+ # the nested lockfile (a read of the committed lock, no re-resolution) and
36
+ # audit those with `-r`, from the workspace, which is where pip-audit is
37
+ # actually installed.
38
+ #
39
+ # ## Discovery, not a fixed path list (#1270)
40
+ #
41
+ # A fixed sweep of "workspace + `_skeletons/**`" is the same shape of gap one
42
+ # level further down: it reports clean on any uv.lock outside that pair, and an
43
+ # INSTANCE grows trees this repo never has — vendored plugin services such as
44
+ # `services/idea-scout/uv.lock`. Found live: that lockfile and
45
+ # `services/ideation/uv.lock` both sat on `cryptography@49.0.0` (CVE-2026-69247)
46
+ # while this gate stayed green, because it never looked there.
47
+ #
48
+ # So every uv.lock under the repo is DISCOVERED by walking from the git root,
49
+ # rather than assumed from a hardcoded list — see "Discover the trees" below.
38
50
  #
39
51
  # ## This file is distributed verbatim (#743)
40
52
  #
@@ -44,11 +56,10 @@
44
56
  # shipped a raw `uv run pip-audit` — so every satellite was born with the
45
57
  # original defect and reddened a required check on any PyPI/OSV hiccup.
46
58
  #
47
- # It therefore takes its target from the CURRENT WORKING DIRECTORY — the CI
48
- # job's `working-directory` — rather than assuming a repo layout: `.` is the
49
- # root project here and in a plugin repo, `services/api` in a sibling, and the
50
- # `_skeletons/**` sweep below simply finds nothing outside this repo. Keep it
51
- # layout-agnostic, or the copies stop being interchangeable and
59
+ # It therefore takes its WORKSPACE tree from the CURRENT WORKING DIRECTORY —
60
+ # the CI job's `working-directory` — rather than assuming a repo layout: `.` is
61
+ # the root project here and in a plugin repo, `services/api` in a sibling. Keep
62
+ # it layout-agnostic, or the copies stop being interchangeable and
52
63
  # `shared-sync.sh --check` starts reporting drift that is really divergence.
53
64
  #
54
65
  # POSIX sh (the CI step runs `sh scripts/...`, i.e. dash) — no `pipefail`.
@@ -108,26 +119,89 @@ audit_deps() {
108
119
  return 0
109
120
  }
110
121
 
111
- # The workspace itself.
112
- audit_deps "pip-audit (workspace)" "" || failed=1
122
+ # ## Discover the trees (#1270)
123
+ #
124
+ # Walk from the git root — not the CWD this script happens to run from — so a
125
+ # vendored tree anywhere in the repo is found regardless of where the CI job's
126
+ # `working-directory` points. Excludes `node_modules`, `.git`, `.worktrees`
127
+ # (other agents' in-progress checkouts) and `.venv` (an installed environment,
128
+ # not a lockfile source).
129
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
130
+ if [ -z "$REPO_ROOT" ]; then
131
+ echo "::error::py-dependency-audit: not inside a git repository ('git rev-parse --show-toplevel' failed). Discovery cannot walk a tree it cannot find." >&2
132
+ exit 2
133
+ fi
134
+
135
+ WORKSPACE_ABS=$(pwd -P)
136
+
137
+ # shellcheck disable=SC2016
138
+ ALL_LOCKS=$(find "$REPO_ROOT" \
139
+ \( -name node_modules -o -name .git -o -name .worktrees -o -name .venv \) -prune -o \
140
+ -type f -name uv.lock -print 2>/dev/null | sort)
141
+
142
+ # Fail CLOSED, not open, on an empty discovery (#1270). Zero trees — including
143
+ # no uv.lock at the workspace root itself — means discovery is broken, not
144
+ # that the repo has nothing to audit. Same posture as `verify.sh`'s `ci_has()`
145
+ # (#1218) and `ci-wiring-audit.sh`'s empty-map check: "This audit checked
146
+ # nothing. That is a configuration error, not a pass." Exit 2, the estate's
147
+ # "cannot tell" code, distinct from "found a vulnerability" (1) and "clean"
148
+ # (0) — CI treats any non-zero as a failed step either way.
149
+ if [ -z "$ALL_LOCKS" ]; then
150
+ printf '::error::py-dependency-audit: discovered ZERO uv.lock trees under %s.\n' "$REPO_ROOT" >&2
151
+ printf 'This audit checked nothing. That is a configuration error, not a pass — see #1270.\n' >&2
152
+ exit 2
153
+ fi
154
+
155
+ # Print what was scanned BEFORE auditing, so the list survives even if a later
156
+ # tree crashes the run — a bare green must be a falsifiable claim, not
157
+ # something a reader has to infer or re-enumerate by hand.
158
+ tree_count=$(printf '%s\n' "$ALL_LOCKS" | wc -l | tr -d ' ')
159
+ printf 'py-dependency-audit: discovered %s uv.lock tree(s):\n' "$tree_count"
160
+ for lock in $ALL_LOCKS; do
161
+ dir=$(dirname "$lock")
162
+ dir_abs=$(cd "$dir" 2>/dev/null && pwd -P)
163
+ case "$dir_abs" in
164
+ "$REPO_ROOT") rel=. ;;
165
+ "$REPO_ROOT"/*) rel=${dir_abs#"$REPO_ROOT"/} ;;
166
+ *) rel="$dir_abs" ;;
167
+ esac
168
+ if [ "$dir_abs" = "$WORKSPACE_ABS" ]; then
169
+ printf ' - %s (workspace)\n' "$rel"
170
+ else
171
+ printf ' - %s\n' "$rel"
172
+ fi
173
+ done
174
+
175
+ # Audit each discovered tree. The workspace's own lockfile is audited via the
176
+ # INSTALLED environment `uv sync` already produced (unchanged from before —
177
+ # `uv run pip-audit` with no `-r`). Every other discovered lockfile is not an
178
+ # installed environment, so it is exported with `--frozen` (a read of the
179
+ # committed lock, no re-resolution) and audited with `-r`, from the workspace,
180
+ # which is where pip-audit is actually installed.
181
+ for lock in $ALL_LOCKS; do
182
+ dir=$(dirname "$lock")
183
+ dir_abs=$(cd "$dir" 2>/dev/null && pwd -P)
184
+ case "$dir_abs" in
185
+ "$REPO_ROOT") rel=. ;;
186
+ "$REPO_ROOT"/*) rel=${dir_abs#"$REPO_ROOT"/} ;;
187
+ *) rel="$dir_abs" ;;
188
+ esac
189
+
190
+ if [ "$dir_abs" = "$WORKSPACE_ABS" ]; then
191
+ audit_deps "pip-audit (workspace: ${rel})" "" || failed=1
192
+ continue
193
+ fi
113
194
 
114
- # Every scaffolding tree with its own lockfile. Discovered rather than listed,
115
- # so a new skeleton is covered the day it lands instead of the day someone
116
- # remembers to add it here.
117
- for lock in $(find _skeletons -name uv.lock -not -path '*/node_modules/*' 2>/dev/null | sort); do
118
- dir="$(dirname "$lock")"
119
195
  reqs="$(mktemp)"
120
196
 
121
- # `--frozen` reads the committed lock verbatim instead of re-resolving, so
122
- # what gets audited is exactly what a scaffolded sibling would be born with.
123
- # `--no-emit-project` drops the skeleton package itself (nothing published to
197
+ # `--no-emit-project` drops the tree's own package (nothing published to
124
198
  # audit); `--no-dev` keeps the audit to what actually ships.
125
199
  if (cd "$dir" && uv export --frozen --no-dev --no-emit-project) >"$reqs" 2>/dev/null && [ -s "$reqs" ]; then
126
- audit_deps "pip-audit (${dir})" "-r $reqs" || failed=1
200
+ audit_deps "pip-audit (${rel})" "-r $reqs" || failed=1
127
201
  else
128
202
  # An export failure is "couldn't run", not "clean" — same discipline as a
129
203
  # transient pip-audit error, and it must never read as a pass.
130
- echo "::warning::pip-audit (${dir}): could not export requirements from ${lock}; treating as INCONCLUSIVE and not blocking. Advisory scanning was NOT performed for this tree — see #719."
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."
131
205
  inconclusive=$((inconclusive + 1))
132
206
  fi
133
207
 
@@ -142,4 +216,5 @@ if [ "$inconclusive" -ne 0 ]; then
142
216
  echo "${inconclusive} tree(s) could not be audited; see warnings above."
143
217
  fi
144
218
 
219
+ echo "py-dependency-audit: audited ${tree_count} tree(s), 0 blocking findings."
145
220
  exit 0
@@ -30,6 +30,23 @@
30
30
  # the gate was green because it was not looking, and "we checked and it is
31
31
  # clean" read identically to "we never checked".
32
32
  #
33
+ # ## Discovery, not a fixed path list (#1270)
34
+ #
35
+ # A fixed sweep of "workspace root + `_skeletons/**`" is itself the same shape
36
+ # of gap, one level further down: it reports clean on any pnpm-lock.yaml
37
+ # outside that pair, and an INSTANCE grows trees this repo never has —
38
+ # vendored plugin frontends under `services/*/web/`, a second app under
39
+ # `web-admin/`, or any other nested pnpm project. Found live:
40
+ # `services/ideation/web/pnpm-lock.yaml` sat on two advisory-range packages
41
+ # (one high) while this exact gate stayed green, because it never looked
42
+ # there. Ten lockfiles in that repo; a fixed sweep covered nine.
43
+ #
44
+ # So every pnpm-lock.yaml under the repo is DISCOVERED by walking from the git
45
+ # root, rather than assumed from a hardcoded list — see "Discover the trees"
46
+ # below. Nothing here still means the estate's layouts differ; discovery
47
+ # covers a repo the day it grows a new one, instead of the day someone
48
+ # remembers to add a path.
49
+ #
33
50
  # ## This file is distributed verbatim (#743)
34
51
  #
35
52
  # Both skeletons and every existing sibling/plugin repo hold a BYTE-IDENTICAL
@@ -39,10 +56,9 @@
39
56
  # every satellite was born with the original defect and reddened its required JS
40
57
  # check on any registry hiccup.
41
58
  #
42
- # It therefore takes its target from the CURRENT WORKING DIRECTORY — the CI
43
- # job's `working-directory` — rather than assuming a repo layout: `.` is the
44
- # root workspace here, `apps/frontend` in a sibling, and the `_skeletons/**`
45
- # sweep below simply finds nothing outside this repo. Keep it layout-agnostic,
59
+ # It therefore takes its WORKSPACE tree from the CURRENT WORKING DIRECTORY —
60
+ # the CI job's `working-directory` — rather than assuming a repo layout: `.` is
61
+ # the root workspace here, `apps/frontend` in a sibling. Keep it layout-agnostic,
46
62
  # or the copies stop being interchangeable and `shared-sync.sh --check` starts
47
63
  # reporting drift that is really divergence.
48
64
  #
@@ -112,14 +128,80 @@ audit_dir() {
112
128
  return 0
113
129
  }
114
130
 
115
- # The workspace itself.
116
- audit_dir "." "pnpm audit (workspace)" "" || failed=1
131
+ # ## Discover the trees (#1270)
132
+ #
133
+ # Walk from the git root — not the CWD this script happens to run from — so a
134
+ # vendored tree anywhere in the repo is found regardless of where the CI job's
135
+ # `working-directory` points. Excludes `node_modules` (installed, not source),
136
+ # `.git`, and `.worktrees` (other agents' in-progress checkouts, git-ignored
137
+ # and not part of this run).
138
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
139
+ if [ -z "$REPO_ROOT" ]; then
140
+ echo "::error::js-dependency-audit: not inside a git repository ('git rev-parse --show-toplevel' failed). Discovery cannot walk a tree it cannot find." >&2
141
+ exit 2
142
+ fi
143
+
144
+ WORKSPACE_ABS=$(pwd -P)
145
+
146
+ # shellcheck disable=SC2016
147
+ ALL_LOCKS=$(find "$REPO_ROOT" \
148
+ \( -name node_modules -o -name .git -o -name .worktrees \) -prune -o \
149
+ -type f -name pnpm-lock.yaml -print 2>/dev/null | sort)
150
+
151
+ # Fail CLOSED, not open, on an empty discovery (#1270). Zero trees — including
152
+ # no lockfile at the workspace root itself — means discovery is broken (a
153
+ # wrong root, an over-eager prune, a repo layout this script has never seen),
154
+ # not that the repo has nothing to audit. Every repo this script is wired into
155
+ # ships at least one pnpm-lock.yaml, so an empty result here is a configuration
156
+ # error, not a clean pass — the same posture as `verify.sh`'s `ci_has()`
157
+ # (#1218) and `ci-wiring-audit.sh`'s empty-map check: "This audit checked
158
+ # nothing. That is a configuration error, not a pass." Exit 2 (not 1), the
159
+ # estate's "cannot tell" code, distinct from "found a vulnerability" (1) and
160
+ # "clean" (0) — CI treats any non-zero as a failed step either way.
161
+ if [ -z "$ALL_LOCKS" ]; then
162
+ printf '::error::js-dependency-audit: discovered ZERO pnpm-lock.yaml trees under %s.\n' "$REPO_ROOT" >&2
163
+ printf 'This audit checked nothing. That is a configuration error, not a pass — see #1270.\n' >&2
164
+ exit 2
165
+ fi
166
+
167
+ # Print what was scanned BEFORE auditing, so the list survives even if a later
168
+ # tree crashes the run — a bare green must be a falsifiable claim, not
169
+ # something a reader has to infer or re-enumerate by hand.
170
+ tree_count=$(printf '%s\n' "$ALL_LOCKS" | wc -l | tr -d ' ')
171
+ printf 'js-dependency-audit: discovered %s pnpm-lock.yaml tree(s):\n' "$tree_count"
172
+ for lock in $ALL_LOCKS; do
173
+ dir=$(dirname "$lock")
174
+ dir_abs=$(cd "$dir" 2>/dev/null && pwd -P)
175
+ case "$dir_abs" in
176
+ "$REPO_ROOT") rel=. ;;
177
+ "$REPO_ROOT"/*) rel=${dir_abs#"$REPO_ROOT"/} ;;
178
+ *) rel="$dir_abs" ;;
179
+ esac
180
+ if [ "$dir_abs" = "$WORKSPACE_ABS" ]; then
181
+ printf ' - %s (workspace)\n' "$rel"
182
+ else
183
+ printf ' - %s\n' "$rel"
184
+ fi
185
+ done
117
186
 
118
- # Every scaffolding tree with its own lockfile. Discovered rather than listed,
119
- # so a new skeleton is covered the day it lands instead of the day someone
120
- # remembers to add it here.
121
- for lock in $(find _skeletons -name pnpm-lock.yaml -not -path '*/node_modules/*' 2>/dev/null | sort); do
122
- audit_dir "$(dirname "$lock")" "pnpm audit ($(dirname "$lock"))" "--ignore-workspace" || failed=1
187
+ # Audit each discovered tree. The workspace's own lockfile is audited WITHOUT
188
+ # --ignore-workspace, so pnpm resolves it normally; every other discovered
189
+ # lockfile is a separate, vendored project and needs the flag, or pnpm walks
190
+ # up, finds the workspace, and silently audits THAT instead reporting clean
191
+ # for a tree it never looked at, which is this exact defect one level down.
192
+ for lock in $ALL_LOCKS; do
193
+ dir=$(dirname "$lock")
194
+ dir_abs=$(cd "$dir" 2>/dev/null && pwd -P)
195
+ case "$dir_abs" in
196
+ "$REPO_ROOT") rel=. ;;
197
+ "$REPO_ROOT"/*) rel=${dir_abs#"$REPO_ROOT"/} ;;
198
+ *) rel="$dir_abs" ;;
199
+ esac
200
+ if [ "$dir_abs" = "$WORKSPACE_ABS" ]; then
201
+ audit_dir "$dir" "pnpm audit (workspace: ${rel})" "" || failed=1
202
+ else
203
+ audit_dir "$dir" "pnpm audit (${rel})" "--ignore-workspace" || failed=1
204
+ fi
123
205
  done
124
206
 
125
207
  if [ "$failed" -ne 0 ]; then
@@ -130,4 +212,5 @@ if [ "$inconclusive" -ne 0 ]; then
130
212
  echo "${inconclusive} tree(s) could not be audited; see warnings above."
131
213
  fi
132
214
 
215
+ echo "js-dependency-audit: audited ${tree_count} tree(s), 0 blocking findings."
133
216
  exit 0
@@ -30,11 +30,23 @@
30
30
  # and it is clean" read identically to "we never checked".
31
31
  #
32
32
  # Unlike `pnpm audit --ignore-workspace`, pip-audit cannot simply be run inside
33
- # a skeleton directory: the skeleton is not an installed environment, and
34
- # pip-audit's default mode audits an environment. So we export `--frozen`
35
- # requirements from the skeleton's own lockfile (a read of the committed lock,
36
- # no re-resolution) and audit those with `-r`, from the workspace, which is
37
- # where pip-audit is actually installed.
33
+ # a nested directory: it is not an installed environment, and pip-audit's
34
+ # default mode audits an environment. So we export `--frozen` requirements from
35
+ # the nested lockfile (a read of the committed lock, no re-resolution) and
36
+ # audit those with `-r`, from the workspace, which is where pip-audit is
37
+ # actually installed.
38
+ #
39
+ # ## Discovery, not a fixed path list (#1270)
40
+ #
41
+ # A fixed sweep of "workspace + `_skeletons/**`" is the same shape of gap one
42
+ # level further down: it reports clean on any uv.lock outside that pair, and an
43
+ # INSTANCE grows trees this repo never has — vendored plugin services such as
44
+ # `services/idea-scout/uv.lock`. Found live: that lockfile and
45
+ # `services/ideation/uv.lock` both sat on `cryptography@49.0.0` (CVE-2026-69247)
46
+ # while this gate stayed green, because it never looked there.
47
+ #
48
+ # So every uv.lock under the repo is DISCOVERED by walking from the git root,
49
+ # rather than assumed from a hardcoded list — see "Discover the trees" below.
38
50
  #
39
51
  # ## This file is distributed verbatim (#743)
40
52
  #
@@ -44,11 +56,10 @@
44
56
  # shipped a raw `uv run pip-audit` — so every satellite was born with the
45
57
  # original defect and reddened a required check on any PyPI/OSV hiccup.
46
58
  #
47
- # It therefore takes its target from the CURRENT WORKING DIRECTORY — the CI
48
- # job's `working-directory` — rather than assuming a repo layout: `.` is the
49
- # root project here and in a plugin repo, `services/api` in a sibling, and the
50
- # `_skeletons/**` sweep below simply finds nothing outside this repo. Keep it
51
- # layout-agnostic, or the copies stop being interchangeable and
59
+ # It therefore takes its WORKSPACE tree from the CURRENT WORKING DIRECTORY —
60
+ # the CI job's `working-directory` — rather than assuming a repo layout: `.` is
61
+ # the root project here and in a plugin repo, `services/api` in a sibling. Keep
62
+ # it layout-agnostic, or the copies stop being interchangeable and
52
63
  # `shared-sync.sh --check` starts reporting drift that is really divergence.
53
64
  #
54
65
  # POSIX sh (the CI step runs `sh scripts/...`, i.e. dash) — no `pipefail`.
@@ -108,26 +119,89 @@ audit_deps() {
108
119
  return 0
109
120
  }
110
121
 
111
- # The workspace itself.
112
- audit_deps "pip-audit (workspace)" "" || failed=1
122
+ # ## Discover the trees (#1270)
123
+ #
124
+ # Walk from the git root — not the CWD this script happens to run from — so a
125
+ # vendored tree anywhere in the repo is found regardless of where the CI job's
126
+ # `working-directory` points. Excludes `node_modules`, `.git`, `.worktrees`
127
+ # (other agents' in-progress checkouts) and `.venv` (an installed environment,
128
+ # not a lockfile source).
129
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
130
+ if [ -z "$REPO_ROOT" ]; then
131
+ echo "::error::py-dependency-audit: not inside a git repository ('git rev-parse --show-toplevel' failed). Discovery cannot walk a tree it cannot find." >&2
132
+ exit 2
133
+ fi
134
+
135
+ WORKSPACE_ABS=$(pwd -P)
136
+
137
+ # shellcheck disable=SC2016
138
+ ALL_LOCKS=$(find "$REPO_ROOT" \
139
+ \( -name node_modules -o -name .git -o -name .worktrees -o -name .venv \) -prune -o \
140
+ -type f -name uv.lock -print 2>/dev/null | sort)
141
+
142
+ # Fail CLOSED, not open, on an empty discovery (#1270). Zero trees — including
143
+ # no uv.lock at the workspace root itself — means discovery is broken, not
144
+ # that the repo has nothing to audit. Same posture as `verify.sh`'s `ci_has()`
145
+ # (#1218) and `ci-wiring-audit.sh`'s empty-map check: "This audit checked
146
+ # nothing. That is a configuration error, not a pass." Exit 2, the estate's
147
+ # "cannot tell" code, distinct from "found a vulnerability" (1) and "clean"
148
+ # (0) — CI treats any non-zero as a failed step either way.
149
+ if [ -z "$ALL_LOCKS" ]; then
150
+ printf '::error::py-dependency-audit: discovered ZERO uv.lock trees under %s.\n' "$REPO_ROOT" >&2
151
+ printf 'This audit checked nothing. That is a configuration error, not a pass — see #1270.\n' >&2
152
+ exit 2
153
+ fi
154
+
155
+ # Print what was scanned BEFORE auditing, so the list survives even if a later
156
+ # tree crashes the run — a bare green must be a falsifiable claim, not
157
+ # something a reader has to infer or re-enumerate by hand.
158
+ tree_count=$(printf '%s\n' "$ALL_LOCKS" | wc -l | tr -d ' ')
159
+ printf 'py-dependency-audit: discovered %s uv.lock tree(s):\n' "$tree_count"
160
+ for lock in $ALL_LOCKS; do
161
+ dir=$(dirname "$lock")
162
+ dir_abs=$(cd "$dir" 2>/dev/null && pwd -P)
163
+ case "$dir_abs" in
164
+ "$REPO_ROOT") rel=. ;;
165
+ "$REPO_ROOT"/*) rel=${dir_abs#"$REPO_ROOT"/} ;;
166
+ *) rel="$dir_abs" ;;
167
+ esac
168
+ if [ "$dir_abs" = "$WORKSPACE_ABS" ]; then
169
+ printf ' - %s (workspace)\n' "$rel"
170
+ else
171
+ printf ' - %s\n' "$rel"
172
+ fi
173
+ done
174
+
175
+ # Audit each discovered tree. The workspace's own lockfile is audited via the
176
+ # INSTALLED environment `uv sync` already produced (unchanged from before —
177
+ # `uv run pip-audit` with no `-r`). Every other discovered lockfile is not an
178
+ # installed environment, so it is exported with `--frozen` (a read of the
179
+ # committed lock, no re-resolution) and audited with `-r`, from the workspace,
180
+ # which is where pip-audit is actually installed.
181
+ for lock in $ALL_LOCKS; do
182
+ dir=$(dirname "$lock")
183
+ dir_abs=$(cd "$dir" 2>/dev/null && pwd -P)
184
+ case "$dir_abs" in
185
+ "$REPO_ROOT") rel=. ;;
186
+ "$REPO_ROOT"/*) rel=${dir_abs#"$REPO_ROOT"/} ;;
187
+ *) rel="$dir_abs" ;;
188
+ esac
189
+
190
+ if [ "$dir_abs" = "$WORKSPACE_ABS" ]; then
191
+ audit_deps "pip-audit (workspace: ${rel})" "" || failed=1
192
+ continue
193
+ fi
113
194
 
114
- # Every scaffolding tree with its own lockfile. Discovered rather than listed,
115
- # so a new skeleton is covered the day it lands instead of the day someone
116
- # remembers to add it here.
117
- for lock in $(find _skeletons -name uv.lock -not -path '*/node_modules/*' 2>/dev/null | sort); do
118
- dir="$(dirname "$lock")"
119
195
  reqs="$(mktemp)"
120
196
 
121
- # `--frozen` reads the committed lock verbatim instead of re-resolving, so
122
- # what gets audited is exactly what a scaffolded sibling would be born with.
123
- # `--no-emit-project` drops the skeleton package itself (nothing published to
197
+ # `--no-emit-project` drops the tree's own package (nothing published to
124
198
  # audit); `--no-dev` keeps the audit to what actually ships.
125
199
  if (cd "$dir" && uv export --frozen --no-dev --no-emit-project) >"$reqs" 2>/dev/null && [ -s "$reqs" ]; then
126
- audit_deps "pip-audit (${dir})" "-r $reqs" || failed=1
200
+ audit_deps "pip-audit (${rel})" "-r $reqs" || failed=1
127
201
  else
128
202
  # An export failure is "couldn't run", not "clean" — same discipline as a
129
203
  # transient pip-audit error, and it must never read as a pass.
130
- echo "::warning::pip-audit (${dir}): could not export requirements from ${lock}; treating as INCONCLUSIVE and not blocking. Advisory scanning was NOT performed for this tree — see #719."
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."
131
205
  inconclusive=$((inconclusive + 1))
132
206
  fi
133
207
 
@@ -142,4 +216,5 @@ if [ "$inconclusive" -ne 0 ]; then
142
216
  echo "${inconclusive} tree(s) could not be audited; see warnings above."
143
217
  fi
144
218
 
219
+ echo "py-dependency-audit: audited ${tree_count} tree(s), 0 blocking findings."
145
220
  exit 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.246.1",
3
+ "version": "0.246.3",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",