github.com/paketo-buildpacks/packit@v1.3.2-0.20211206231111-86b75c657449/build_test.go (about) 1 package packit_test 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 "testing" 10 "testing/iotest" 11 12 "github.com/paketo-buildpacks/packit" 13 "github.com/paketo-buildpacks/packit/fakes" 14 "github.com/sclevine/spec" 15 16 . "github.com/onsi/gomega" 17 . "github.com/paketo-buildpacks/packit/matchers" 18 ) 19 20 func testBuild(t *testing.T, context spec.G, it spec.S) { 21 var ( 22 Expect = NewWithT(t).Expect 23 24 workingDir string 25 platformDir string 26 tmpDir string 27 layersDir string 28 planPath string 29 cnbDir string 30 envCnbDir string 31 binaryPath string 32 exitHandler *fakes.ExitHandler 33 ) 34 35 it.Before(func() { 36 var err error 37 workingDir, err = os.Getwd() 38 Expect(err).NotTo(HaveOccurred()) 39 40 tmpDir, err = os.MkdirTemp("", "working-dir") 41 Expect(err).NotTo(HaveOccurred()) 42 43 tmpDir, err = filepath.EvalSymlinks(tmpDir) 44 Expect(err).NotTo(HaveOccurred()) 45 46 Expect(os.Chdir(tmpDir)).To(Succeed()) 47 48 layersDir, err = os.MkdirTemp("", "layers") 49 Expect(err).NotTo(HaveOccurred()) 50 51 platformDir, err = os.MkdirTemp("", "platform") 52 Expect(err).NotTo(HaveOccurred()) 53 54 file, err := os.CreateTemp("", "plan.toml") 55 Expect(err).NotTo(HaveOccurred()) 56 defer file.Close() 57 58 _, err = file.WriteString(` 59 [[entries]] 60 name = "some-entry" 61 62 [entries.metadata] 63 version = "some-version" 64 some-key = "some-value" 65 `) 66 Expect(err).NotTo(HaveOccurred()) 67 68 planPath = file.Name() 69 70 cnbDir, err = os.MkdirTemp("", "cnb") 71 Expect(err).NotTo(HaveOccurred()) 72 73 envCnbDir, err = os.MkdirTemp("", "envCnb") 74 Expect(err).NotTo(HaveOccurred()) 75 76 bpTOML := []byte(` 77 api = "0.7" 78 [buildpack] 79 id = "some-id" 80 name = "some-name" 81 version = "some-version" 82 homepage = "some-homepage" 83 description = "some-description" 84 keywords = ["some-keyword"] 85 sbom-formats = ["some-sbom-format", "some-other-sbom-format"] 86 clear-env = false 87 88 [[buildpack.licenses]] 89 type = "some-license-type" 90 uri = "some-license-uri" 91 `) 92 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 93 Expect(os.WriteFile(filepath.Join(envCnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 94 95 binaryPath = filepath.Join(cnbDir, "bin", "build") 96 97 Expect(os.Setenv("CNB_STACK_ID", "some-stack")).To(Succeed()) 98 99 exitHandler = &fakes.ExitHandler{} 100 }) 101 102 it.After(func() { 103 Expect(os.Unsetenv("CNB_STACK_ID")).To(Succeed()) 104 105 Expect(os.Chdir(workingDir)).To(Succeed()) 106 Expect(os.RemoveAll(tmpDir)).To(Succeed()) 107 Expect(os.RemoveAll(layersDir)).To(Succeed()) 108 Expect(os.RemoveAll(platformDir)).To(Succeed()) 109 }) 110 111 it("provides the build context to the given BuildFunc", func() { 112 var context packit.BuildContext 113 114 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 115 context = ctx 116 117 return packit.BuildResult{}, nil 118 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 119 120 Expect(context).To(Equal(packit.BuildContext{ 121 CNBPath: cnbDir, 122 Stack: "some-stack", 123 Platform: packit.Platform{ 124 Path: platformDir, 125 }, 126 WorkingDir: tmpDir, 127 Plan: packit.BuildpackPlan{ 128 Entries: []packit.BuildpackPlanEntry{ 129 { 130 Name: "some-entry", 131 Metadata: map[string]interface{}{ 132 "version": "some-version", 133 "some-key": "some-value", 134 }, 135 }, 136 }, 137 }, 138 Layers: packit.Layers{ 139 Path: layersDir, 140 }, 141 BuildpackInfo: packit.BuildpackInfo{ 142 ID: "some-id", 143 Name: "some-name", 144 Version: "some-version", 145 Homepage: "some-homepage", 146 Description: "some-description", 147 Keywords: []string{"some-keyword"}, 148 SBOMFormats: []string{"some-sbom-format", "some-other-sbom-format"}, 149 Licenses: []packit.BuildpackInfoLicense{ 150 { 151 Type: "some-license-type", 152 URI: "some-license-uri", 153 }, 154 }, 155 }, 156 })) 157 }) 158 159 context("when there are updates to the build plan", func() { 160 context("when the api version is less than 0.5", func() { 161 it.Before(func() { 162 bpTOML := []byte(` 163 api = "0.4" 164 [buildpack] 165 id = "some-id" 166 name = "some-name" 167 version = "some-version" 168 clear-env = false 169 `) 170 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 171 Expect(os.WriteFile(filepath.Join(envCnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 172 173 }) 174 175 it("updates the buildpack plan.toml with any changes", func() { 176 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 177 ctx.Plan.Entries[0].Metadata["other-key"] = "other-value" 178 179 return packit.BuildResult{ 180 Plan: ctx.Plan, 181 }, nil 182 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 183 184 contents, err := os.ReadFile(planPath) 185 Expect(err).NotTo(HaveOccurred()) 186 187 Expect(string(contents)).To(MatchTOML(` 188 [[entries]] 189 name = "some-entry" 190 191 [entries.metadata] 192 version = "some-version" 193 some-key = "some-value" 194 other-key = "other-value" 195 `)) 196 }) 197 }) 198 199 context("when the api version is greater or equal to 0.5", func() { 200 it("throws an error", func() { 201 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 202 return packit.BuildResult{ 203 Plan: ctx.Plan, 204 }, nil 205 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 206 207 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("buildpack plan is read only"))) 208 }) 209 }) 210 }) 211 212 it("persists layer metadata", func() { 213 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 214 layerPath := filepath.Join(ctx.Layers.Path, "some-layer") 215 Expect(os.MkdirAll(layerPath, os.ModePerm)).To(Succeed()) 216 217 return packit.BuildResult{ 218 Layers: []packit.Layer{ 219 packit.Layer{ 220 Path: layerPath, 221 Name: "some-layer", 222 Build: true, 223 Launch: true, 224 Cache: true, 225 Metadata: map[string]interface{}{ 226 "some-key": "some-value", 227 }, 228 }, 229 }, 230 }, nil 231 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 232 233 contents, err := os.ReadFile(filepath.Join(layersDir, "some-layer.toml")) 234 Expect(err).NotTo(HaveOccurred()) 235 236 Expect(string(contents)).To(MatchTOML(` 237 [types] 238 launch = true 239 build = true 240 cache = true 241 242 [metadata] 243 some-key = "some-value" 244 `)) 245 }) 246 247 context("when the buildpack api version is less than 0.6", func() { 248 it.Before(func() { 249 bpTOML := []byte(` 250 api = "0.5" 251 [buildpack] 252 id = "some-id" 253 name = "some-name" 254 version = "some-version" 255 `) 256 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 257 }) 258 259 it("persists layer metadata", func() { 260 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 261 layerPath := filepath.Join(ctx.Layers.Path, "some-layer") 262 Expect(os.MkdirAll(layerPath, os.ModePerm)).To(Succeed()) 263 264 return packit.BuildResult{ 265 Layers: []packit.Layer{ 266 packit.Layer{ 267 Path: layerPath, 268 Name: "some-layer", 269 Build: true, 270 Launch: true, 271 Cache: true, 272 Metadata: map[string]interface{}{ 273 "some-key": "some-value", 274 }, 275 }, 276 }, 277 }, nil 278 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 279 280 contents, err := os.ReadFile(filepath.Join(layersDir, "some-layer.toml")) 281 Expect(err).NotTo(HaveOccurred()) 282 283 Expect(string(contents)).To(MatchTOML(` 284 launch = true 285 build = true 286 cache = true 287 288 [metadata] 289 some-key = "some-value" 290 `)) 291 }) 292 }) 293 294 context("when there are sbom entries in layer metadata", func() { 295 it("writes them to their specified locations", func() { 296 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 297 layerPath := filepath.Join(ctx.Layers.Path, "some-layer") 298 Expect(os.MkdirAll(layerPath, os.ModePerm)).To(Succeed()) 299 300 return packit.BuildResult{ 301 Layers: []packit.Layer{ 302 packit.Layer{ 303 Path: layerPath, 304 Name: "some-layer", 305 SBOM: packit.SBOMFormats{ 306 { 307 Extension: "some.json", 308 Content: strings.NewReader(`{"some-key": "some-value"}`), 309 }, 310 { 311 Extension: "other.yml", 312 Content: strings.NewReader(`other-key: other-value`), 313 }, 314 }, 315 }, 316 }, 317 }, nil 318 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 319 320 contents, err := os.ReadFile(filepath.Join(layersDir, "some-layer.sbom.some.json")) 321 Expect(err).NotTo(HaveOccurred()) 322 Expect(string(contents)).To(MatchJSON(`{"some-key": "some-value"}`)) 323 324 contents, err = os.ReadFile(filepath.Join(layersDir, "some-layer.sbom.other.yml")) 325 Expect(err).NotTo(HaveOccurred()) 326 Expect(string(contents)).To(MatchYAML(`other-key: other-value`)) 327 }) 328 329 context("when the api version is less than 0.7", func() { 330 it.Before(func() { 331 bpTOML := []byte(` 332 api = "0.6" 333 [buildpack] 334 id = "some-id" 335 name = "some-name" 336 version = "some-version" 337 clear-env = false 338 `) 339 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 340 Expect(os.WriteFile(filepath.Join(envCnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 341 }) 342 343 it("throws an error", func() { 344 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 345 layerPath := filepath.Join(ctx.Layers.Path, "some-layer") 346 Expect(os.MkdirAll(layerPath, os.ModePerm)).To(Succeed()) 347 348 return packit.BuildResult{ 349 Layers: []packit.Layer{ 350 packit.Layer{ 351 Path: layerPath, 352 Name: "some-layer", 353 SBOM: packit.SBOMFormats{ 354 { 355 Extension: "some.json", 356 Content: strings.NewReader(`{"some-key": "some-value"}`), 357 }, 358 }, 359 }, 360 }, 361 }, nil 362 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 363 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("some-layer.sbom.* output is only supported with Buildpack API v0.7 or higher"))) 364 }) 365 }) 366 }) 367 368 context("when there are existing layer.toml files", func() { 369 context("when the layer.toml's will not be re-written", func() { 370 var obsoleteLayerPath string 371 372 it.Before(func() { 373 obsoleteLayerPath = filepath.Join(layersDir, "obsolete-layer") 374 Expect(os.MkdirAll(obsoleteLayerPath, os.ModePerm)).To(Succeed()) 375 Expect(os.WriteFile(obsoleteLayerPath+".toml", []byte{}, 0600)).To(Succeed()) 376 377 Expect(os.WriteFile(filepath.Join(layersDir, "launch.toml"), []byte{}, 0600)).To(Succeed()) 378 Expect(os.WriteFile(filepath.Join(layersDir, "store.toml"), []byte{}, 0600)).To(Succeed()) 379 }) 380 381 context("when the buildpack api version is less than 0.6", func() { 382 it.Before(func() { 383 bpTOML := []byte(` 384 api = "0.5" 385 [buildpack] 386 id = "some-id" 387 name = "some-name" 388 version = "some-version" 389 `) 390 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 391 }) 392 393 it("removes them", func() { 394 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 395 return packit.BuildResult{ 396 Layers: []packit.Layer{}, 397 }, nil 398 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 399 Expect(obsoleteLayerPath).NotTo(BeARegularFile()) 400 Expect(obsoleteLayerPath + ".toml").NotTo(BeARegularFile()) 401 402 Expect(filepath.Join(layersDir, "launch.toml")).To(BeARegularFile()) 403 Expect(filepath.Join(layersDir, "store.toml")).To(BeARegularFile()) 404 }) 405 406 context("failures", func() { 407 context("when getting the layer toml list", func() { 408 var unremovableTOMLPath string 409 410 it.Before(func() { 411 unremovableTOMLPath = filepath.Join(layersDir, "unremovable.toml") 412 Expect(os.MkdirAll(filepath.Join(layersDir, "unremovable"), os.ModePerm)).To(Succeed()) 413 Expect(os.WriteFile(unremovableTOMLPath, []byte{}, os.ModePerm)).To(Succeed()) 414 Expect(os.Chmod(layersDir, 0666)).To(Succeed()) 415 }) 416 417 it.After(func() { 418 Expect(os.Chmod(layersDir, os.ModePerm)).To(Succeed()) 419 }) 420 421 it("returns an error", func() { 422 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 423 return packit.BuildResult{ 424 Layers: []packit.Layer{}, 425 }, nil 426 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 427 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("failed to remove layer toml:"))) 428 }) 429 }) 430 }) 431 }) 432 433 context("when the buildpack api version is greater than or equal to 0.6", func() { 434 it.Before(func() { 435 bpTOML := []byte(` 436 api = "0.6" 437 [buildpack] 438 id = "some-id" 439 name = "some-name" 440 version = "some-version" 441 `) 442 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 443 }) 444 445 it("leaves them in place", func() { 446 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 447 return packit.BuildResult{ 448 Layers: []packit.Layer{}, 449 }, nil 450 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 451 452 Expect(obsoleteLayerPath).To(BeADirectory()) 453 Expect(obsoleteLayerPath + ".toml").To(BeARegularFile()) 454 455 Expect(filepath.Join(layersDir, "launch.toml")).To(BeARegularFile()) 456 Expect(filepath.Join(layersDir, "store.toml")).To(BeARegularFile()) 457 }) 458 }) 459 }) 460 }) 461 462 context("when the CNB_BUILDPACK_DIR environment variable is set", func() { 463 it.Before(func() { 464 os.Setenv("CNB_BUILDPACK_DIR", envCnbDir) 465 }) 466 467 it.After(func() { 468 os.Unsetenv("CNB_BUILDPACK_DIR") 469 }) 470 471 it("sets the correct value for CNBdir in the Build context", func() { 472 var context packit.BuildContext 473 474 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 475 context = ctx 476 477 return packit.BuildResult{}, nil 478 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 479 480 Expect(context).To(Equal(packit.BuildContext{ 481 CNBPath: envCnbDir, 482 Platform: packit.Platform{ 483 Path: platformDir, 484 }, 485 Stack: "some-stack", 486 WorkingDir: tmpDir, 487 Plan: packit.BuildpackPlan{ 488 Entries: []packit.BuildpackPlanEntry{ 489 { 490 Name: "some-entry", 491 Metadata: map[string]interface{}{ 492 "version": "some-version", 493 "some-key": "some-value", 494 }, 495 }, 496 }, 497 }, 498 Layers: packit.Layers{ 499 Path: layersDir, 500 }, 501 BuildpackInfo: packit.BuildpackInfo{ 502 ID: "some-id", 503 Name: "some-name", 504 Version: "some-version", 505 Homepage: "some-homepage", 506 Description: "some-description", 507 Keywords: []string{"some-keyword"}, 508 SBOMFormats: []string{"some-sbom-format", "some-other-sbom-format"}, 509 Licenses: []packit.BuildpackInfoLicense{ 510 { 511 Type: "some-license-type", 512 URI: "some-license-uri", 513 }, 514 }, 515 }, 516 })) 517 }) 518 }) 519 520 context("when there are sbom entries in the build metadata", func() { 521 it("writes them to their specified locations", func() { 522 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 523 return packit.BuildResult{ 524 Build: packit.BuildMetadata{ 525 SBOM: packit.SBOMFormats{ 526 { 527 Extension: "some.json", 528 Content: strings.NewReader(`{"some-key": "some-value"}`), 529 }, 530 { 531 Extension: "other.yml", 532 Content: strings.NewReader(`other-key: other-value`), 533 }, 534 }, 535 }, 536 }, nil 537 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 538 539 contents, err := os.ReadFile(filepath.Join(layersDir, "build.sbom.some.json")) 540 Expect(err).NotTo(HaveOccurred()) 541 Expect(string(contents)).To(MatchJSON(`{"some-key": "some-value"}`)) 542 543 contents, err = os.ReadFile(filepath.Join(layersDir, "build.sbom.other.yml")) 544 Expect(err).NotTo(HaveOccurred()) 545 Expect(string(contents)).To(MatchYAML(`other-key: other-value`)) 546 }) 547 548 context("when the api version is less than 0.7", func() { 549 it.Before(func() { 550 bpTOML := []byte(` 551 api = "0.6" 552 [buildpack] 553 id = "some-id" 554 name = "some-name" 555 version = "some-version" 556 clear-env = false 557 `) 558 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 559 Expect(os.WriteFile(filepath.Join(envCnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 560 }) 561 562 it("throws an error", func() { 563 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 564 return packit.BuildResult{ 565 Build: packit.BuildMetadata{ 566 SBOM: packit.SBOMFormats{ 567 { 568 Extension: "some.json", 569 Content: strings.NewReader(`{"some-key": "some-value"}`), 570 }, 571 }, 572 }, 573 }, nil 574 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 575 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("build.sbom.* output is only supported with Buildpack API v0.7 or higher"))) 576 }) 577 }) 578 }) 579 580 context("when there are bom entries in the build metadata", func() { 581 it("persists a build.toml", func() { 582 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 583 return packit.BuildResult{ 584 Build: packit.BuildMetadata{ 585 BOM: []packit.BOMEntry{ 586 { 587 Name: "example", 588 }, 589 { 590 Name: "another-example", 591 Metadata: map[string]string{ 592 "some-key": "some-value", 593 }, 594 }, 595 }, 596 }, 597 }, nil 598 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 599 600 contents, err := os.ReadFile(filepath.Join(layersDir, "build.toml")) 601 Expect(err).NotTo(HaveOccurred()) 602 603 Expect(string(contents)).To(MatchTOML(` 604 [[bom]] 605 name = "example" 606 [[bom]] 607 name = "another-example" 608 [bom.metadata] 609 some-key = "some-value" 610 `)) 611 }) 612 613 context("when the api version is less than 0.5", func() { 614 it.Before(func() { 615 bpTOML := []byte(` 616 api = "0.4" 617 [buildpack] 618 id = "some-id" 619 name = "some-name" 620 version = "some-version" 621 clear-env = false 622 `) 623 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 624 Expect(os.WriteFile(filepath.Join(envCnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 625 }) 626 627 it("throws an error", func() { 628 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 629 return packit.BuildResult{ 630 Build: packit.BuildMetadata{ 631 BOM: []packit.BOMEntry{ 632 { 633 Name: "example", 634 }, 635 { 636 Name: "another-example", 637 Metadata: map[string]string{ 638 "some-key": "some-value", 639 }, 640 }, 641 }, 642 }, 643 }, nil 644 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 645 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("build.toml is only supported with Buildpack API v0.5 or higher"))) 646 }) 647 }) 648 }) 649 650 context("when there are unmet entries in the build metadata", func() { 651 it("persists a build.toml", func() { 652 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 653 return packit.BuildResult{ 654 Build: packit.BuildMetadata{ 655 Unmet: []packit.UnmetEntry{ 656 { 657 Name: "example", 658 }, 659 { 660 Name: "another-example", 661 }, 662 }, 663 }, 664 }, nil 665 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 666 667 contents, err := os.ReadFile(filepath.Join(layersDir, "build.toml")) 668 Expect(err).NotTo(HaveOccurred()) 669 670 Expect(string(contents)).To(MatchTOML(` 671 [[unmet]] 672 name = "example" 673 [[unmet]] 674 name = "another-example" 675 `)) 676 }) 677 context("when the api version is less than 0.5", func() { 678 it.Before(func() { 679 bpTOML := []byte(` 680 api = "0.4" 681 [buildpack] 682 id = "some-id" 683 name = "some-name" 684 version = "some-version" 685 clear-env = false 686 `) 687 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 688 Expect(os.WriteFile(filepath.Join(envCnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 689 690 }) 691 692 it("throws an error", func() { 693 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 694 return packit.BuildResult{ 695 Build: packit.BuildMetadata{ 696 Unmet: []packit.UnmetEntry{ 697 { 698 Name: "example", 699 }, 700 { 701 Name: "another-example", 702 }, 703 }, 704 }, 705 }, nil 706 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 707 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("build.toml is only supported with Buildpack API v0.5 or higher"))) 708 709 }) 710 }) 711 }) 712 713 context("when there are sbom entries in the launch metadata", func() { 714 it("writes them to their specified locations", func() { 715 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 716 return packit.BuildResult{ 717 Launch: packit.LaunchMetadata{ 718 SBOM: packit.SBOMFormats{ 719 { 720 Extension: "some.json", 721 Content: strings.NewReader(`{"some-key": "some-value"}`), 722 }, 723 { 724 Extension: "other.yml", 725 Content: strings.NewReader(`other-key: other-value`), 726 }, 727 }, 728 }, 729 }, nil 730 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 731 732 contents, err := os.ReadFile(filepath.Join(layersDir, "launch.sbom.some.json")) 733 Expect(err).NotTo(HaveOccurred()) 734 Expect(string(contents)).To(MatchJSON(`{"some-key": "some-value"}`)) 735 736 contents, err = os.ReadFile(filepath.Join(layersDir, "launch.sbom.other.yml")) 737 Expect(err).NotTo(HaveOccurred()) 738 Expect(string(contents)).To(MatchYAML(`other-key: other-value`)) 739 }) 740 741 context("when the api version is less than 0.7", func() { 742 it.Before(func() { 743 bpTOML := []byte(` 744 api = "0.6" 745 [buildpack] 746 id = "some-id" 747 name = "some-name" 748 version = "some-version" 749 clear-env = false 750 `) 751 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 752 Expect(os.WriteFile(filepath.Join(envCnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 753 }) 754 755 it("throws an error", func() { 756 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 757 return packit.BuildResult{ 758 Launch: packit.LaunchMetadata{ 759 SBOM: packit.SBOMFormats{ 760 { 761 Extension: "some.json", 762 Content: strings.NewReader(`{"some-key": "some-value"}`), 763 }, 764 }, 765 }, 766 }, nil 767 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 768 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("launch.sbom.* output is only supported with Buildpack API v0.7 or higher"))) 769 }) 770 }) 771 }) 772 773 context("when there are bom entries in the launch metadata", func() { 774 it("persists a launch.toml", func() { 775 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 776 return packit.BuildResult{ 777 Launch: packit.LaunchMetadata{ 778 BOM: []packit.BOMEntry{ 779 { 780 Name: "example", 781 }, 782 { 783 Name: "another-example", 784 Metadata: map[string]string{ 785 "some-key": "some-value", 786 }, 787 }, 788 }, 789 }, 790 }, nil 791 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 792 793 contents, err := os.ReadFile(filepath.Join(layersDir, "launch.toml")) 794 Expect(err).NotTo(HaveOccurred()) 795 796 Expect(string(contents)).To(MatchTOML(` 797 [[bom]] 798 name = "example" 799 [[bom]] 800 name = "another-example" 801 [bom.metadata] 802 some-key = "some-value" 803 `)) 804 }) 805 }) 806 807 context("when there are processes in the result", func() { 808 it("persists a launch.toml", func() { 809 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 810 return packit.BuildResult{ 811 Launch: packit.LaunchMetadata{ 812 Processes: []packit.Process{ 813 { 814 Type: "some-type", 815 Command: "some-command", 816 Args: []string{"some-arg"}, 817 Direct: true, 818 }, 819 }, 820 }, 821 }, nil 822 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 823 824 contents, err := os.ReadFile(filepath.Join(layersDir, "launch.toml")) 825 Expect(err).NotTo(HaveOccurred()) 826 827 Expect(string(contents)).To(MatchTOML(` 828 [[processes]] 829 type = "some-type" 830 command = "some-command" 831 args = ["some-arg"] 832 direct = true 833 `)) 834 }) 835 836 context("when the process is the default", func() { 837 it("persists a launch.toml", func() { 838 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 839 return packit.BuildResult{ 840 Launch: packit.LaunchMetadata{ 841 Processes: []packit.Process{ 842 { 843 Type: "some-type", 844 Command: "some-command", 845 Args: []string{"some-arg"}, 846 Direct: true, 847 Default: true, 848 }, 849 }, 850 }, 851 }, nil 852 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 853 854 contents, err := os.ReadFile(filepath.Join(layersDir, "launch.toml")) 855 Expect(err).NotTo(HaveOccurred()) 856 857 Expect(string(contents)).To(MatchTOML(` 858 [[processes]] 859 type = "some-type" 860 command = "some-command" 861 args = ["some-arg"] 862 direct = true 863 default = true 864 `)) 865 }) 866 }) 867 868 context("when the api version is less than 0.6", func() { 869 it.Before(func() { 870 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), []byte(` 871 api = "0.5" 872 [buildpack] 873 id = "some-id" 874 name = "some-name" 875 version = "some-version" 876 clear-env = false 877 `), 0600)).To(Succeed()) 878 }) 879 880 it("errors", func() { 881 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 882 return packit.BuildResult{ 883 Launch: packit.LaunchMetadata{ 884 Processes: []packit.Process{ 885 { 886 Type: "some-type", 887 Command: "some-command", 888 Args: []string{"some-arg"}, 889 Direct: true, 890 Default: true, 891 }, 892 }, 893 }, 894 }, nil 895 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 896 897 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("processes can only be marked as default with Buildpack API v0.6 or higher"))) 898 }) 899 }) 900 }) 901 902 context("when there are slices in the result", func() { 903 it("persists a launch.toml", func() { 904 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 905 return packit.BuildResult{ 906 Launch: packit.LaunchMetadata{ 907 Slices: []packit.Slice{ 908 { 909 Paths: []string{"some-slice"}, 910 }, 911 }, 912 }, 913 }, nil 914 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 915 916 contents, err := os.ReadFile(filepath.Join(layersDir, "launch.toml")) 917 Expect(err).NotTo(HaveOccurred()) 918 919 Expect(string(contents)).To(MatchTOML(` 920 [[slices]] 921 paths = ["some-slice"] 922 `)) 923 }) 924 }) 925 926 context("when there are labels in the result", func() { 927 it("persists a launch.toml", func() { 928 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 929 return packit.BuildResult{ 930 Launch: packit.LaunchMetadata{ 931 Labels: map[string]string{ 932 "some key": "some value", 933 "some-other-key": "some-other-value", 934 }, 935 }, 936 }, nil 937 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 938 939 contents, err := os.ReadFile(filepath.Join(layersDir, "launch.toml")) 940 Expect(err).NotTo(HaveOccurred()) 941 942 Expect(string(contents)).To(MatchTOML(` 943 [[labels]] 944 key = "some key" 945 value = "some value" 946 947 [[labels]] 948 key = "some-other-key" 949 value = "some-other-value" 950 `)) 951 }) 952 }) 953 954 context("when there are no processes, slices, bom or labels in the result", func() { 955 it("does not persist a launch.toml", func() { 956 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 957 return packit.BuildResult{}, nil 958 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 959 960 Expect(filepath.Join(layersDir, "launch.toml")).NotTo(BeARegularFile()) 961 }) 962 }) 963 964 context("persists env vars", func() { 965 context("writes to shared env folder", func() { 966 it("writes env vars into env directory", func() { 967 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 968 return packit.BuildResult{ 969 Layers: []packit.Layer{ 970 { 971 Path: filepath.Join(ctx.Layers.Path, "some-layer"), 972 SharedEnv: packit.Environment{ 973 "SOME_VAR.append": "append-value", 974 "SOME_VAR.default": "default-value", 975 "SOME_VAR.delim": "delim-value", 976 "SOME_VAR.prepend": "prepend-value", 977 "SOME_VAR.override": "override-value", 978 }, 979 }, 980 }, 981 }, nil 982 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 983 984 for _, modifier := range []string{"append", "default", "delim", "prepend", "override"} { 985 contents, err := os.ReadFile(filepath.Join(layersDir, "some-layer", "env", fmt.Sprintf("SOME_VAR.%s", modifier))) 986 Expect(err).NotTo(HaveOccurred()) 987 Expect(string(contents)).To(Equal(fmt.Sprintf("%s-value", modifier))) 988 } 989 }) 990 }) 991 992 context("writes to launch folder", func() { 993 it("writes env vars into env.launch directory", func() { 994 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 995 return packit.BuildResult{ 996 Layers: []packit.Layer{ 997 { 998 Path: filepath.Join(ctx.Layers.Path, "some-layer"), 999 LaunchEnv: packit.Environment{ 1000 "SOME_VAR.append": "append-value", 1001 "SOME_VAR.default": "default-value", 1002 "SOME_VAR.delim": "delim-value", 1003 "SOME_VAR.prepend": "prepend-value", 1004 "SOME_VAR.override": "override-value", 1005 }, 1006 }, 1007 }, 1008 }, nil 1009 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 1010 1011 for _, modifier := range []string{"append", "default", "delim", "prepend", "override"} { 1012 contents, err := os.ReadFile(filepath.Join(layersDir, "some-layer", "env.launch", fmt.Sprintf("SOME_VAR.%s", modifier))) 1013 Expect(err).NotTo(HaveOccurred()) 1014 Expect(string(contents)).To(Equal(fmt.Sprintf("%s-value", modifier))) 1015 } 1016 }) 1017 it("writes env vars into env.launch/<process> directory", func() { 1018 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1019 return packit.BuildResult{ 1020 Layers: []packit.Layer{ 1021 { 1022 Path: filepath.Join(ctx.Layers.Path, "some-layer"), 1023 ProcessLaunchEnv: map[string]packit.Environment{ 1024 "process-name": { 1025 "SOME_VAR.append": "append-value", 1026 "SOME_VAR.default": "default-value", 1027 "SOME_VAR.delim": "delim-value", 1028 "SOME_VAR.prepend": "prepend-value", 1029 "SOME_VAR.override": "override-value", 1030 }, 1031 "another-process-name": { 1032 "SOME_VAR.append": "append-value", 1033 "SOME_VAR.default": "default-value", 1034 "SOME_VAR.delim": "delim-value", 1035 "SOME_VAR.prepend": "prepend-value", 1036 "SOME_VAR.override": "override-value", 1037 }, 1038 }, 1039 }, 1040 }, 1041 }, nil 1042 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 1043 1044 for _, process := range []string{"process-name", "another-process-name"} { 1045 for _, modifier := range []string{"append", "default", "delim", "prepend", "override"} { 1046 contents, err := os.ReadFile(filepath.Join(layersDir, "some-layer", "env.launch", process, fmt.Sprintf("SOME_VAR.%s", modifier))) 1047 Expect(err).NotTo(HaveOccurred()) 1048 Expect(string(contents)).To(Equal(fmt.Sprintf("%s-value", modifier))) 1049 } 1050 } 1051 }) 1052 }) 1053 1054 context("writes to build folder", func() { 1055 it("writes env vars into env.build directory", func() { 1056 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1057 return packit.BuildResult{ 1058 Layers: []packit.Layer{ 1059 { 1060 Path: filepath.Join(ctx.Layers.Path, "some-layer"), 1061 BuildEnv: packit.Environment{ 1062 "SOME_VAR.append": "append-value", 1063 "SOME_VAR.default": "default-value", 1064 "SOME_VAR.delim": "delim-value", 1065 "SOME_VAR.prepend": "prepend-value", 1066 "SOME_VAR.override": "override-value", 1067 }, 1068 }, 1069 }, 1070 }, nil 1071 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath})) 1072 1073 for _, modifier := range []string{"append", "default", "delim", "prepend", "override"} { 1074 contents, err := os.ReadFile(filepath.Join(layersDir, "some-layer", "env.build", fmt.Sprintf("SOME_VAR.%s", modifier))) 1075 Expect(err).NotTo(HaveOccurred()) 1076 Expect(string(contents)).To(Equal(fmt.Sprintf("%s-value", modifier))) 1077 } 1078 }) 1079 }) 1080 }) 1081 1082 context("failure cases", func() { 1083 context("when the buildpack plan.toml is malformed", func() { 1084 it.Before(func() { 1085 err := os.WriteFile(planPath, []byte("%%%"), 0600) 1086 Expect(err).NotTo(HaveOccurred()) 1087 }) 1088 1089 it("calls the exit handler", func() { 1090 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1091 return packit.BuildResult{}, nil 1092 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1093 1094 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("expected '.' or '=', but got '%' instead"))) 1095 }) 1096 }) 1097 1098 context("when the build func returns an error", func() { 1099 it("calls the exit handler", func() { 1100 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1101 return packit.BuildResult{}, errors.New("build failed") 1102 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1103 1104 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError("build failed")) 1105 }) 1106 }) 1107 1108 context("when the buildpack.toml is malformed", func() { 1109 it.Before(func() { 1110 err := os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), []byte("%%%"), 0600) 1111 Expect(err).NotTo(HaveOccurred()) 1112 }) 1113 1114 it("calls the exit handler", func() { 1115 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1116 return packit.BuildResult{}, nil 1117 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1118 1119 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("expected '.' or '=', but got '%' instead"))) 1120 }) 1121 }) 1122 1123 context("when the buildpack plan.toml cannot be written", func() { 1124 it.Before(func() { 1125 bpTOML := []byte(` 1126 api = "0.4" 1127 [buildpack] 1128 id = "some-id" 1129 name = "some-name" 1130 version = "some-version" 1131 clear-env = false 1132 `) 1133 Expect(os.WriteFile(filepath.Join(cnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 1134 Expect(os.WriteFile(filepath.Join(envCnbDir, "buildpack.toml"), bpTOML, 0600)).To(Succeed()) 1135 Expect(os.Chmod(planPath, 0444)).To(Succeed()) 1136 }) 1137 1138 it("calls the exit handler", func() { 1139 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1140 return packit.BuildResult{Plan: ctx.Plan}, nil 1141 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1142 1143 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("permission denied"))) 1144 }) 1145 }) 1146 1147 context("when the layer.toml file cannot be written", func() { 1148 it.Before(func() { 1149 Expect(os.Chmod(layersDir, 0000)).To(Succeed()) 1150 }) 1151 1152 it.After(func() { 1153 Expect(os.Chmod(layersDir, os.ModePerm)).To(Succeed()) 1154 }) 1155 1156 it("calls the exit handler", func() { 1157 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1158 return packit.BuildResult{ 1159 Layers: []packit.Layer{ 1160 packit.Layer{ 1161 Path: filepath.Join(layersDir, "some-layer"), 1162 Name: "some-layer", 1163 }, 1164 }, 1165 }, nil 1166 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1167 1168 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("permission denied"))) 1169 }) 1170 }) 1171 1172 context("when the layer sbom cannot be written", func() { 1173 it("calls the exit handler", func() { 1174 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1175 return packit.BuildResult{ 1176 Layers: []packit.Layer{ 1177 packit.Layer{ 1178 Path: filepath.Join(layersDir, "some-layer"), 1179 Name: "some-layer", 1180 SBOM: packit.SBOMFormats{ 1181 { 1182 Extension: "some.json", 1183 Content: iotest.ErrReader(errors.New("failed to format layer sbom")), 1184 }, 1185 }, 1186 }, 1187 }, 1188 }, nil 1189 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1190 1191 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("failed to format layer sbom"))) 1192 }) 1193 }) 1194 1195 context("when the launch.toml file cannot be written", func() { 1196 it.Before(func() { 1197 _, err := os.OpenFile(filepath.Join(layersDir, "launch.toml"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0000) 1198 Expect(err).NotTo(HaveOccurred()) 1199 }) 1200 1201 it.After(func() { 1202 Expect(os.Chmod(filepath.Join(layersDir, "launch.toml"), os.ModePerm)).To(Succeed()) 1203 }) 1204 1205 it("calls the exit handler", func() { 1206 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1207 return packit.BuildResult{ 1208 Launch: packit.LaunchMetadata{ 1209 Processes: []packit.Process{{}}, 1210 }, 1211 }, nil 1212 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1213 1214 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("permission denied"))) 1215 }) 1216 }) 1217 1218 context("when the env dir cannot be created", func() { 1219 var envDir string 1220 it.Before(func() { 1221 var err error 1222 envDir, err = os.MkdirTemp("", "environment") 1223 Expect(err).NotTo(HaveOccurred()) 1224 1225 Expect(os.Chmod(envDir, 0000)).To(Succeed()) 1226 }) 1227 1228 it.After(func() { 1229 Expect(os.Chmod(envDir, os.ModePerm)).To(Succeed()) 1230 }) 1231 1232 context("SharedEnv", func() { 1233 it("calls the exit handler", func() { 1234 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1235 return packit.BuildResult{ 1236 Layers: []packit.Layer{ 1237 { 1238 Path: envDir, 1239 SharedEnv: packit.Environment{ 1240 "SOME_VAR.override": "some-value", 1241 }, 1242 }, 1243 }, 1244 }, nil 1245 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1246 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("permission denied"))) 1247 }) 1248 }) 1249 1250 context("BuildEnv", func() { 1251 it("calls the exit handler", func() { 1252 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1253 return packit.BuildResult{ 1254 Layers: []packit.Layer{ 1255 { 1256 Path: envDir, 1257 BuildEnv: packit.Environment{ 1258 "SOME_VAR.override": "some-value", 1259 }, 1260 }, 1261 }, 1262 }, nil 1263 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1264 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("permission denied"))) 1265 }) 1266 }) 1267 1268 context("LaunchEnv", func() { 1269 it("calls the exit handler", func() { 1270 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1271 return packit.BuildResult{ 1272 Layers: []packit.Layer{ 1273 { 1274 Path: envDir, 1275 LaunchEnv: packit.Environment{ 1276 "SOME_VAR.override": "some-value", 1277 }, 1278 }, 1279 }, 1280 }, nil 1281 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1282 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("permission denied"))) 1283 }) 1284 }) 1285 }) 1286 1287 context("when the env file cannot be created", func() { 1288 context("SharedEnv", func() { 1289 var envDir string 1290 it.Before(func() { 1291 envDir = filepath.Join(layersDir, "some-layer", "env") 1292 Expect(os.MkdirAll(envDir, os.ModePerm)).To(Succeed()) 1293 Expect(os.Chmod(envDir, 0000)).To(Succeed()) 1294 }) 1295 1296 it.After(func() { 1297 Expect(os.Chmod(envDir, os.ModePerm)).To(Succeed()) 1298 }) 1299 1300 it("calls the exit handler", func() { 1301 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1302 return packit.BuildResult{ 1303 Layers: []packit.Layer{{ 1304 Path: filepath.Join(layersDir, "some-layer"), 1305 SharedEnv: packit.Environment{ 1306 "SOME_VAR.override": "some-value", 1307 }, 1308 }}, 1309 }, nil 1310 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1311 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("permission denied"))) 1312 }) 1313 }) 1314 1315 context("BuildEnv", func() { 1316 var envDir string 1317 it.Before(func() { 1318 envDir = filepath.Join(layersDir, "some-layer", "env.build") 1319 Expect(os.MkdirAll(envDir, os.ModePerm)).To(Succeed()) 1320 Expect(os.Chmod(envDir, 0000)).To(Succeed()) 1321 }) 1322 1323 it.After(func() { 1324 Expect(os.Chmod(envDir, os.ModePerm)).To(Succeed()) 1325 }) 1326 1327 it("calls the exit handler", func() { 1328 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1329 return packit.BuildResult{ 1330 Layers: []packit.Layer{{ 1331 Path: filepath.Join(layersDir, "some-layer"), 1332 BuildEnv: packit.Environment{ 1333 "SOME_VAR.override": "some-value", 1334 }, 1335 }}, 1336 }, nil 1337 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1338 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("permission denied"))) 1339 }) 1340 }) 1341 1342 context("LaunchEnv", func() { 1343 var envDir string 1344 it.Before(func() { 1345 envDir = filepath.Join(layersDir, "some-layer", "env.launch") 1346 Expect(os.MkdirAll(envDir, os.ModePerm)).To(Succeed()) 1347 Expect(os.Chmod(envDir, 0000)).To(Succeed()) 1348 }) 1349 1350 it.After(func() { 1351 Expect(os.Chmod(envDir, os.ModePerm)).To(Succeed()) 1352 }) 1353 1354 it("calls the exit handler", func() { 1355 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1356 return packit.BuildResult{ 1357 Layers: []packit.Layer{{ 1358 Path: filepath.Join(layersDir, "some-layer"), 1359 LaunchEnv: packit.Environment{ 1360 "SOME_VAR.override": "some-value", 1361 }, 1362 }}, 1363 }, nil 1364 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1365 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("permission denied"))) 1366 }) 1367 }) 1368 }) 1369 1370 context("when the launch sbom cannot be written", func() { 1371 it("calls the exit handler", func() { 1372 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1373 return packit.BuildResult{ 1374 Launch: packit.LaunchMetadata{ 1375 SBOM: packit.SBOMFormats{ 1376 { 1377 Extension: "some.json", 1378 Content: iotest.ErrReader(errors.New("failed to format launch sbom")), 1379 }, 1380 }, 1381 }, 1382 }, nil 1383 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1384 1385 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("failed to format launch sbom"))) 1386 }) 1387 }) 1388 1389 context("when the build sbom cannot be written", func() { 1390 it("calls the exit handler", func() { 1391 packit.Build(func(ctx packit.BuildContext) (packit.BuildResult, error) { 1392 return packit.BuildResult{ 1393 Build: packit.BuildMetadata{ 1394 SBOM: packit.SBOMFormats{ 1395 { 1396 Extension: "some.json", 1397 Content: iotest.ErrReader(errors.New("failed to format build sbom")), 1398 }, 1399 }, 1400 }, 1401 }, nil 1402 }, packit.WithArgs([]string{binaryPath, layersDir, platformDir, planPath}), packit.WithExitHandler(exitHandler)) 1403 1404 Expect(exitHandler.ErrorCall.Receives.Error).To(MatchError(ContainSubstring("failed to format build sbom"))) 1405 }) 1406 }) 1407 }) 1408 }