You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 345660e
Browse filesBrowse the repository at this point in the historyBrowse files
* Start fix for #641
Assisted-by: Claude Code:claude-opus-5-5
* Warn when PDM < 2.11 keeps an unpatched install
Vendoring a patch into a PDM project whose pdm.lock was written by
PDM before 2.11 (lock_version 2, 4.3 or 4.4) left an env that already
held the package unpatched: PDM keeps a same-version install on
`pdm sync`, the scan said nothing, and `vex` attested not_affected
with a "re-run your install" hint that does not help.
The vendored PDM flavor now probes the env PDM installs into (its
venv or PEP 582 __pypackages__) like the Pipenv and Hatch flavors,
and warns pypi_pdm_stale_install with the remedy that release line
supports: `pdm sync --reinstall` on PDM 2.x, or removing the
installed copy before `pdm sync` on PDM 1.x, which has no
--reinstall. vex's vendored_tree_out_of_sync hint names the same
remedy. A 2.11+ lock stays silent.
Fixes#641
Assisted-by: Claude Code:claude-opus-5-5
* Format the PDM stale-install changes
Assisted-by: Claude Code:claude-opus-5-5
* Tighten the PDM stale-install advice
Review follow-ups for the PDM < 2.11 stale-install warning:
- warn on a superseding re-wire too, not only fresh and in-sync runs
- name a copy inherited from the base interpreter of a
--system-site-packages venv apart, with a remedy that reaches it
- add vex's PDM hint only for a package pdm.lock wires to a vendored
artifact, reading pdm.lock once per run instead of once per package
- share the "keeps an installed release" lock-version check between
hosted and vendored mode
- say "PDM before 2.0" for lock_version 2, which PDM 0.x writes too
Assisted-by: Claude Code:claude-opus-5-5
---------
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: crates/socket-patch-cli/CLI_CONTRACT.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -487,7 +487,7 @@ Contract details:
487
487
* **JSON success surface**: `apply` adds a top-level `vex` object to its envelope; `scan` adds a top-level `vex` key to its result. Both carry `{ path, statements, format: "openvex-0.2.0" }`.
488
488
* `apply`'s no-manifest early exit (the `noManifest` success no-op; v5.0: its human line is `No patch manifest found; nothing to apply.` — it names the missing `.socket/manifest.json`, not the folder, since `.socket/` may legitimately hold vendored state) and `vendor`'s (`No manifest found, nothing to vendor.` — a project with hosted pins ejects instead, v5.0) still generate the document from the lockfiles and the vendor ledger (manifest-less VEX: hosted / vendored checkouts carry no manifest). Nothing referenced anywhere keeps the calm exit 0 (a stale document at the path is removed; `--json` carries any discovery diagnostics in `warnings[]`); any other VEX failure fails the command with exit 1 — including a run whose only candidates are omitted `record_unavailable` (an `--offline` run over a lockfile-wired checkout with no local records), so an ambient `SOCKET_VEX` there fails the install. `--dry-run` skips generation on both, and so does `apply --check` — it stays read-only and offline-safe, leaving the output path untouched. `scan` has no such early exit: with no manifest and nothing wired anywhere its `--vex` fails with `manifest_not_found`.
489
489
* **Stale-doc removal (v3.5)**: a run that ends in a VEX error removes a recognizably-OpenVEX file (JSON whose `@context` names openvex.dev) already sitting at the output path — a pipeline reusing one path can never ship yesterday's attestation for a now-unpatched tree. Unrelated files at the path are never touched; a mid-write partial that no longer parses as JSON is left for downstream parsers to reject loudly.
490
-
* **Additive warnings (v3.5)**: `product_not_iri` (the `--product`/`--vex-product` override is neither a `pkg:` purl nor an absolute IRI; honored verbatim, warned) and `vendored_tree_out_of_sync` (a healthy vendored attestation stands on the committed artifact + lock wiring while the PRESENT installed tree hash-mismatches the patched bytes — run the package manager's install (for a project with Hatch environments the detail also names `hatch env remove <env>`, since Hatch keeps an installed release); the attestation itself is unchanged). Both ride stderr in human mode and `warnings[]` in the standalone `vex --json` envelope. Same channel for `product_multiple_manifests` (auto-detect found several project manifests and names the one it used), `vex_stale_doc_removed` (the stale-doc removal above happened), the manifest-less plan's advisories — `vex_wiring_conflict` (the lockfiles wire a package to different patches: which files, which uuids, how to fix it), `vex_record_superseded` (a recorded patch replaced by the lockfile-wired one), `vex_claim_unwired` (a ledger claim whose patch the lockfiles still mention, but not as wiring), `vex_record_offline` / `vex_record_not_found` / `vex_record_fetch_failed` (why a lockfile-wired patch has no record — the detail behind a `record_unavailable` skip) and `api_auth_fallback` (the public proxy served free patches only: the authenticated API refused the credentials, `get` / `scan`'s warning text; or, v5.0, a token was set with no `--org` / `SOCKET_ORG_SLUG` / socket-cli `defaultOrg` and the org could not be resolved, so the whole run used the proxy — standalone `vex --json` carries it when it fetched records, and `scan --json` / `get --json` report this case in their top-level `warnings[]`) — and, standalone only, `org_looks_like_path` (`-o`/`--org` given a file-shaped value — `-O` is `--output`). The standalone error envelope carries `warnings[]` too. An embedded `--vex` that fails also folds each omitted patch into the host command's `warnings[]` as `vex_omitted` (`<purl>: <why> (<errorCode>)` — standalone `vex` lists them as `skipped` events), and `--silent` lists them as `omitted: <purl> (<errorCode>)` lines under the error. A corrupt `.socket/vendor/state.json` is no longer degraded with a warning: every form of vex fails with `vendor_ledger_corrupt` (see the error-code table). A malformed pre-v5 `redirect-state.json` is, as of v5.0, only the `redirect_ledger_corrupt` warning (hosted mode keeps no ledger; the file is an optional migration record source).
490
+
* **Additive warnings (v3.5)**: `product_not_iri` (the `--product`/`--vex-product` override is neither a `pkg:` purl nor an absolute IRI; honored verbatim, warned) and `vendored_tree_out_of_sync` (a healthy vendored attestation stands on the committed artifact + lock wiring while the PRESENT installed tree hash-mismatches the patched bytes — run the package manager's install (for a project with Hatch environments the detail also names `hatch env remove <env>`, since Hatch keeps an installed release; for a pypi package of a project whose governing pdm.lock was written by PDM < 2.11 it names `pdm sync --reinstall`, or removing the installed copy first on PDM 1.x); the attestation itself is unchanged). Both ride stderr in human mode and `warnings[]` in the standalone `vex --json` envelope. Same channel for `product_multiple_manifests` (auto-detect found several project manifests and names the one it used), `vex_stale_doc_removed` (the stale-doc removal above happened), the manifest-less plan's advisories — `vex_wiring_conflict` (the lockfiles wire a package to different patches: which files, which uuids, how to fix it), `vex_record_superseded` (a recorded patch replaced by the lockfile-wired one), `vex_claim_unwired` (a ledger claim whose patch the lockfiles still mention, but not as wiring), `vex_record_offline` / `vex_record_not_found` / `vex_record_fetch_failed` (why a lockfile-wired patch has no record — the detail behind a `record_unavailable` skip) and `api_auth_fallback` (the public proxy served free patches only: the authenticated API refused the credentials, `get` / `scan`'s warning text; or, v5.0, a token was set with no `--org` / `SOCKET_ORG_SLUG` / socket-cli `defaultOrg` and the org could not be resolved, so the whole run used the proxy — standalone `vex --json` carries it when it fetched records, and `scan --json` / `get --json` report this case in their top-level `warnings[]`) — and, standalone only, `org_looks_like_path` (`-o`/`--org` given a file-shaped value — `-O` is `--output`). The standalone error envelope carries `warnings[]` too. An embedded `--vex` that fails also folds each omitted patch into the host command's `warnings[]` as `vex_omitted` (`<purl>: <why> (<errorCode>)` — standalone `vex` lists them as `skipped` events), and `--silent` lists them as `omitted: <purl> (<errorCode>)` lines under the error. A corrupt `.socket/vendor/state.json` is no longer degraded with a warning: every form of vex fails with `vendor_ledger_corrupt` (see the error-code table). A malformed pre-v5 `redirect-state.json` is, as of v5.0, only the `redirect_ledger_corrupt` warning (hosted mode keeps no ledger; the file is an optional migration record source).
491
491
492
492
### VEX provenance markers (contract)
493
493
@@ -1649,6 +1649,7 @@ command's integration tests check its output.
1649
1649
| `pypi_poetry_changed` / `pypi_pdm_changed` / `pypi_pipenv_changed` / `pypi_uv_changed` | `failed` | vendor (pypi, v5.0): the lock / project file changed between the read that planned the edit and the first write — refused before any write (worded like `pypi_lock_changed`: "<file> changed during vendoring; re-run"). |
1650
1650
| `pypi_pipenv_stale_install` | `skipped` (warning) | vendor (pipenv): the vendored twin of `redirect_pypi_stale_install` — the project's venv still holds the upstream release Pipenv will not reinstall over; the detail names the `pipenv run pip uninstall -y <pkg> && pipenv sync` remedy, with the same lock-category `sync` arguments as the hosted warning. |
1651
1651
| `pypi_hatch_stale_install` | `skipped` (warning) | vendor (hatch): an existing Hatch environment of the project (found under Hatch's data dir, `dirs.env.virtual` or an explicit env `path`) still holds the upstream release; Hatch keeps it on the next `hatch run`, so the detail names the env and the `hatch env remove <env>` / `hatch env prune` remedy. |
1652
+
| `pypi_pdm_stale_install` | `skipped` (warning) | vendor (pdm): the project's PDM env (its venv, or PEP 582 `__pypackages__`) still holds the upstream release, and pdm.lock was written by PDM < 2.11 (lock_version `2` / `4.3` / `4.4`), which keeps a same-version install on `pdm sync` / `pdm install`; the detail names `pdm sync --reinstall`, or for PDM 1.x (lock_version `2`, no `--reinstall`) removing the installed copy before `pdm sync`. Emitted on a fresh vendor and on an in-sync re-run while the env stays stale. |
1652
1653
| `pypi_pipenv_installer_unknown` | `skipped` (warning) | vendor (pipenv): no `pipenv` answered on PATH; the vendored references assume Pipenv 2018 or later (7–11 cannot consume them — use hosted mode there); `SOCKET_PIPENV_MAJOR` pins the release. |
1653
1654
| `vendor_lock_entry_relocked` | revert `warnings[]` | vendor `--revert` / rollback (pipenv): a relock regenerated the wired entry to a registry reference, or removed it; the record is retired (artifact removed, ledger entry dropped) instead of drift-kept. |
1654
1655
| `vendor_lock_entry_pruned_kept` | revert `warnings[]` | vendor `--revert` / rollback (yarn berry, #737): vendoring dropped a lock entry only the patched package's implicit `node-gyp` dependency reached (or one descriptor of a shared entry), and the lock has re-added or changed that entry since; it is left as it is (not drift: the artifact is still removed). Run `yarn install` if the lock is incomplete. |
0 commit comments