Skip to content

Keep composer unit tests off the host's env - #2064

Merged
Mikola Lysenko (mikolalysenko) merged 2 commits into
mainfrom
ci-janitor/composer-env-scrub
Nov 13, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 2 commits into
mainfrom
ci-janitor/composer-env-scrub

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Composer's vendor-dir lookups read the developer's environment in unit tests. On main (de81f1b), cargo test -p socket-patch-core --lib passes clean (7,720 tests) but fails 10 crawlers::composer_crawler tests when COMPOSER_VENDOR_DIR is set. A vendor-dir in the developer's own ~/.composer/config.json (or under COMPOSER_HOME/APPDATA) has the same effect, because the user-level config is found through HOME.

CI impact today: none. No workflow sets these, and CI has been green: zero failed or re-run merge_group runs, and zero merge-queue evictions in the last 24h. With nothing merge-blocking or flaky to fix, this run took the next item in the hermetic-test series (#2054–#2057, all merged), from the hostile-env probe on #1919. That probe didn't cover the Composer variables.

Root cause

resolve_local_vendor_dir_sync, local_install_unread and global_vendor_dir_sync pass |name| std::env::var_os(name) into resolve_vendor_dir. That function honours COMPOSER_VENDOR_DIR first, then the user config through local_composer_home.

Fix

These three lookups now go through one process_var. In production and integration-test builds it is std::env::var_os, so nothing changes. In unit-test builds it is test_env::guarded_var_os (added here; guarded_var is now built on it), so a test sees only the vars it holds with an EnvGuard. That's the same pattern #2057 used for go_env. The injected-closure tests that already cover resolve_vendor_dir's cascade are unaffected.

Proof

  • COMPOSER_VENDOR_DIR=elsewhere on the core lib tests: 10 failed → 0 (7,721 passed).
  • Clean run: 7,721 passed (the 7,720 existing plus 1 new).
  • New #[serial] regression test vendor_dir_lookups_ignore_the_hosts_composer_env: it sets COMPOSER_VENDOR_DIR raw, the way a host would, and asserts the fixture still resolves <project>/vendor. A drop guard restores the previous value even if an assertion fails. It also asserts that a value held with EnvGuard is honoured. With process_var reverted to std::env::var_os, the test fails with host env hidden.
  • cargo clippy --locked -p socket-patch-core --all-features -- -D warnings (the CI invocation) is clean. The file is rustfmt'd.

No tests removed or moved.

/code-review high

I ran it on the first commit and fixed 3 findings in eda0096:

  • The test no longer sets HOME, which non-serial tests running alongside could read.
  • The test restores the env on drop instead of by hand.
  • New test_env::guarded_var_os keeps non-UTF-8 values, matching production's var_os.

3 findings were not fixed:

Also found (for #1919, not in this PR)

On the same probe, YARN_NODE_LINKER=pnp still fails 7 tests (npm_crawler 1, shared_store 2, npm_flavor 2, yarn_berry_lock 2), and a HOME with nodeLinker: pnp in .yarnrc.yml fails npm_flavor::vendorable_probe_refuses_berry_configured_for_pnp. These are the same modules as the YARN_RC_FILENAME follow-ups already listed there.

https://claude.ai/code/session_011f9aeSSzeJ3EZNDhV5v3Vj


Generated by Claude Code

resolve_local_vendor_dir_sync, local_install_unread and the global
vendor-dir lookup read COMPOSER_VENDOR_DIR, and COMPOSER_HOME / HOME /
APPDATA for the user-level config.json, straight from the process.
Unit tests reach them through the crawler, so a developer's
COMPOSER_VENDOR_DIR (or a vendor-dir in ~/.composer/config.json) moves
every fixture's vendor tree: on main `cargo test -p socket-patch-core
--lib` fails 10 composer_crawler tests with COMPOSER_VENDOR_DIR set.

In unit-test builds these lookups now read only the vars a test holds
with an EnvGuard (test_env::guarded_var), the pattern #2057 used for
go_env. Production and integration-test builds read the process env
exactly as before. A serial regression test sets the host vars raw and
checks they're hidden, and that a held value is still honoured.

Refs #1919.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011f9aeSSzeJ3EZNDhV5v3Vj
@mikolalysenko Mikola Lysenko (mikolalysenko) added the ci-janitor Opened by the CI janitor routine (flakes, redundant tests, CI perf) label Nov 13, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@cursor

cursor Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

PR Summary

Low Risk
Test-only env indirection with unchanged production behaviour; low risk aside from ensuring all vendor-dir code paths use process_var.

Overview
Composer vendor-dir resolution (global_vendor_dir_sync, resolve_local_vendor_dir_sync, local_install_unread) no longer reads the process environment directly in unit tests. Those paths now share a process_var helper: production still uses std::env::var_os, while #[cfg(test)] uses test_env::guarded_var_os so only vars held with EnvGuard are visible—preventing a developer's COMPOSER_VENDOR_DIR or HOME-based Composer config from breaking fixtures.

test_env gains guarded_var_os (OsString, for var_os callers); guarded_var is implemented on top of it.

A new #[serial] regression test confirms host-set COMPOSER_VENDOR_DIR is ignored and EnvGuard-set values are honoured.

Reviewed by Cursor Bugbot for commit eda0096. Configure here.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

From /code-review high on the PR:

- The regression test set HOME raw, which non-serial tests running
  alongside could read. It now sets only COMPOSER_VENDOR_DIR, which
  nothing outside the lookups under test reads, and a drop guard puts
  the previous value back even if an assertion fails.
- test_env::guarded_var dropped non-UTF-8 values, while production
  reads var_os. New guarded_var_os keeps the bytes, and composer's
  process_var uses it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011f9aeSSzeJ3EZNDhV5v3Vj
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit eda0096. Configure here.

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Nov 13, 2026
@mikolalysenko

Mikola Lysenko (mikolalysenko) commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator Author

Ready for review (burn-down agent).

  • Head: eda0096
  • CI: 50/50 checks settled green (31 success, 19 skipped); no main-wide failures.
  • Bugbot: reviewed eda0096, no new issues (earlier review on 2936b22 is stale and had no open threads).
  • Test-only change: composer vendor-dir lookups go through a process_var seam that reads only EnvGuard-held vars under cfg(test); production still uses std::env::var_os. Worth a look: that every vendor-dir path now uses process_var.

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief

What it does. Test-only change. Composer's three vendor-dir lookups (resolve_local_vendor_dir_sync, local_install_unread, global_vendor_dir_sync) now read env through one process_var. In production and integration builds that is still std::env::var_os. In unit-test builds it only sees vars a test holds with EnvGuard, so a developer's COMPOSER_VENDOR_DIR or HOME-located Composer config no longer breaks 10 composer_crawler tests. It's the same pattern #2057 used for go_env.

Risk: low. The production path is unchanged (#[cfg(not(test))] → std::env::var_os), and the diff is 2 files, +73/−4.

Look here

  • [composer_crawler.rs:779-795](https://github.com/SocketDev/socket-patch/blob/eda00964430952bd5321b55a829529d18442ac6f/crates/socket-patch-core/src/crawlers/composer_crawler.rs#L779-L795): the cfg(test) / cfg(not(test)) pair for process_var
  • [composer_crawler.rs:818-840](https://github.com/SocketDev/socket-patch/blob/eda00964430952bd5321b55a829529d18442ac6f/crates/socket-patch-core/src/crawlers/composer_crawler.rs#L818-L840): the call sites switched over
  • test_env.rs:19-28: the new guarded_var_os, which keeps non-UTF-8 values like production's var_os
  • [composer_crawler.rs:2536-2579](https://github.com/SocketDev/socket-patch/blob/eda00964430952bd5321b55a829529d18442ac6f/crates/socket-patch-core/src/crawlers/composer_crawler.rs#L2536-L2579): the regression test (serial, restores the raw host var on drop)

Verified

  • Read the full diff and checked that CHANGELOG.md is untouched.
  • cargo test -p socket-patch-core --lib composer: 215 passed, both clean and with COMPOSER_VENDOR_DIR=elsewhere.
  • I reverted the test-build process_var to std::env::var_os, and the new test then fails with host env hidden, so it does exercise the fix.
  • The test_env tests pass.
  • cargo clippy --all-targets reports no warnings in the touched files. The lints it does report are all in untouched files and come from main.
  • CI: 50/50 settled green (31 success, 19 skipped), with ci-ok and clippy green. Bugbot is clean on eda0096.

Changes I made: none.

Open questions: none blocking.

Auto-merge is armed, so approving sends this straight to the merge queue.


Generated by Claude Code

Merged via the queue into main with commit 7c5240e Nov 13, 2026
50 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the ci-janitor/composer-env-scrub branch November 13, 2026 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-janitor Opened by the CI janitor routine (flakes, redundant tests, CI perf) Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants