@@ -1152,7 +1152,7 @@ pub async fn run(args: VendorArgs) -> i32 {
11521152
11531153 // A workspace member's ledger lives at the root: reverting the
11541154 // member's empty one would report success and unwire nothing (#1921).
1155- if args. revert {
1155+ if args. revert && matches ! ( manifest_exists ( & manifest_path ) . await , Ok ( false ) ) {
11561156 if let Some ( message) = member_refusal ( & args. common . cwd , "vendor --revert" ) . await {
11571157 return emit_eject_refusal ( & args. common , MEMBER_REFUSAL_CODE , & message) ;
11581158 }
@@ -1290,20 +1290,20 @@ async fn run_check(args: &VendorArgs) -> i32 {
12901290 if state. entries . is_empty ( ) && jvm_orphan. is_some ( ) {
12911291 return emit_eject_refusal ( & args. common , "vendor_ledger_missing" , JVM_ORPHAN_DETAIL ) ;
12921292 }
1293- // A workspace member verifies nothing of its own: the root's ledger
1294- // and artifacts are the ones the install uses, so a pass here would
1295- // hide a tampered root (#1921).
1296- if state. entries . is_empty ( ) && jvm_orphan. is_none ( ) {
1297- let manifest_path = args. common . resolved_manifest_path ( ) ;
1298- if !matches ! ( manifest_exists( & manifest_path) . await , Ok ( true ) ) {
1299- if let Some ( message) = member_refusal ( root, "vendor --check" ) . await {
1300- return emit_eject_refusal ( & args. common , MEMBER_REFUSAL_CODE , & message) ;
1301- }
1302- }
1303- }
13041293 let manifest_path = args. common . resolved_manifest_path ( ) ;
13051294 let manifest = match read_manifest ( & manifest_path) . await {
1306- Ok ( m) => m. unwrap_or_default ( ) ,
1295+ Ok ( Some ( m) ) => m,
1296+ // A workspace member verifies nothing of its own: the root's
1297+ // ledger and artifacts are the ones the install uses, so a pass
1298+ // here would hide a tampered root (#1921).
1299+ Ok ( None ) => {
1300+ if state. entries . is_empty ( ) && jvm_orphan. is_none ( ) {
1301+ if let Some ( message) = member_refusal ( root, "vendor --check" ) . await {
1302+ return emit_eject_refusal ( & args. common , MEMBER_REFUSAL_CODE , & message) ;
1303+ }
1304+ }
1305+ Default :: default ( )
1306+ }
13071307 Err ( e) => {
13081308 let err = crate :: json_envelope:: manifest_load_error ( & manifest_path, & e) ;
13091309 return emit_eject_refusal ( & args. common , & err. code , & err. message ) ;
@@ -1498,8 +1498,6 @@ fn artifacts_gitignore_checked(mut ecosystems: impl Iterator<Item = Ecosystem>)
14981498 } )
14991499}
15001500
1501- /// A refused eject: the JSON error envelope (`status: error`) or an
1502- /// `Error:` line (printed even under `--silent`). Exit 1; nothing touched.
15031501/// The refusal code of a vendor run from a workspace member: the same one
15041502/// vendored `scan` / `get` use for a member with no lock of its own.
15051503const MEMBER_REFUSAL_CODE : & str = "vendor_lockfile_missing" ;
@@ -1509,8 +1507,13 @@ const MEMBER_REFUSAL_CODE: &str = "vendor_lockfile_missing";
15091507/// Callers ask only when `dir` has no hosted pins and no manifest; this
15101508/// also requires an empty (or absent) vendor ledger, so the run would
15111509/// otherwise exit 0 having looked at nothing (#1921). An unreadable
1512- /// ledger is left to the caller's own refusal.
1510+ /// ledger is left to the caller's own refusal. Only an npm project (a
1511+ /// directory holding `package.json`) is a member: another ecosystem's
1512+ /// project nested under a pnpm workspace is its own project.
15131513async fn member_refusal ( dir : & Path , form : & str ) -> Option < String > {
1514+ if !dir. join ( "package.json" ) . is_file ( ) {
1515+ return None ;
1516+ }
15141517 if !load_state ( dir) . await . ok ( ) ?. entries . is_empty ( ) {
15151518 return None ;
15161519 }
@@ -1521,16 +1524,18 @@ async fn member_refusal(dir: &Path, form: &str) -> Option<String> {
15211524
15221525fn member_refusal_message ( dir : & Path , root : & Path , form : & str ) -> String {
15231526 format ! (
1524- "{} is a workspace member with no lockfile, manifest or vendor ledger of its \
1525- own: the workspace root {} installs it and holds its patches, which `{form}` \
1526- run here cannot see; run socket-patch from {} (the workspace root); nothing \
1527- was written",
1527+ "{} is a workspace member with no manifest or vendor ledger of its own: \
1528+ the workspace root {} installs it from its lock and holds its patches, which \
1529+ `{form}` run here cannot see; run socket-patch from {} (the workspace root); \
1530+ nothing was written",
15281531 dir. display( ) ,
15291532 root. display( ) ,
15301533 root. display( )
15311534 )
15321535}
15331536
1537+ /// A refused eject: the JSON error envelope (`status: error`) or an
1538+ /// `Error:` line (printed even under `--silent`). Exit 1; nothing touched.
15341539fn emit_eject_refusal ( common : & GlobalArgs , code : & str , message : & str ) -> i32 {
15351540 if common. json {
15361541 let mut env = Envelope :: new ( Command :: Vendor ) ;
0 commit comments