Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 25 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,9 @@ into the new version's section — see docs/releasing.md.
silently shadows any repository). Both are proven by docker capstones
against the real .NET SDK / Apache Maven (cold-cache, `--network none`,
RED + TAMPER probes). `nuget` and `maven` are now DEFAULT compile features;
in-place agent apply for both remains runtime-gated
(`SOCKET_EXPERIMENTAL_NUGET=1` / `SOCKET_EXPERIMENTAL_MAVEN=1` — sidecar
corruption risk) while the committable vendor path is safe. The vendored
the `SOCKET_EXPERIMENTAL_NUGET` / `SOCKET_EXPERIMENTAL_MAVEN` runtime
opt-ins that briefly gated in-place agent apply were retired later in this
cycle (see the "promoted to fully available" entry under Changed). The vendored
path convention + uuid recovery rule now covers `nuget` and `maven` dirs,
and `--vendor-source` prebuilt downloads cover nuget.
- **Maven hosted rewriter (pom projects) — fail-closed version suffixing +
Expand Down Expand Up @@ -337,6 +337,24 @@ into the new version's section — see docs/releasing.md.

### Changed

- **Maven and NuGet promoted to fully available — the
`SOCKET_EXPERIMENTAL_MAVEN` / `SOCKET_EXPERIMENTAL_NUGET` runtime gates
are retired.** Every flow (`scan` in all modes, `apply`, `get`,
`rollback`, `vendor`, `repair`, `vex`, `setup`) now discovers and
patches installed Maven and NuGet packages unconditionally; the
"N patch(es) skipped — support is experimental" warnings are gone, and
the previously `#[ignore]`d maven/nuget dispatch e2e tests now gate CI.
Setting the old env vars is harmless but does nothing. Behavior notes:
a default `scan` now walks the local Maven repository (`~/.m2` /
`MAVEN_REPO_LOCAL`) and the NuGet caches, and `scan --prune`/`--sync`
now judges maven/nuget manifest entries like any other ecosystem's
(previously they were exempt from pruning while the gate was closed).
The in-place sidecar caveat is unchanged and now documented per mode in
`docs/ecosystems.md`: agent-mode patching leaves Maven's
`.jar.sha1`/`.jar.md5` stale and NuGet's fixup deletes
`.nupkg.metadata` + advises on `.nupkg.sha512`; the vendored/hosted
modes never touch the caches.

- **Release workflow consolidated into a single `release.yml`.** One
dispatch now publishes every ecosystem package — crates.io, npm, PyPI,
RubyGems (both gems, via OIDC trusted publishing), Packagist, Maven
Expand All @@ -361,9 +379,10 @@ into the new version's section — see docs/releasing.md.
Maven, Composer, and Deno support is now unconditional. Builds that passed
`--features <eco>` will get an "unknown feature" error and should simply
drop the flag; `--no-default-features` no longer produces a minimal binary
(there is nothing left to strip). The runtime gates are unchanged:
Maven/NuGet crawling and apply still require `SOCKET_EXPERIMENTAL_MAVEN=1` /
`SOCKET_EXPERIMENTAL_NUGET=1`. The only remaining features are the
(there is nothing left to strip). The `SOCKET_EXPERIMENTAL_MAVEN` /
`SOCKET_EXPERIMENTAL_NUGET` runtime gates outlived this entry only briefly —
they are retired in the same release (see the "promoted to fully available"
entry under Changed). The only remaining features are the
test-suite gates `docker-e2e` and `setup-e2e` on `socket-patch-cli`. (MAJOR
for anyone scripting `--features`; no behavior change for default builds
beyond composer/deno support now being present.)
Expand Down
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,7 @@ the edit.

