|
4 | 4 | "context" |
5 | 5 | "crypto/rand" |
6 | 6 | "encoding/base64" |
| 7 | + "errors" |
7 | 8 | "math" |
8 | 9 | "testing" |
9 | 10 | "time" |
@@ -32,6 +33,8 @@ func (its imgTrustStore) VerifySignature( |
32 | 33 | return "", time.Time{}, false, nil |
33 | 34 | } |
34 | 35 |
|
| 36 | +var errImageMetaBucketNotFound = errors.New("ImageMeta bucket not found") |
| 37 | + |
35 | 38 | func TestWrapperErrors(t *testing.T) { |
36 | 39 | image := CreateDefaultImage() |
37 | 40 | imageMeta := image.AsImageMeta() |
@@ -302,23 +305,63 @@ func TestWrapperErrors(t *testing.T) { |
302 | 305 | So(err, ShouldNotBeNil) |
303 | 306 | }) |
304 | 307 |
|
305 | | - Convey("image is index, fail to get manifests", func() { |
| 308 | + Convey("image is index, missing manifests are skipped gracefully", func() { |
| 309 | + err := boltdbWrapper.SetRepoReference(ctx, "repo", "tag", multiarchImageMeta) |
| 310 | + So(err, ShouldBeNil) |
| 311 | + |
| 312 | + // Missing manifests are skipped gracefully, so GetFullImageMeta succeeds |
| 313 | + // but returns an index with no manifests |
| 314 | + fullImageMeta, err := boltdbWrapper.GetFullImageMeta(ctx, "repo", "tag") |
| 315 | + So(err, ShouldBeNil) |
| 316 | + So(len(fullImageMeta.Manifests), ShouldEqual, 0) |
| 317 | + }) |
| 318 | + |
| 319 | + Convey("image is index, corrupted manifest data returns error", func() { |
| 320 | + // Create a multiarch image with multiple manifests |
| 321 | + multiarchImage := CreateMultiarchWith().RandomImages(2).Build() |
| 322 | + multiarchImageMeta := multiarchImage.AsImageMeta() |
306 | 323 | err := boltdbWrapper.SetImageMeta(multiarchImageMeta.Digest, multiarchImageMeta) |
307 | 324 | So(err, ShouldBeNil) |
308 | 325 |
|
309 | | - err = boltdbWrapper.SetRepoMeta("repo", mTypes.RepoMeta{ |
310 | | - Name: "repo", |
311 | | - Tags: map[mTypes.Tag]mTypes.Descriptor{ |
312 | | - "tag": { |
313 | | - MediaType: ispec.MediaTypeImageIndex, |
314 | | - Digest: multiarchImageMeta.Digest.String(), |
315 | | - }, |
316 | | - }, |
| 326 | + // Store the first manifest normally |
| 327 | + firstManifest := multiarchImage.Images[0] |
| 328 | + firstManifestMeta := firstManifest.AsImageMeta() |
| 329 | + err = boltdbWrapper.SetImageMeta(firstManifestMeta.Digest, firstManifestMeta) |
| 330 | + So(err, ShouldBeNil) |
| 331 | + |
| 332 | + // Store the second manifest normally first, then corrupt it |
| 333 | + secondManifest := multiarchImage.Images[1] |
| 334 | + secondManifestMeta := secondManifest.AsImageMeta() |
| 335 | + err = boltdbWrapper.SetImageMeta(secondManifestMeta.Digest, secondManifestMeta) |
| 336 | + So(err, ShouldBeNil) |
| 337 | + |
| 338 | + secondManifestDigest := secondManifest.ManifestDescriptor.Digest |
| 339 | + |
| 340 | + // Corrupt the data for the second manifest by storing invalid protobuf data |
| 341 | + // This will cause getProtoImageMeta to return an unmarshaling error |
| 342 | + // which is not ErrImageMetaNotFound, so it will propagate through getAllContainedMeta |
| 343 | + corruptedData := []byte("invalid protobuf data") |
| 344 | + |
| 345 | + // Access BoltDB directly to corrupt the data |
| 346 | + err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error { |
| 347 | + imageBuck := tx.Bucket([]byte(boltdb.ImageMetaBuck)) |
| 348 | + if imageBuck == nil { |
| 349 | + return errImageMetaBucketNotFound |
| 350 | + } |
| 351 | + // Store corrupted protobuf data |
| 352 | + return imageBuck.Put([]byte(secondManifestDigest.String()), corruptedData) |
317 | 353 | }) |
318 | 354 | So(err, ShouldBeNil) |
319 | 355 |
|
320 | | - _, err = boltdbWrapper.GetFullImageMeta(ctx, "repo", "tag") |
| 356 | + err = boltdbWrapper.SetRepoReference(ctx, "repo", "tag", multiarchImageMeta) |
| 357 | + So(err, ShouldBeNil) |
| 358 | + |
| 359 | + // GetFullImageMeta should return an error due to corrupted manifest data |
| 360 | + // The error from getAllContainedMeta should propagate |
| 361 | + fullImageMeta, err := boltdbWrapper.GetFullImageMeta(ctx, "repo", "tag") |
321 | 362 | So(err, ShouldNotBeNil) |
| 363 | + // Should still return a FullImageMeta object (even with error) |
| 364 | + So(fullImageMeta, ShouldNotBeNil) |
322 | 365 | }) |
323 | 366 | }) |
324 | 367 |
|
@@ -443,6 +486,54 @@ func TestWrapperErrors(t *testing.T) { |
443 | 486 | _, err = boltdbWrapper.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta) |
444 | 487 | So(err, ShouldBeNil) |
445 | 488 | }) |
| 489 | + |
| 490 | + Convey("getAllContainedMeta error for index is joined and processing continues", func() { |
| 491 | + // Create a multiarch image with multiple manifests |
| 492 | + multiarchImage := CreateMultiarchWith().RandomImages(2).Build() |
| 493 | + multiarchImageMeta := multiarchImage.AsImageMeta() |
| 494 | + err := boltdbWrapper.SetImageMeta(multiarchImageMeta.Digest, multiarchImageMeta) |
| 495 | + So(err, ShouldBeNil) |
| 496 | + |
| 497 | + // Store the first manifest normally |
| 498 | + firstManifest := multiarchImage.Images[0] |
| 499 | + firstManifestMeta := firstManifest.AsImageMeta() |
| 500 | + err = boltdbWrapper.SetImageMeta(firstManifestMeta.Digest, firstManifestMeta) |
| 501 | + So(err, ShouldBeNil) |
| 502 | + |
| 503 | + // Store the second manifest normally first, then corrupt it |
| 504 | + secondManifest := multiarchImage.Images[1] |
| 505 | + secondManifestMeta := secondManifest.AsImageMeta() |
| 506 | + err = boltdbWrapper.SetImageMeta(secondManifestMeta.Digest, secondManifestMeta) |
| 507 | + So(err, ShouldBeNil) |
| 508 | + |
| 509 | + secondManifestDigest := secondManifest.ManifestDescriptor.Digest |
| 510 | + |
| 511 | + // Corrupt the data for the second manifest by storing invalid protobuf data |
| 512 | + // This will cause getProtoImageMeta to return an unmarshaling error |
| 513 | + // which is not ErrImageMetaNotFound, so it will propagate through getAllContainedMeta |
| 514 | + corruptedData := []byte("invalid protobuf data") |
| 515 | + |
| 516 | + // Access BoltDB directly to corrupt the data |
| 517 | + err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error { |
| 518 | + imageBuck := tx.Bucket([]byte(boltdb.ImageMetaBuck)) |
| 519 | + if imageBuck == nil { |
| 520 | + return errImageMetaBucketNotFound |
| 521 | + } |
| 522 | + // Store corrupted protobuf data |
| 523 | + return imageBuck.Put([]byte(secondManifestDigest.String()), corruptedData) |
| 524 | + }) |
| 525 | + So(err, ShouldBeNil) |
| 526 | + |
| 527 | + err = boltdbWrapper.SetRepoReference(ctx, "repo", "tag", multiarchImageMeta) |
| 528 | + So(err, ShouldBeNil) |
| 529 | + |
| 530 | + // FilterTags should return an error due to corrupted manifest data |
| 531 | + // The error from getAllContainedMeta should be joined with viewError |
| 532 | + images, err := boltdbWrapper.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta) |
| 533 | + So(err, ShouldNotBeNil) |
| 534 | + // Should still return some images (the first valid manifest might be processed) |
| 535 | + So(images, ShouldNotBeNil) |
| 536 | + }) |
446 | 537 | }) |
447 | 538 |
|
448 | 539 | Convey("SearchRepos", func() { |
@@ -470,6 +561,53 @@ func TestWrapperErrors(t *testing.T) { |
470 | 561 | }) |
471 | 562 | }) |
472 | 563 |
|
| 564 | + Convey("GetImageMeta", func() { |
| 565 | + Convey("image is index, getAllContainedMeta error returns error", func() { |
| 566 | + // Create a multiarch image with multiple manifests |
| 567 | + multiarchImage := CreateMultiarchWith().RandomImages(2).Build() |
| 568 | + multiarchImageMeta := multiarchImage.AsImageMeta() |
| 569 | + err := boltdbWrapper.SetImageMeta(multiarchImageMeta.Digest, multiarchImageMeta) |
| 570 | + So(err, ShouldBeNil) |
| 571 | + |
| 572 | + // Store the first manifest normally |
| 573 | + firstManifest := multiarchImage.Images[0] |
| 574 | + firstManifestMeta := firstManifest.AsImageMeta() |
| 575 | + err = boltdbWrapper.SetImageMeta(firstManifestMeta.Digest, firstManifestMeta) |
| 576 | + So(err, ShouldBeNil) |
| 577 | + |
| 578 | + // Store the second manifest normally first, then corrupt it |
| 579 | + secondManifest := multiarchImage.Images[1] |
| 580 | + secondManifestMeta := secondManifest.AsImageMeta() |
| 581 | + err = boltdbWrapper.SetImageMeta(secondManifestMeta.Digest, secondManifestMeta) |
| 582 | + So(err, ShouldBeNil) |
| 583 | + |
| 584 | + secondManifestDigest := secondManifest.ManifestDescriptor.Digest |
| 585 | + |
| 586 | + // Corrupt the data for the second manifest by storing invalid protobuf data |
| 587 | + // This will cause getProtoImageMeta to return an unmarshaling error |
| 588 | + // which is not ErrImageMetaNotFound, so it will propagate through getAllContainedMeta |
| 589 | + corruptedData := []byte("invalid protobuf data") |
| 590 | + |
| 591 | + // Access BoltDB directly to corrupt the data |
| 592 | + err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error { |
| 593 | + imageBuck := tx.Bucket([]byte(boltdb.ImageMetaBuck)) |
| 594 | + if imageBuck == nil { |
| 595 | + return errImageMetaBucketNotFound |
| 596 | + } |
| 597 | + // Store corrupted protobuf data |
| 598 | + return imageBuck.Put([]byte(secondManifestDigest.String()), corruptedData) |
| 599 | + }) |
| 600 | + So(err, ShouldBeNil) |
| 601 | + |
| 602 | + // GetImageMeta should return an error due to corrupted manifest data |
| 603 | + // The error from getAllContainedMeta should propagate |
| 604 | + imageMeta, err := boltdbWrapper.GetImageMeta(multiarchImageMeta.Digest) |
| 605 | + So(err, ShouldNotBeNil) |
| 606 | + // Should still return an ImageMeta object (even with error) |
| 607 | + So(imageMeta, ShouldNotBeNil) |
| 608 | + }) |
| 609 | + }) |
| 610 | + |
473 | 611 | Convey("SetRepoReference", func() { |
474 | 612 | Convey("getProtoRepoMeta errors", func() { |
475 | 613 | err := setRepoMeta("repo", badProtoBlob, boltdbWrapper.DB) |
|
0 commit comments