Skip to content

Commit b812a18

Browse files
authored
fix: preserve directory-only manifest patterns
Address peer review feedback by retaining pathlib.rglob trailing-slash semantics, trimming the release notes, and removing redundant implementation commentary.
1 parent a7c6ba3 commit b812a18

3 files changed

Lines changed: 33 additions & 44 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,22 @@
44

55
### Changed: faster local scan setup for large repositories
66

7-
- Replaced repeated per-pattern recursive manifest globs with one streaming
8-
filesystem walk per scan root. Excluded directories and `.git` are pruned
9-
before descent, reducing filesystem metadata work without building a
10-
repository-sized in-memory file index.
11-
- Removed the unconditional `git fetch --all` from CLI initialization. Pull
12-
request scans now use local refs first and fetch only a required base or head
13-
ref when the checkout does not contain enough history.
14-
- Added native Buildkite commit, branch, pull-request range, and GitHub SCM
15-
configuration fallbacks so Buildkite jobs no longer need GitHub
16-
Actions-shaped environment-variable shims.
17-
- Added INFO-level timings for CLI run registration, organization setup, Git
18-
initialization and fetches, changed-file detection, supported-pattern lookup,
19-
and manifest discovery.
20-
- Supported manifest patterns are cached for each CLI invocation once the API
21-
returns them, so a transient lookup failure no longer keeps the run on the
22-
smaller local fallback pattern set. Manifest results from `--sub-path` routing
23-
are reused during scan creation.
7+
- Manifest discovery now uses one filesystem walk per scan root and prunes
8+
excluded directories before descent.
9+
- Pull request scans use local Git refs first and fetch only missing history.
10+
Buildkite pull request metadata is now supported directly.
11+
- Supported manifest patterns are cached per invocation, and discovered
12+
manifests are reused during scan creation.
13+
- Added timings for initialization, Git operations, changed-file detection,
14+
pattern lookup, and manifest discovery.
2415

2516
### Changed: scan comparisons no longer fetch unused artifacts
2617

27-
- Scan comparisons now ask the API to omit unchanged artifacts unless an enabled
28-
output actually reads them (`--strict-blocking`, `--enable-gitlab-security`,
29-
`--generate-license`, or `--legal-format fossa`). Cached comparison responses
30-
embed every unchanged artifact at roughly 1 KB each, so on a large dependency
31-
tree this was most of the response — over 10 MB for a tree of ~10k unchanged
32-
packages — downloaded and parsed on every pull request even when nothing read
33-
it. Behavior is unchanged for any run that uses those outputs.
34-
35-
### Changed: scan comparison timing is easier to attribute
36-
37-
- Lowered the diff-scan poll ceiling from 30s to 10s. A finished comparison is no
38-
longer left unobserved for up to half a minute, which matters when the CLI runs
39-
inside a CI step with a per-step time budget.
40-
- Diff scans now log their ID, poll count, and the wait before the final poll, so
41-
a CI log distinguishes backend comparison time from time spent between polls.
18+
- Scan comparisons omit unchanged artifacts unless an enabled output needs them.
19+
- Diff scans poll more frequently and log identifiers and timing details for
20+
easier troubleshooting.
4221
- Documented the `diff-scans:create`, `diff-scans:list` and `full-scans:list`
43-
token scopes. Without them the comparison silently falls back to the older
44-
streaming path.
22+
token scopes required by the optimized comparison path.
4523

4624
## 2.6.5
4725

socketsecurity/core/__init__.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,6 @@
103103
# minutes to compute. The timeout is a backstop against a diff scan that never
104104
# completes; on expiry (or any other failure of this flow) the caller falls back to the
105105
# legacy streaming comparison rather than failing the scan outright.
106-
#
107-
# The max interval is also the upper bound on how long a finished comparison sits
108-
# unnoticed between polls, which is dead time added to every PR job. Callers commonly
109-
# run this inside a CI step with a per-step time budget of a few minutes, so the cap is
110-
# kept small: a multi-minute comparison costs roughly 2x the polls of a 30s cap while
111-
# cutting the worst-case dead time from 30s to 10s. Diff scans log their poll count and
112-
# last interval on completion so this tradeoff can be re-evaluated against real timings.
113106
DIFF_SCAN_POLL_INITIAL_INTERVAL_SECONDS = 5.0
114107
DIFF_SCAN_POLL_MAX_INTERVAL_SECONDS = 10.0
115108
DIFF_SCAN_POLL_BACKOFF_MULTIPLIER = 1.5
@@ -495,12 +488,12 @@ def _prepare_manifest_patterns(
495488
# PurePath.match compares pattern segments right to left, so a path-shaped glob
496489
# can only match a file whose basename matches the glob's final segment. Folding
497490
# those final segments into the basename prefilter lets the walk skip the path
498-
# match for everything else. An empty final segment (a trailing "/") constrains
499-
# nothing, so it becomes "*" and the prefilter admits every name.
491+
# match for everything else. A trailing "/" is directory-only under the legacy
492+
# rglob behavior, so its empty final segment intentionally admits no files.
500493
candidate_basenames = set(literal_basenames)
501494
candidate_basename_globs = set(basename_globs)
502495
for pattern in path_globs:
503-
final_segment = pattern.rstrip("/").rsplit("/", 1)[-1] or "*"
496+
final_segment = pattern.rsplit("/", 1)[-1]
504497
if any(character in final_segment for character in "*?["):
505498
candidate_basename_globs.add(final_segment)
506499
else:

tests/unit/test_manifest_discovery.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,24 @@ def test_single_walk_matches_legacy_rglob_results_for_builtin_patterns(tmp_path)
117117
assert set(core.find_files(str(tmp_path))) == legacy_results
118118

119119

120+
def test_directory_only_pattern_does_not_match_same_named_file(tmp_path):
121+
"""A trailing slash keeps pathlib.rglob's directory-only semantics."""
122+
_write_files(
123+
tmp_path,
124+
{
125+
"manifests/package.json",
126+
"nested/manifests",
127+
},
128+
)
129+
patterns = {
130+
"test": {
131+
"directory-only": {"pattern": "manifests/"},
132+
},
133+
}
134+
135+
assert _make_core(patterns=patterns).find_files(str(tmp_path)) == []
136+
137+
120138
def test_prunes_git_default_globs_and_exclude_paths_before_descent(
121139
tmp_path, mocker, caplog
122140
):

0 commit comments

Comments
 (0)