@@ -579,40 +579,7 @@ func (s *S3Cache) downloadWithSLSAVerification(ctx context.Context, p cache.Pack
579579 }
580580
581581 // Step 6: Download provenance bundle if it exists (best effort, non-blocking)
582- // Provenance bundles are stored alongside artifacts as <artifact>.provenance.jsonl
583- // This is needed for dependency provenance collection during local builds
584- provenanceKey := artifactKey + ".provenance.jsonl"
585- provenancePath := localPath + ".provenance.jsonl"
586- tmpProvenancePath := provenancePath + ".tmp"
587-
588- // Try to download provenance bundle (non-critical, don't fail if missing)
589- if err := s .waitForRateLimit (ctx ); err == nil {
590- downloadCtx , cancel := context .WithTimeout (ctx , 30 * time .Second )
591- defer cancel ()
592-
593- if _ , err := s .storage .GetObject (downloadCtx , provenanceKey , tmpProvenancePath ); err == nil {
594- // Successfully downloaded, move to final location
595- if err := s .atomicMove (tmpProvenancePath , provenancePath ); err != nil {
596- log .WithError (err ).WithFields (log.Fields {
597- "package" : p .FullName (),
598- "key" : provenanceKey ,
599- }).Debug ("Failed to move provenance bundle, continuing" )
600- s .cleanupTempFiles (tmpProvenancePath )
601- } else {
602- log .WithFields (log.Fields {
603- "package" : p .FullName (),
604- "key" : provenanceKey ,
605- }).Debug ("Successfully downloaded provenance bundle" )
606- }
607- } else {
608- // Provenance not found - this is expected for older artifacts
609- log .WithFields (log.Fields {
610- "package" : p .FullName (),
611- "key" : provenanceKey ,
612- }).Debug ("Provenance bundle not found in remote cache (expected for older artifacts)" )
613- s .cleanupTempFiles (tmpProvenancePath )
614- }
615- }
582+ s .downloadProvenanceBundle (ctx , p .FullName (), artifactKey , localPath )
616583
617584 // Clean up temporary attestation file
618585 s .cleanupTempFiles (tmpAttestationPath )
@@ -1004,37 +971,8 @@ func (s *S3Cache) Upload(ctx context.Context, src cache.LocalCache, pkgs []cache
1004971 "key" : key ,
1005972 }).Debug ("successfully uploaded package to remote cache" )
1006973
1007- // Upload provenance bundle if it exists
1008- // Provenance bundles are stored alongside artifacts as <artifact>.provenance.jsonl
1009- provenancePath := localPath + ".provenance.jsonl"
1010- if fileExists (provenancePath ) {
1011- provenanceKey := key + ".provenance.jsonl"
1012-
1013- // Wait for rate limiter permission
1014- if err := s .waitForRateLimit (ctx ); err != nil {
1015- log .WithError (err ).WithFields (log.Fields {
1016- "package" : p .FullName (),
1017- "key" : provenanceKey ,
1018- }).Warn ("rate limiter error during provenance upload - continuing" )
1019- // Don't add to uploadErrors - provenance is optional
1020- return nil
1021- }
1022-
1023- timeoutCtx , cancel := context .WithTimeout (ctx , 60 * time .Second )
1024- defer cancel ()
1025- if err := s .storage .UploadObject (timeoutCtx , provenanceKey , provenancePath ); err != nil {
1026- log .WithError (err ).WithFields (log.Fields {
1027- "package" : p .FullName (),
1028- "key" : provenanceKey ,
1029- }).Warn ("failed to upload provenance bundle to remote cache - continuing" )
1030- // Don't add to uploadErrors - provenance is optional
1031- } else {
1032- log .WithFields (log.Fields {
1033- "package" : p .FullName (),
1034- "key" : provenanceKey ,
1035- }).Debug ("successfully uploaded provenance bundle to remote cache" )
1036- }
1037- }
974+ // Upload provenance bundle if it exists (non-blocking)
975+ s .uploadProvenanceBundle (ctx , p .FullName (), key , localPath )
1038976
1039977 return nil
1040978 })
@@ -1300,3 +1238,118 @@ func fileExists(filename string) bool {
13001238 }
13011239 return ! info .IsDir ()
13021240}
1241+
1242+ // uploadProvenanceBundle uploads a provenance bundle to S3 with retry logic.
1243+ // This is a non-blocking operation - failures are logged but don't fail the build.
1244+ // Provenance bundles are stored alongside artifacts as <artifact>.provenance.jsonl
1245+ // and are needed for dependency provenance collection during local builds.
1246+ func (s * S3Cache ) uploadProvenanceBundle (ctx context.Context , packageName , artifactKey , localPath string ) {
1247+ provenancePath := localPath + ".provenance.jsonl"
1248+
1249+ // Check if provenance file exists
1250+ if ! fileExists (provenancePath ) {
1251+ log .WithFields (log.Fields {
1252+ "package" : packageName ,
1253+ "path" : provenancePath ,
1254+ }).Debug ("Provenance bundle not found locally, skipping upload" )
1255+ return
1256+ }
1257+
1258+ provenanceKey := artifactKey + ".provenance.jsonl"
1259+
1260+ // Wait for rate limiter permission
1261+ if err := s .waitForRateLimit (ctx ); err != nil {
1262+ log .WithError (err ).WithFields (log.Fields {
1263+ "package" : packageName ,
1264+ "key" : provenanceKey ,
1265+ }).Warn ("Rate limiter error during provenance upload, skipping" )
1266+ return
1267+ }
1268+
1269+ // Upload with timeout and retry logic (via storage layer)
1270+ uploadCtx , cancel := context .WithTimeout (ctx , 60 * time .Second )
1271+ defer cancel ()
1272+
1273+ if err := s .storage .UploadObject (uploadCtx , provenanceKey , provenancePath ); err != nil {
1274+ log .WithError (err ).WithFields (log.Fields {
1275+ "package" : packageName ,
1276+ "key" : provenanceKey ,
1277+ "path" : provenancePath ,
1278+ }).Warn ("Failed to upload provenance bundle to remote cache" )
1279+ return
1280+ }
1281+
1282+ log .WithFields (log.Fields {
1283+ "package" : packageName ,
1284+ "key" : provenanceKey ,
1285+ }).Debug ("Successfully uploaded provenance bundle to remote cache" )
1286+ }
1287+
1288+ // downloadProvenanceBundle downloads a provenance bundle from S3 with verification.
1289+ // This is a best-effort operation - missing provenance is expected for older artifacts.
1290+ // Returns true if provenance was successfully downloaded, false otherwise.
1291+ func (s * S3Cache ) downloadProvenanceBundle (ctx context.Context , packageName , artifactKey , localPath string ) bool {
1292+ provenanceKey := artifactKey + ".provenance.jsonl"
1293+ provenancePath := localPath + ".provenance.jsonl"
1294+ tmpProvenancePath := provenancePath + ".tmp"
1295+
1296+ // Wait for rate limiter permission
1297+ if err := s .waitForRateLimit (ctx ); err != nil {
1298+ log .WithError (err ).WithFields (log.Fields {
1299+ "package" : packageName ,
1300+ "key" : provenanceKey ,
1301+ }).Debug ("Rate limiter error during provenance download, skipping" )
1302+ return false
1303+ }
1304+
1305+ // Download with timeout
1306+ downloadCtx , cancel := context .WithTimeout (ctx , 30 * time .Second )
1307+ defer cancel ()
1308+
1309+ bytesDownloaded , err := s .storage .GetObject (downloadCtx , provenanceKey , tmpProvenancePath )
1310+ if err != nil {
1311+ // Provenance not found - this is expected for older artifacts
1312+ log .WithFields (log.Fields {
1313+ "package" : packageName ,
1314+ "key" : provenanceKey ,
1315+ }).Debug ("Provenance bundle not found in remote cache (expected for older artifacts)" )
1316+ s .cleanupTempFiles (tmpProvenancePath )
1317+ return false
1318+ }
1319+
1320+ // Verify the downloaded file exists and has content
1321+ if ! fileExists (tmpProvenancePath ) {
1322+ log .WithFields (log.Fields {
1323+ "package" : packageName ,
1324+ "key" : provenanceKey ,
1325+ }).Warn ("Provenance bundle download reported success but file not found" )
1326+ s .cleanupTempFiles (tmpProvenancePath )
1327+ return false
1328+ }
1329+
1330+ if bytesDownloaded == 0 {
1331+ log .WithFields (log.Fields {
1332+ "package" : packageName ,
1333+ "key" : provenanceKey ,
1334+ }).Warn ("Provenance bundle downloaded but file is empty" )
1335+ s .cleanupTempFiles (tmpProvenancePath )
1336+ return false
1337+ }
1338+
1339+ // Atomically move to final location
1340+ if err := s .atomicMove (tmpProvenancePath , provenancePath ); err != nil {
1341+ log .WithError (err ).WithFields (log.Fields {
1342+ "package" : packageName ,
1343+ "key" : provenanceKey ,
1344+ }).Warn ("Failed to move provenance bundle to final location" )
1345+ s .cleanupTempFiles (tmpProvenancePath )
1346+ return false
1347+ }
1348+
1349+ log .WithFields (log.Fields {
1350+ "package" : packageName ,
1351+ "key" : provenanceKey ,
1352+ "bytes" : bytesDownloaded ,
1353+ }).Debug ("Successfully downloaded provenance bundle" )
1354+ return true
1355+ }
0 commit comments