Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
7115db4
Stop writing the hosted redirect ledger from scan
mikolalysenko Sep 27, 2026
f0e3921
Restore hosted pins to their upstream registry entries instead of rep…
claude Sep 27, 2026
03643e0
Update rollback prompt unit test for the upstream-restore wording
claude Sep 27, 2026
61d7191
Derive list, scan updates and takeover state from lockfile hosted pins
claude Sep 27, 2026
a01ae92
Drop the hosted ledger from get, repair, the in-memory engine and the…
claude Sep 27, 2026
bd0f6d2
vendor ejects a hosted project; vendoring over any hosted pin restore…
claude Sep 27, 2026
65d25c7
Rewrite scan/mod.rs takeover unit tests for lockfile-derived hosted s…
claude Sep 27, 2026
e1bb9a6
Restore hosted gem and composer pins to their upstream entries
claude Sep 27, 2026
37e96e2
Fix clippy findings in the eject and takeover paths
claude Sep 27, 2026
1257869
Restore hosted PyPI pins to their upstream registry entries
claude Sep 27, 2026
1a2ff9f
Restore vlt, Maven and NuGet hosted pins to their upstream entries
claude Sep 27, 2026
c0d0797
Drop dead fixture fields clippy flags in covgap_commands_rollback
claude Sep 27, 2026
5eadb00
Retire a pre-v5 hosted ledger when rollback finds nothing else; updat…
claude Sep 27, 2026
2b331c1
Feed the hosted scan's in-run VEX this run's records
claude Sep 27, 2026
e62ce75
Refresh doc comments that still described the hosted ledger
claude Sep 28, 2026
faa15c7
vendor --revert restores hosted pins a pre-v5 vendor ledger re-creates
claude Sep 28, 2026
cebe197
Refuse around contested hosted wiring; refuse offline eject before an…
claude Sep 28, 2026
002d8ac
Make eject one transaction: plan, restore upstream, vendor, or roll back
claude Sep 28, 2026
33852ba
Rewrite hosted rollback/remove coverage-gap tests to the v5 upstream …
claude Sep 28, 2026
abbf31c
Rewrite hosted rollback/remove/vex-step tests to the ledger-free v5 c…
claude Sep 28, 2026
4a0de07
Rewrite hosted scan/get integration tests for the ledger-free v5 cont…
claude Sep 28, 2026
a2175d8
Tidy hosted remove/rollback messages and legacy-ledger residue
claude Sep 28, 2026
5fff6b5
Rewrite list and vex ledger tests for lockfile-derived hosted state
claude Sep 28, 2026
9dce1a9
Rewrite manifest-less VEX suites for the ledger-free hosted mode
claude Sep 28, 2026
ba5f91a
Teach the real-uv VEX matrix the ledger-free hosted mode
claude Sep 28, 2026
3d07d59
Run the real-uv hosted revert against the v5 rollback contract
claude Sep 28, 2026
9b0f61b
Delete the hosted ledger replay engine; keep a read-only legacy loader
claude Sep 28, 2026
7d5918c
Document the ledger-free hosted contract and hosted eject
claude Sep 28, 2026
9e2474b
Rewrite vendor takeover covgap tests to lockfile hosted pins; add WS2…
claude Sep 28, 2026
8480078
Rewrite in_process_vendor hosted takeovers to the v5 upstream restore
claude Sep 28, 2026
6b996ad
mode_migration_npm: hosted takeovers restore the upstream registry entry
claude Sep 28, 2026
e13c284
mode_migration_cargo: hosted takeovers restore the crates.io entry
claude Sep 28, 2026
b798ca7
mode_migration_bun: no hosted ledger; unwinds restore the upstream 4-…
claude Sep 28, 2026
818ff6b
in_process_vendor_bun_takeover: hosted pins without a ledger
claude Sep 28, 2026
430d466
e2e_bun_lockb: binary hosted pins are refused by rollback and vendor …
claude Sep 28, 2026
9c0d31f
e2e_redirect_bun_build: no hosted ledger; rollback restores the upstr…
claude Sep 28, 2026
a53b2e9
e2e_redirect_yarn_classic_build: hosted run writes only yarn.lock
claude Sep 28, 2026
d690792
e2e_redirect_gem_stale_install: no ledger fallback in hosted mode
claude Sep 28, 2026
26e7924
e2e_redirect_pnpm_build: no hosted ledger; rollback restores the reso…
claude Sep 28, 2026
41fc92d
e2e_redirect_cargo_shapes: remove restores crates.io entries without …
claude Sep 28, 2026
823ce8a
e2e_redirect_cargo_build: the three-file rewrite is the whole hosted …
claude Sep 28, 2026
8a02879
golang hosted e2e: go.mod/go.sum is the whole hosted state
claude Sep 28, 2026
4271ba6
Format the rewritten vendor/hosted test files
claude Sep 28, 2026
6872162
Pin that a transactional eject emits no per-purl takeover warning
claude Sep 28, 2026
d93b400
Document the transactional eject, offline refusal and contested wiring
claude Sep 28, 2026
c7e7189
Drop a stale comment on the hosted unwind error
claude Sep 28, 2026
4f2ef29
Prove eject from a fresh hosted checkout; verify hash-pinned requirem…
claude Sep 28, 2026
9bd9569
Give the stale-Pipfile rollback test a derivable hash mode
claude Sep 28, 2026
78e4c1e
node addon smoke: a wet hosted session writes no ledger
claude Sep 28, 2026
f1cc47b
covgap scan_hosted: unreadable-workspace case asserts no ledger
claude Sep 28, 2026
44240a2
Rewrite the CI-only e2e suites and backtests to the ledger-free hoste…
claude Sep 28, 2026
f2aade0
Hold the vlt configured-registry slot [3] rule pending real-vlt evidence
claude Sep 28, 2026
b6954d4
Backtests: send a User-Agent on public patch-view fetches
claude Sep 28, 2026
7f73cfe
Re-land the vlt configured-registry slot [3] rule on real-vlt evidence
claude Sep 28, 2026
dc634b3
hosted-e2e uv leg: serve the record of the uuid the lock pins
claude Sep 28, 2026
ef79e51
PDM static_urls restore writes files in URL order; bun backtest User-…
claude Sep 28, 2026
89578ce
covgap rollback: macOS-only blob-pin check derives hashes from the fi…
claude Sep 28, 2026
59a0834
Round-trip hosted rollback of unpopulated Poetry 1.0/1.1 locks
claude Sep 28, 2026
6da01c0
yarn berry e2e: manifest-less VEX matrix expects no hosted ledger
claude Sep 28, 2026
e36ba5b
e2e vex poetry: accept the one-file-per-line metadata.files pin
claude Sep 28, 2026
08c30b7
Keep Pipenv's index on hosted entries so rollback restores it exactly
claude Sep 28, 2026
65aa074
Restore hosted bun.lockb pins natively for the vendor takeover
claude Sep 28, 2026
698bef6
bun backtest: inject the custom-registry slot with byte I/O
claude Sep 28, 2026
8ce40d9
Demote hosted format-1 bun.lockb locks exactly on the vendor takeover
claude Sep 28, 2026
ba7034f
ci: give the Windows test leg a 50-minute budget
claude Sep 28, 2026
fc9a52a
Check out the Poetry and Pipenv lock fixtures byte-exact on Windows
claude Sep 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ crates/socket-patch-core/tests/fixtures/redirect/** -text

crates/socket-patch-core/tests/fixtures/pdm-native/*.lock -text

# Poetry and Pipenv locks are real `poetry lock` / `pipenv lock` output: the
# upstream restore and VEX tests round-trip them byte for byte and derive
# their CRLF variants from the LF bytes themselves.
crates/socket-patch-core/tests/fixtures/poetry/** -text
crates/socket-patch-core/tests/fixtures/pipenv/** -text
crates/socket-patch-core/tests/fixtures/pipenv-shapes/** -text

# The captured pnpm 1-12 locks are byte-real: the hosted/vendored rewriters
# refuse CRLF by design (vendor_lockfile_crlf_unsupported), and the tests
# derive their CRLF variants from the LF bytes themselves.
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 35
# Windows runs the same suite ~1.6x slower than macOS: on the base
# branch it already took 34m40s of a flat 35m budget.
timeout-minutes: ${{ matrix.os == 'windows-latest' && 50 || 35 }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand Down
246 changes: 209 additions & 37 deletions CHANGELOG.md

Large diffs are not rendered by default.

218 changes: 134 additions & 84 deletions README.md

Large diffs are not rendered by default.

273 changes: 149 additions & 124 deletions crates/socket-patch-cli/CLI_CONTRACT.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion crates/socket-patch-cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ impl GlobalArgs {
}

/// The project root whose `.socket/` state stores — manifest, vendor
/// ledger, redirect ledger — belong together: the RESOLVED manifest's
/// ledger — belong together: the RESOLVED manifest's
/// directory, stepping out of a standard `.socket/` layout when the
/// manifest lives in one. For the default `<cwd>/.socket/manifest.json`
/// this is exactly `cwd`; for a `--manifest-path` into another project
Expand Down
41 changes: 29 additions & 12 deletions crates/socket-patch-cli/src/commands/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,8 +541,8 @@ pub struct GetArgs {
/// [default: hosted; agent with `--save-only` or `--global`]
// agent = record in .socket/manifest.json + blobs and apply in place;
// hosted = rewrite lockfiles so the patched deps resolve to Socket's
// hosted patch server (no manifest, no blobs; state lives in the
// redirect ledger); vendored = commit patched artifacts under
// hosted patch server (no manifest, no blobs, no ledger: the lockfile
// is the record); vendored = commit patched artifacts under
// .socket/vendor/ and rewire the lockfile (no manifest, no blobs; the
// vendor ledger carries the records). Hosted/vendored runs produce the
// same on-disk result as `scan --mode hosted|vendored` selecting the
Expand Down Expand Up @@ -1222,6 +1222,9 @@ pub struct DownloadParams {
/// `false`: their patch content is staged in memory and the committed
/// artifact is the patch — nothing should land in `.socket/blobs`.
pub persist_blobs: bool,
/// `--patch-server-url`: the extra origin whose URLs count as hosted
/// when lockfile discovery reads the project's hosted pins.
pub patch_server_url: Option<String>,
}

impl DownloadParams {
Expand Down Expand Up @@ -1851,10 +1854,9 @@ type LockRefusals = HashMap<String, (&'static str, String)>;
/// classic / yarn berry gates and cargo's locked-version gate), over the
/// patches the phase would otherwise fetch a view for — past the Bun
/// refusal and the ledger's idempotency skip, which take precedence in the
/// fetch loop. A purl the hosted redirect ledger claims is left to the
/// vendor loop: its takeover reverts the hosted lock edits first, and the
/// revert rewrites the very text the gates read. A redirect ledger that
/// cannot be read leaves every purl to the loop.
/// fetch loop. A purl the lockfiles pin hosted is left to the vendor loop:
/// its takeover restores the upstream lock entry first, and the restore
/// rewrites the very text the gates read.
///
/// Only a package the vendor loop would hand to its backend is refused
/// here (see [`crate::commands::vendor::lock_refusals_reaching_backend`]):
Expand All @@ -1872,11 +1874,23 @@ async fn lock_text_refusals_for(
) -> LockRefusals {
let cwd = params.cwd.as_path();
let claimed: Vec<String> =
match socket_patch_core::patch::redirect::load_redirect_state(cwd).await {
Ok(Some(state)) => state.records.keys().map(|k| canonical_purl(k)).collect(),
Ok(None) => Vec::new(),
Err(_) => return HashMap::new(),
};
socket_patch_core::patch::redirect::upstream::HostedPin::all(
&socket_patch_core::vex::discover_patched_refs_with(
cwd,
&socket_patch_core::vex::DiscoverOptions {
patch_server_origins: params
.patch_server_url
.iter()
.filter(|url| !url.trim().is_empty())
.cloned()
.collect(),
},
)
.await,
)
.into_iter()
.map(|pin| canonical_purl(&pin.purl))
.collect();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vendored refusals miss contested pins

Medium Severity

lock_text_refusals_for and hosted_state_from_lockfiles still build hosted claims from HostedPin::all, which only sees VEX-eligible refs. Contested hosted wiring is omitted, so those packages are lock-text-gated or classified as not hosted instead of taking the restore/takeover path.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by learned rule: Inventory/discovery must propagate unsupported-layout diagnoses as typed errors, never swallow into None

Reviewed by Cursor Bugbot for commit fc9a52a. Configure here.

let candidates: Vec<(&str, &str)> = selected
.iter()
.filter(|sr| bun_refusal.filter(|r| r.applies_to(&sr.purl)).is_none())
Expand Down Expand Up @@ -3663,12 +3677,13 @@ fn get_download_params(args: &GetArgs, save_only: bool, persist_blobs: bool) ->
strict: args.common.strict,
ecosystems: args.common.ecosystems.clone(),
persist_blobs,
patch_server_url: args.common.patch_server_url.clone(),
}
}

/// `get … --mode hosted`: hand the selected (purl, uuid) pairs to scan's
/// hosted engine ([`super::scan::boxed_run_redirect_selected`]) — lockfile
/// rewrite + redirect ledger, no manifest, no blobs — so the on-disk result
/// rewrite only, no manifest, no blobs, no ledger — so the on-disk result
/// matches `scan --mode hosted` selecting the same patches. The engine owns
/// all output (and honors `--dry-run` internally); in JSON mode it nests its
/// `redirect` block into the get base envelope passed as `scan_result`.
Expand Down Expand Up @@ -5223,6 +5238,7 @@ mod tests {
strict: false,
ecosystems: None,
persist_blobs: false,
patch_server_url: None,
}
}

Expand Down Expand Up @@ -5891,6 +5907,7 @@ mod tests {
ecosystems: None,
// The vendor-detached posture this fn exists for.
persist_blobs: false,
patch_server_url: None,
}
}

Expand Down
Loading
Loading