> If it prints `No patches available for installed packages.`, none of your installed
> dependency versions currently has a Socket patch — the good outcome, with nothing to
> apply. (One exception: Maven and NuGet installed-package discovery is experimental and
> off by default — `scan` silently skips them unless `SOCKET_EXPERIMENTAL_MAVEN=1` /
> `SOCKET_EXPERIMENTAL_NUGET=1` is set; see the
> [mode × ecosystem matrix](docs/ecosystems.md#mode--ecosystem-matrix).)
> apply.
> To walk the rest of the loop anyway, make a scratch project pinned to a version
> that has a free patch — at the time of writing, `flatted@3.3.1`:
>
Expand Down Expand Up @@ -727,10 +724,12 @@ What gets wired, per ecosystem:
`"setup": { "manual": ["deno"] }`) so [`vex`](#vex) still attests the hand-applied
patches — this matters most for Deno, which has no vendored or hosted alternative.
For Maven
and NuGet, discovery of installed packages is experimental and off by default (opt in
with `SOCKET_EXPERIMENTAL_MAVEN=1` / `SOCKET_EXPERIMENTAL_NUGET=1`), and in-place
patching corrupts their cache checksum sidecars — prefer `--mode vendored` or
`--mode hosted`; see [ecosystems.md](docs/ecosystems.md#maven--nuget-caveats).
and NuGet, note that in-place patching leaves the caches' own checksum sidecars stale
(NuGet's fixup deletes `.nupkg.metadata` and raises an advisory for the signed-package
`.nupkg.sha512` marker; Maven's `.jar.sha1`/`.jar.md5` are left as-is) — the copy-out
modes, `scan --mode vendored` and `scan --mode hosted`, never touch the caches and
avoid the issue entirely. See
[ecosystems.md](docs/ecosystems.md#maven--nuget-caveats).

**Usage:**
```bash
Expand Down
2 changes: 0 additions & 2 deletions crates/socket-patch-cli/CLI_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -746,8 +746,6 @@ These exist for staged rollouts and the launcher wrappers. They are **internal**

| Env var | Purpose |
|---|---|
| `SOCKET_EXPERIMENTAL_MAVEN` | Opt-in gate (`=1`) for the maven installed-package crawl behind `scan`/`apply`/`vendor` — agent-mode in-place jar patching corrupts the `~/.m2` checksum sidecars, so discovery stays off by default (`src/ecosystem_dispatch.rs`). |
| `SOCKET_EXPERIMENTAL_NUGET` | Same gate for nuget — in-place patching breaks the `.nupkg.sha512` tamper-evidence sidecar. |
| `SOCKET_PATCH_BIN` | Points the CLI launcher wrappers (RubyGems / Composer / Maven / NuGet) and the gem Bundler plugin at an existing `socket-patch` binary (skips the download-on-first-run); also the escape hatch `apply` names when a golang-featureless binary is asked to audit Go redirects. |
| `SOCKET_UPDATE_BASE_URL` | Points BOTH the release-metadata and asset-download routes of `--update`/the update notice at one base (mirror or test fixture) instead of `github.com` + `api.github.com`. Overriding it relaxes the downloaded binary's version self-check from hard-fail to warning. |
| `SOCKET_UPDATE_STATE_DIR` | Overrides the per-user dir holding `update-check.json` + `update.lock` (tests point it into a tempdir). |
Expand Down
6 changes: 3 additions & 3 deletions crates/socket-patch-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ libc = { workspace = true }

[features]
# Every ecosystem (npm, PyPI, Ruby gems, Go, Cargo, NuGet, Maven, Composer,
# Deno) is unconditionally compiled in — there are no ecosystem feature gates.
# Maven `apply` stays runtime-gated behind `SOCKET_EXPERIMENTAL_MAVEN=1`
# (in-place jar patching corrupts sidecars); committable `vendor` is safe.
# Deno) is unconditionally compiled in AND enabled at runtime — there are no
# ecosystem feature gates and no runtime env gates (the old
# SOCKET_EXPERIMENTAL_MAVEN/NUGET opt-ins are retired).
# The only features left gate opt-in test suites:
#
# Enables the Docker-driven real-package e2e test suite under
Expand Down
53 changes: 20 additions & 33 deletions crates/socket-patch-cli/src/commands/scan/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,13 @@ pub(super) fn print_gc_vendored_line(gc: &GcSummary) {
/// `--sync` would GC the very patch it just downloaded.
///
/// Entries the crawl never even looked for are exempt too
/// (`crawl_covers_purl`): the runtime-gated maven/nuget crawlers with their
/// gate off, and any `pkg:<type>/` this build has no crawler for. The
/// manifest is a committed, shared file, so a newer CLI's ecosystem can
/// legitimately appear in it — "absent from the crawl" then says nothing
/// about whether the package is installed, and pruning would silently
/// delete a teammate's patch (plus its blobs). Same fail-safe reasoning as
/// capturing `scanned_purls` before the `--ecosystems` filter.
/// (`crawl_covers_purl`): any `pkg:<type>/` this build has no crawler
/// for. The manifest is a committed, shared file, so a newer CLI's
/// ecosystem can legitimately appear in it — "absent from the crawl"
/// then says nothing about whether the package is installed, and pruning
/// would silently delete a teammate's patch (plus its blobs). Same
/// fail-safe reasoning as capturing `scanned_purls` before the
/// `--ecosystems` filter.
fn detect_prunable(
manifest: &PatchManifest,
scanned_purls: &HashSet<String>,
Expand Down Expand Up @@ -455,40 +455,27 @@ mod tests {
}

#[test]
fn detect_prunable_keeps_runtime_gated_ecosystem_entries() {
// Maven/NuGet crawlers only run under their experimental opt-in
// env gates, so with the gate OFF their packages are invisible to
// the crawl — "absent" must not mean "uninstalled". (An ambient
// opt-in makes them genuinely crawled, which is a different
// scenario; skip rather than mutate the shared process env.)
fn detect_prunable_judges_maven_and_nuget_like_any_ecosystem() {
// Maven/NuGet are first-class ecosystems: every scan crawls them,
// so their manifest entries ARE judged — absent from the scan
// means genuinely uninstalled, and they prune like any other
// ecosystem. (They used to be exempt behind the retired
// `SOCKET_EXPERIMENTAL_*` runtime gates.)
let m = manifest_with(&[
("pkg:maven/com.example/lib@1.0.0", "uuid-a"),
("pkg:nuget/Some.Package@1.0.0", "uuid-b"),
("pkg:npm/gone@1.0.0", "uuid-c"),
]);
// Mirror `ecosystem_dispatch::env_truthy` exactly — the gate opens
// only on `1`/`true` (any case), so a merely-PRESENT but falsy
// `SOCKET_EXPERIMENTAL_MAVEN=0` leaves the ecosystem uncrawled and
// therefore exempt. Testing presence instead of truthiness made this
// expectation disagree with the code under test and fail spuriously.
let gate_open = |name: &str| {
std::env::var(name)
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
.unwrap_or(false)
};
let mut expected = vec!["pkg:npm/gone@1.0.0".to_string()];
if gate_open("SOCKET_EXPERIMENTAL_MAVEN") {
expected.push("pkg:maven/com.example/lib@1.0.0".to_string());
}
if gate_open("SOCKET_EXPERIMENTAL_NUGET") {
expected.push("pkg:nuget/Some.Package@1.0.0".to_string());
}
expected.sort();
let mut out = detect_prunable(&m, &scanned(&[]), &no_vendored());
out.sort();
assert_eq!(
out, expected,
"a runtime-gated ecosystem that was never crawled must not prune"
out,
vec![
"pkg:maven/com.example/lib@1.0.0".to_string(),
"pkg:npm/gone@1.0.0".to_string(),
"pkg:nuget/Some.Package@1.0.0".to_string(),
],
"maven/nuget orphans must prune like any other ecosystem's"
);
}

Expand Down
Loading
Loading