@@ -692,6 +692,16 @@ pub enum ArtifactHealth {
692692 UnknownFlavor { flavor : String } ,
693693}
694694
695+ impl ArtifactHealth {
696+ /// Only a Bun member-relative copy of the canonical tarball is off;
697+ /// `repair` rewrites it from the committed tarball.
698+ pub fn is_workspace_copy_issue ( & self ) -> bool {
699+ matches ! ( self , ArtifactHealth :: Corrupt { reason }
700+ if reason == "vendor_workspace_artifact_missing"
701+ || reason == "vendor_workspace_artifact_corrupt" )
702+ }
703+ }
704+
695705/// Health-check one vendored artifact against its patch record: the
696706/// per-file afterHash verification of [`verify_vendored_patch_record`]
697707/// (which for dir-shaped artifacts includes the whole-tree fileInventory
@@ -782,10 +792,15 @@ pub async fn describe_artifact_failure(
782792 let path = & entry. artifact . path ;
783793 Some ( match health {
784794 ArtifactHealth :: Healthy => return None ,
795+ // A JVM tree also counts as missing when only its marker is gone.
796+ ArtifactHealth :: Missing if super :: jvm:: apply:: is_jvm_entry ( entry) => format ! (
797+ "committed artifact {path} or its tree marker is missing (vendor_artifact_missing); \
798+ {REPAIR}"
799+ ) ,
785800 ArtifactHealth :: Missing => {
786801 format ! ( "committed artifact {path} is missing (vendor_artifact_missing); {REPAIR}" )
787802 }
788- ArtifactHealth :: Corrupt { reason } if reason . starts_with ( "vendor_workspace_artifact_" ) => {
803+ ArtifactHealth :: Corrupt { reason } if health . is_workspace_copy_issue ( ) => {
789804 let mirror = super :: bun_workspace:: failing_mirror ( project_root, entry)
790805 . await
791806 . unwrap_or_else ( || format ! ( "of {path}" ) ) ;
@@ -794,10 +809,14 @@ pub async fn describe_artifact_failure(
794809 } else {
795810 "has different bytes"
796811 } ;
797- format ! (
798- "Bun workspace copy {mirror} {cause} ({reason}); the committed artifact {path} \
799- it mirrors is intact; {REPAIR}"
800- )
812+ // The canonical tarball was checked against the ledger only
813+ // when the ledger records its sha256.
814+ let canonical = if entry. artifact . sha256 . is_empty ( ) {
815+ String :: new ( )
816+ } else {
817+ format ! ( "; the committed artifact {path} it mirrors is intact" )
818+ } ;
819+ format ! ( "Bun workspace copy {mirror} {cause} ({reason}){canonical}; {REPAIR}" )
801820 }
802821 ArtifactHealth :: Corrupt { reason } => {
803822 let cause = match reason. as_str ( ) {
@@ -811,12 +830,22 @@ pub async fn describe_artifact_failure(
811830 format ! ( "committed artifact {path} {cause} ({reason}); {REPAIR}" )
812831 }
813832 ArtifactHealth :: StaleUuid => format ! (
814- "committed artifact {path} is for a different patch than the vendor ledger records \
833+ "the vendor ledger and the patch manifest name different patches for {path} \
815834 (vendor_uuid_mismatch); a re-vendor is pending: run `socket-patch vendor`"
816835 ) ,
836+ ArtifactHealth :: Unverifiable { reason }
837+ if reason == "vendor_workspace_artifact_invalid" =>
838+ {
839+ format ! (
840+ "the Bun workspace copies of {path} cannot be checked because bun.lockb cannot be \
841+ read or names an unsafe path ({reason}); restore bun.lockb from version control \
842+ or re-run `socket-patch vendor`"
843+ )
844+ }
817845 ArtifactHealth :: Unverifiable { reason } => format ! (
818- "the vendor ledger entry for {path} cannot be verified ({reason}); fix \
819- .socket/vendor/state.json, for example by restoring it from version control"
846+ "committed artifact {path} cannot be verified ({reason}), so `socket-patch repair` \
847+ will not rebuild it; restore .socket/vendor/state.json and .socket/manifest.json \
848+ from version control, or re-run `socket-patch vendor`"
820849 ) ,
821850 ArtifactHealth :: UnknownFlavor { flavor } => format ! (
822851 "{path} was vendored for the npm flavor `{flavor}`, which this socket-patch release \
@@ -1104,19 +1133,19 @@ mod tests {
11041133 (
11051134 ArtifactHealth :: StaleUuid ,
11061135 format ! (
1107- "committed artifact {rel} is for a different patch than the vendor ledger \
1108- records (vendor_uuid_mismatch); a re-vendor is pending: run \
1109- `socket-patch vendor`"
1136+ "the vendor ledger and the patch manifest name different patches for {rel} \
1137+ (vendor_uuid_mismatch); a re-vendor is pending: run `socket-patch vendor`"
11101138 ) ,
11111139 ) ,
11121140 (
11131141 ArtifactHealth :: Unverifiable {
11141142 reason : "vendor_artifact_path_invalid" . into ( ) ,
11151143 } ,
11161144 format ! (
1117- "the vendor ledger entry for {rel} cannot be verified \
1118- (vendor_artifact_path_invalid); fix .socket/vendor/state.json, for example \
1119- by restoring it from version control"
1145+ "committed artifact {rel} cannot be verified (vendor_artifact_path_invalid), \
1146+ so `socket-patch repair` will not rebuild it; restore \
1147+ .socket/vendor/state.json and .socket/manifest.json from version control, \
1148+ or re-run `socket-patch vendor`"
11201149 ) ,
11211150 ) ,
11221151 (
@@ -1139,9 +1168,13 @@ mod tests {
11391168 } )
11401169 . await
11411170 . unwrap ( ) ;
1142- assert ! (
1143- text. starts_with( & format!( "Bun workspace copy of {rel} is missing" ) ) ,
1144- "{text}"
1171+ assert_eq ! (
1172+ text,
1173+ format!(
1174+ "Bun workspace copy of {rel} is missing (vendor_workspace_artifact_missing); run \
1175+ `socket-patch repair` to restore it, then commit it"
1176+ ) ,
1177+ "no recorded sha256: the canonical tarball is not claimed intact"
11451178 ) ;
11461179 assert ! ( !text. contains( '{' ) && !text. contains( '"' ) , "{text}" ) ;
11471180 }
0 commit comments