Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

scan --sync / --mode agent never re-applies an already-recorded patch, so after a fresh Hatch env (or any reinstall) it exits 0 with the package unpatched

Đã đóng
#454 3 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
72/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python, rust
Lĩnh vực
cli

Hướng nghiên cứu

Start in crates/socket-patch-cli/src/commands/get.rs at the downloaded > 0 gates around lines 2438 and 2485, then trace how scan --mode agent and --sync call download_and_apply_patches_with. Use the provided Hatch reproduction to verify that a second scan after recreating the environment reapplies the recorded patch and does not report success when application fails. The issue does not name a test file.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

agent:claimed agent:triaged bug bughunt pm:hatch priority:p1

[agent] Found by the scheduled Hatch bug-hunt routine (ledger #314).

Summary

scan --mode agent and scan --sync only run the nested apply when the run downloaded a new or updated patch record. When every discovered patch is already in .socket/manifest.json, the records come back skipped and apply never runs. The installed files aren't checked or re-patched, and the scan reports "status": "success", applied: 0, exit 0.

So after anything that reinstalls the package (hatch env remove + hatch env create, hatch env prune, a CI cache miss, a new matrix env, pip install --force-reinstall, or a failed first apply), re-running the scan leaves the environment unpatched and reports success. The same happens with --global-prefix / -g after a first run whose apply failed: once the prefix is writable again, the re-run exits 0 and still doesn't patch it.

This isn't Hatch-specific. The gate is in the shared download_and_apply_patches_with. I found it with real Hatch, where recreating envs is routine.

Impact

--sync is documented as the one-shot reconciliation: the help text at crates/socket-patch-cli/src/commands/scan/mod.rs:289 says "a cron job or CI workflow can run socket-patch scan --json --sync to end up fully reconciled in one invocation". A CI job that runs hatch env create && socket-patch scan --sync --json passes green on every run after the first while the env runs the vulnerable code. The only signal is that vex afterwards refuses to attest (not_applied), which is correct but easy to miss.

Repro (Linux, Hatch 1.18.1, mock patch API serving a six 1.16.0 patch)

mkdir rr && cd rr && mkdir app && touch app/__init__.py
cat > pyproject.toml <<'EOF'
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "app"
version = "0.1.0"
dependencies = ["six==1.16.0"]

[tool.hatch.build.targets.wheel]
packages = ["app"]

[tool.hatch.envs.default]
path = ".venv"
EOF
export SOCKET_API_URL=http://127.0.0.1:8765 SOCKET_API_TOKEN=fake SOCKET_ORG_SLUG=org SOCKET_PATCH_SERVER_URL=http://127.0.0.1:8765
hatch env create
socket-patch scan --mode agent --json --yes      # applied 1, six patched
hatch env remove default && hatch env create      # fresh env, pristine six
socket-patch scan --mode agent --json --yes; echo $?   # success, skipped 1, applied 0, exit 0, six NOT patched
hatch env remove default && hatch env create
socket-patch scan --sync --json --yes; echo $?         # same: success, skipped 1, exit 0, six NOT patched
socket-patch apply --json                              # applied 1: the only thing that actually reconciles

Output on 1.18.1 (the 1.7.0 output is identical):

  scan --mode agent: success applied 1 skipped 0 exit=0 import_patched=True
 -- hatch env remove + create
  scan --mode agent: success applied 0 skipped 1 exit=0 import_patched=False
 -- hatch env remove + create
  scan --sync: success applied 0 skipped 1 exit=0 import_patched=False
Warning: omitting pkg:pypi/[email protected] from VEX: the patched files still hold the original content (not_applied)

Global-prefix variant, without Hatch: pip install --target <prefix> six==1.16.0, then scan --global-prefix <prefix> --mode agent (applied 1), reinstall six, then re-scan. The re-scan gives success, skipped 1, exit 0, unpatched. --sync does the same, and each ran twice. Starting from a read-only prefix as non-root (runuser -u nobody), the first scan exits 1 (its JSON is the #424 shape), and the second scan exits 0 with success even after the prefix is made writable again.

Expected vs actual

  • Expected: scan --mode agent records and applies (docs/usage.md "Agent mode records patches and applies them to installed files"), and --sync ends "fully reconciled in one invocation". A record that's already in the manifest but not applied to the installed copy should be applied, as apply does. At minimum, the scan shouldn't report success / exit 0 while a discovered, recorded patch is unapplied.
  • Actual: skipped records short-circuit the nested apply, and the installed tree is never looked at.

OS × version

Cell Result
Linux, Hatch 1.18.1, .venv env, scan --mode agent after env recreate ❌ exit 0, unpatched
Linux, Hatch 1.18.1, scan --sync after env recreate ❌ exit 0, unpatched
Linux, Hatch 1.7.0, both of the above ❌
Linux, --global-prefix (pip --target), after reinstall, agent and --sync ❌
Linux, --global-prefix read-only then writable, non-root ❌ second run exits 0
socket-patch apply in the same states (control) ✅ re-applies
vex in the same states (control) ✅ omits not_applied

The logic is OS-independent (no path or filesystem handling is involved).

First bad version

Released v4.0.0 (PyPI socket-patch==4.0.0) behaves the same, so this isn't a v5 regression.

Suspect code

  • crates/socket-patch-cli/src/commands/get.rs:2438: let apply_lock = if !params.save_only && downloaded > 0 {. The nested apply (and its lock) only exists when something was downloaded.
  • crates/socket-patch-cli/src/commands/get.rs:2485: apply_failed is gated on downloaded > 0 too, so an all-skipped run can never fail.

Related, but a separate defect: #424 (the scan JSON drops the apply failure on the first run).

Ngôn ngữ chính
Rust
Star
8
Fork
1
Merge trung bình
19 giờ 1 phút
Pull request đã merge (30 ngày)
473

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của SocketDev/socket-patch

Tất cả issue của SocketDev/socket-patch

Issue tương tự

Thêm issue về Rust

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.