Compare commits

...

68 Commits

Author SHA1 Message Date
Daniel Mikusa 25ba7f615a
Update pipelines (#168)
- Updates to most recent pipeline-builder version
- Updates pipelines to use Go 1.18
- Updates pipelines to use 'go install' instead of 'go get'
- Adds a pipeline to check for and update Go versions & to check for transitive go.mod updates, which dependabot does not do

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
Co-authored-by: Sambhav Kothari <skothari44@bloomberg.net>
2022-08-19 17:28:46 +00:00
Daniel Mikusa 6305526cf8
Use curl to install richgo (#167)
This PR changes the workflow to use 'curl' to fetch and install richgo instead of 'go get'. We could switch to 'go install', but 'curl' is faster than fetching & building.

This is what the pipeline-builder project has been doing to install richgo for quite a while now.

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
2022-08-11 08:51:16 +01:00
Daniel Mikusa 2e5389a593
Ensure directories are created when process-specific env variables are used (#159)
* Ensure directories are created when process-specific env variables are used
* Add comment to explain the need for extra calls to makedirs

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>

Co-authored-by: Sambhav Kothari <skothari44@bloomberg.net>
2022-07-14 21:45:18 -04:00
Daniel Mikusa 587c59c91d
Bump go module dependencies (#161)
I do not believe that Dependabot is running against this branch, so we'll need to manually update them occasionally.

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
2022-07-14 21:44:07 +01:00
Buildpacks Robot 5f657b5cfc
Bump pipeline from 1.21.1 to 1.21.2 (#138)
Bumps pipeline from 1.21.1 to 1.21.2.

Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: buildpack-bot <buildpack-bot@users.noreply.github.com>
2022-04-20 07:18:12 +02:00
Buildpacks Robot 6e3b073b7b
Bump pipeline from 1.20.0 to 1.21.1 (#137)
Co-authored-by: buildpack-bot <buildpack-bot@users.noreply.github.com>
2022-04-12 10:23:26 +01:00
Sambhav Kothari 52e0183e1d
Add support for buildpack api 0.8 (#131) 2022-04-11 16:13:40 +01:00
dependabot[bot] 2f1a4584c6
Bump github.com/BurntSushi/toml from 1.0.0 to 1.1.0 (#136)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-09 12:44:21 +01:00
Gabe Cemaj 963d4bea64
Use semver to parse and check BP API versions (#134)
Signed-off-by: gcemaj <gcemaj@bloomberg.net>

Co-authored-by: gcemaj <gcemaj@bloomberg.net>
2022-04-07 21:53:45 +01:00
Sambhav Kothari 71c0efab66
Merge pull request #133 from gcemaj/gcemaj-launch-working-dir
Add support for working-directory in launch.toml (API>=0.8)
2022-04-05 22:11:45 +01:00
Sambhav Kothari 3d9ff459f6
Merge branch 'main' into gcemaj-launch-working-dir 2022-04-05 21:22:38 +01:00
Sambhav Kothari abe34281b4
Merge pull request #125 from buildpacks/dependabot/go_modules/github.com/stretchr/testify-1.7.1
Bump github.com/stretchr/testify from 1.7.0 to 1.7.1
2022-04-05 21:20:00 +01:00
Sambhav Kothari 8b98521c54
Merge branch 'main' into dependabot/go_modules/github.com/stretchr/testify-1.7.1 2022-04-05 21:16:53 +01:00
Sambhav Kothari e4b66fbc45
Merge pull request #135 from buildpacks/dependabot/go_modules/github.com/BurntSushi/toml-1.1.0
Bump github.com/BurntSushi/toml from 1.0.0 to 1.1.0
2022-04-05 21:09:25 +01:00
gcemaj 5c5fb9c447 [action] add working-directory to launch.toml (API>=0.8)
Signed-off-by: gcemaj <gcemaj@bloomberg.net>
2022-04-05 15:08:21 -04:00
dependabot[bot] 69cca5e154
Bump github.com/BurntSushi/toml from 1.0.0 to 1.1.0
Bumps [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml) from 1.0.0 to 1.1.0.
- [Release notes](https://github.com/BurntSushi/toml/releases)
- [Commits](https://github.com/BurntSushi/toml/compare/v1.0.0...v1.1.0)

---
updated-dependencies:
- dependency-name: github.com/BurntSushi/toml
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-05 19:03:25 +00:00
Sambhav Kothari a9e6d2093f
Merge branch 'main' into dependabot/go_modules/github.com/stretchr/testify-1.7.1 2022-04-02 02:00:39 +01:00
Sambhav Kothari 31fc6e39de
Merge pull request #129 from buildpacks/dependabot/go_modules/github.com/onsi/gomega-1.19.0
Bump github.com/onsi/gomega from 1.18.1 to 1.19.0
2022-04-02 02:00:21 +01:00
dependabot[bot] 8ebd909600
Bump github.com/onsi/gomega from 1.18.1 to 1.19.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.18.1 to 1.19.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.18.1...v1.19.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 19:05:28 +00:00
dependabot[bot] fdc1649156
Bump github.com/stretchr/testify from 1.7.0 to 1.7.1
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.0 to 1.7.1.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.7.0...v1.7.1)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-16 19:05:09 +00:00
Sambhav Kothari e2931f6866
Merge pull request #123 from buildpacks/update/pipeline
Bump pipeline from 1.19.0 to 1.20.0
2022-03-11 05:59:03 +00:00
buildpack-bot 007e6d2e3e Bump pipeline from 1.19.0 to 1.20.0
Bumps pipeline from 1.19.0 to 1.20.0.

Signed-off-by: GitHub <noreply@github.com>
2022-03-11 05:10:39 +00:00
Sambhav Kothari 0df8dedcfe
Merge pull request #118 from dmikusa-pivotal/deps-update 2022-03-03 19:03:31 +00:00
Daniel Mikusa 7ed3dc927c
Updates to go 1.17
Updates go.mod to use go 1.17 to unlock features in newer versions of Go.

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
2022-03-03 12:34:13 -05:00
Emily Casey bc167dd856
Merge pull request #117 from buildpacks/update/pipeline
Bump pipeline from 1.18.0 to 1.19.0
2022-02-25 09:50:17 -05:00
buildpack-bot 714a5dc525 Bump pipeline from 1.18.0 to 1.19.0
Bumps pipeline from 1.18.0 to 1.19.0.

Signed-off-by: GitHub <noreply@github.com>
2022-02-15 05:10:59 +00:00
Sambhav Kothari fdc252a082
Merge pull request #116 from buildpacks/update/pipeline
Bump pipeline from 1.17.0 to 1.18.0
2022-02-10 06:10:28 +00:00
buildpack-bot 62037e0b7a Bump pipeline from 1.17.0 to 1.18.0
Bumps pipeline from 1.17.0 to 1.18.0.

Signed-off-by: GitHub <noreply@github.com>
2022-02-10 05:10:51 +00:00
Sambhav Kothari 6a941db0cd
Merge pull request #115 from dmikusa-pivotal/lifecycle_0_13_3 2022-02-02 19:35:08 +00:00
Daniel Mikusa f496f6e88d
Adds WithBOMLabel Config Option to control writing BOM Labels
In some environments and with some applications, a long enough BOM label may be generated that it will either break Kubernetes or cause your application to fail to start. With the changes in lifecycle 0.13.3, we are enabling the BOM label again, but due to the issue above we also need a way for users to disable it if there are problems.

When running `libcnb.Build` you may now include an `Option` of `WithBOMLabel` that has an argument of either true or false. If not set, it defaults to false. This controls the output of libcnb.BOMEntry items in `launch.toml` and `build.toml`. If true, BOM entries are written. If false, BOM entries are not written, even if they are returned by the buildpack.

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
2022-02-01 14:08:07 -05:00
Daniel Mikusa 86ede05ba0
Permit both BOM formats at the same time
Starting with lifecycle 0.13.3, it is permitted to have both the old style label-based BOM information and the new style layer-based BOM information. If the buildpack API is 0.6 or older, label-based BOMs only is OK. If the buildpack API is 0.7, you may have both label-based BOM and layer-based BOM or just layer-based BOM. It is permitted to have just label-based BOM, however, that will generate a warning from the lifecycle.

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
2022-01-31 09:50:30 -05:00
Sambhav Kothari d3e6e18255
Merge pull request #114 from buildpacks/dependabot/go_modules/github.com/onsi/gomega-1.18.1
Bump github.com/onsi/gomega from 1.18.0 to 1.18.1
2022-01-28 21:35:41 +00:00
dependabot[bot] a0a8708c7a
Bump github.com/onsi/gomega from 1.18.0 to 1.18.1
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.18.0 to 1.18.1.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.18.0...v1.18.1)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-28 19:02:39 +00:00
Sambhav Kothari 53c63e4082
Merge pull request #112 from buildpacks/dependabot/go_modules/github.com/onsi/gomega-1.18.0
Bump github.com/onsi/gomega from 1.17.0 to 1.18.0
2022-01-24 23:00:38 +00:00
dependabot[bot] df6fd7ca71
Bump github.com/onsi/gomega from 1.17.0 to 1.18.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.17.0 to 1.18.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.17.0...v1.18.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-24 19:06:33 +00:00
Sambhav Kothari d91d62a519
Merge pull request #111 from buildpacks/update/pipeline
Bump pipeline from 1.16.0 to 1.17.0
2022-01-24 07:42:44 +00:00
buildpack-bot 4d89af3641 Bump pipeline from 1.16.0 to 1.17.0
Bumps pipeline from 1.16.0 to 1.17.0.

Signed-off-by: GitHub <noreply@github.com>
2022-01-24 05:10:12 +00:00
Sambhav Kothari f4abcd0215
Merge pull request #110 from buildpacks/dependabot/go_modules/github.com/BurntSushi/toml-1.0.0 2022-01-12 19:08:04 +00:00
dependabot[bot] f04e4e2cf2
Bump github.com/BurntSushi/toml from 0.4.1 to 1.0.0
Bumps [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml) from 0.4.1 to 1.0.0.
- [Release notes](https://github.com/BurntSushi/toml/releases)
- [Commits](https://github.com/BurntSushi/toml/compare/v0.4.1...v1.0.0)

---
updated-dependencies:
- dependency-name: github.com/BurntSushi/toml
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-12 19:03:14 +00:00
Sambhav Kothari 49c96bbc6c
Merge pull request #109 from buildpacks/samj1912-patch-1 2022-01-11 18:40:07 +00:00
Sambhav Kothari 2d891dd194
Only validate for API versions 0.5 and 0.6
libcnb is only supported for versions 0.5+ and we check for it a few lines above. Removing some unnecessary checks

Signed-off-by: Sambhav Kothari <skothari44@bloomberg.net>
2022-01-11 18:20:04 +00:00
Sambhav Kothari 896a63b4e3
Merge pull request #108 from dmikusa-pivotal/gh_issue_107 2022-01-11 18:15:26 +00:00
Daniel Mikusa 45c858b545
Validation should only occur under API 0.7
- Adds API checks before validating SBOM format, should only happen with API 0.7+
- Adds a test to confirm validation does not run if the API is less than 0.7.

Resolves #107

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
2022-01-10 16:36:14 -05:00
Sambhav Kothari c9ad73fb07
Merge pull request #106 from buildpacks/binding
Use appropriate bindings path for detect
2022-01-06 19:58:38 +00:00
Sambhav Kothari f869c1d937
Use appropriate bindings path for detect
Signed-off-by: Sambhav Kothari <skothari44@bloomberg.net>
2022-01-05 22:21:53 +00:00
Sambhav Kothari 4a789fd9d2
Merge pull request #100 from buildpacks/update/pipeline
Bump pipeline from 1.15.1 to 1.16.0
2021-12-06 09:21:08 +00:00
buildpack-bot d67b3ffea7 Bump pipeline from 1.15.1 to 1.16.0
Bumps pipeline from 1.15.1 to 1.16.0.

Signed-off-by: GitHub <noreply@github.com>
2021-12-06 05:11:25 +00:00
Sambhav Kothari 128cdb9dbe
Merge pull request #99 from dmikusa-pivotal/sbom-bug
Fixes bug with Warning message regarding SBOM format
2021-11-29 23:10:52 +00:00
Daniel Mikusa 77cb45d022
Fixes bug with Warning message regarding SBOM format
In the current implementation, it is possible for the `Warning: this buildpack is including both old and new format SBOM...` message to be triggered incorrectly. The warning is displayed if the launch or build object are not empty & if the API is `0.7`. This isn't right though. If you have no SBOM entries, but you have process types or labels, then it would be not empty & you'd see this message incorrectly.

This PR adjust the criteria such that you'll see this warning message if launch or build are not empty, if API is `0.7` and if BOM entries is not empty.

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
2021-11-29 16:35:16 -05:00
Sambhav Kothari a33b3677ad
Merge pull request #98 from buildpacks/polish-pr-97
Polish PR: Additional updates for SBOM Support
2021-11-24 08:34:09 +00:00
Sambhav Kothari 6d86013d6d Make validate SBOM private
Signed-off-by: Sambhav Kothari <skothari44@bloomberg.net>
2021-11-23 18:52:42 +00:00
Daniel Mikusa 66f3e9f328
Additional updates for SBOM Support
- Adds SBOMFormats (maps to `sbom-formats` in buildpack.toml) to the BuildpackInfo struct. This makes the information accessible to buildpacks.
- Modifies build such that it only writes the old-style build and launch BOM information if the buildpack API is less than 0.7. If it's 0.7+, it should not write the old style format as that can conflict with the new SBOM format and cause the lifecycle to fail. Omits a warning message if this occurs.
- Adds validation of the new SBOM files that are written by a buildpack. We check that the extension matches up with a valid MIME type that is listed in buildpack.toml's `sbom-formats` field. If it does not match up, then it fails. This should not generally happen with published buildpacks. This check can be helpful while authoring buildpacks, to ensure everything is correctly setup.

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
Co-authored-by: Sambhav Kothari <sambhavs.email@gmail.com>
Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
2021-11-20 21:35:28 -05:00
Sambhav Kothari 6aa81e5081
Merge pull request #95 from dmikusa-pivotal/bom-rfc-95
Adds a convenience method for getting the build, launch and layer BOM file paths
2021-11-18 03:15:25 +00:00
Daniel Mikusa c06fd640c3
Adds a convenience method for getting the build, launch and layer BOM file paths
This PR includes:

- convenience methods on the Layers and Layer object for fetching the SBoM path
- deprecated messages if using old-style BOM functionality

Co-authored-by: Sambhav Kothari <sambhavs.email@gmail.com>
Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
2021-11-17 20:44:18 -05:00
Sambhav Kothari 50e1696404
Merge pull request #92 from buildpacks/update/pipeline
Bump pipeline from 1.13.0 to 1.15.1
2021-11-12 09:18:45 +00:00
buildpack-bot 9cb9a2095d Bump pipeline from 1.13.0 to 1.15.1
Bumps pipeline from 1.13.0 to 1.15.1.

Signed-off-by: GitHub <noreply@github.com>
2021-11-12 05:10:26 +00:00
Sambhav Kothari 0376b8a285
Merge pull request #94 from dmikusa-pivotal/api-07 2021-11-11 21:14:11 +00:00
Daniel Mikusa 9af239f94c
Updates libcnb to support buildpacks API 0.7
Buildpacks API 0.7 brings one new feature, the functionality for SBoM output through [RFC #95](https://github.com/buildpacks/rfcs/blob/main/text/0095-sbom.md).

Without this change, you can write the SBoM information as described in RFC #95, but the lifecycle will ignore it. To make the lifecycle capture your SBoM information you need to:
1. Use a version of libcnb with this PR.
2. Update the `api = "0.8"` line in your buildpack.toml.
3. Write the SBoM files from your buildpack according to the locations in RFC #95. Libcnb does not provide any help with this activity presently, it is up to the buildpack author.
4. Use a lifecycle version with support, 0.13.0+
5. Use a pack version with platform API 0.8+

The lifecycle should then copy your SBoM files and include them into the image.

This PR is only required because the current implementation restricts usage of libcnb to specific buildpack API versions and we needed to add 0.7 to this list.

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
2021-11-11 13:02:54 -05:00
Sambhav Kothari 70403787d2
Merge pull request #91 from buildpacks/update/pipeline
Bump pipeline from 1.12.1 to 1.13.0
2021-11-09 05:54:29 +00:00
buildpack-bot ced0ee6ed8 Bump pipeline from 1.12.1 to 1.13.0
Bumps pipeline from 1.12.1 to 1.13.0.

Signed-off-by: GitHub <noreply@github.com>
2021-11-09 05:10:07 +00:00
Sambhav Kothari c564678891
Merge pull request #90 from buildpacks/dependabot/go_modules/github.com/onsi/gomega-1.17.0
Bump github.com/onsi/gomega from 1.16.0 to 1.17.0
2021-11-08 23:16:52 +00:00
dependabot[bot] 5c9b56b7c6
Bump github.com/onsi/gomega from 1.16.0 to 1.17.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.16.0...v1.17.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-08 19:04:45 +00:00
Sambhav Kothari 8c10662dc7
Merge pull request #86 from jghiloni/issue-85
Add struct tag to Buildpack.Path field
2021-11-04 22:15:53 +00:00
Josh Ghiloni b2b6b4b4c1
Make substring match more explicit in buildpack toml test
Signed-off-by: Josh Ghiloni <jghiloni@vmware.com>
2021-11-04 13:33:50 -04:00
Josh Ghiloni 33e2828ac7
Omit Path field from serialization altogether
Signed-off-by: Josh Ghiloni <jghiloni@vmware.com>
2021-11-04 11:20:26 -04:00
Josh Ghiloni a965403652
Add struct tag to Buildpack.Path field
Most Go applications use github.com/burntsushi/toml as their toml
parsing library. When struct tags are omitted, the library will do
case-insensitive deserialization, so a property called "path" will
successfully unmarshal into the Path struct field. However, if you
marshal a Buildpack instance to toml, the "Path = " field appears
regardless of whether it is set or not, and technically violates the
buildpack toml spec. This PR adds a struct tag to not only marshal the
field to the "path" property in the resultant toml, but also adds the
"omitempty" modifier to ignore the field altogether when not set.

Signed-off-by: Josh Ghiloni <jghiloni@vmware.com>
2021-11-04 10:21:07 -04:00
Sambhav Kothari bc6e6ca9a4
Merge pull request #84 from buildpacks/update/pipeline
Bump pipeline from 1.12.0 to 1.12.1
2021-11-04 07:08:48 +00:00
buildpack-bot 536a77887b Bump pipeline from 1.12.0 to 1.12.1
Bumps pipeline from 1.12.0 to 1.12.1.

Signed-off-by: GitHub <noreply@github.com>
2021-11-04 05:09:37 +00:00
28 changed files with 1748 additions and 376 deletions

View File

@ -14,7 +14,19 @@ test:
set -euo pipefail
GO111MODULE=on go get -u -ldflags="-s -w" github.com/kyoh86/richgo
echo "Installing richgo ${RICHGO_VERSION}"
mkdir -p "${HOME}"/bin
echo "${HOME}/bin" >> "${GITHUB_PATH}"
curl \
--location \
--show-error \
--silent \
"https://github.com/kyoh86/richgo/releases/download/v${RICHGO_VERSION}/richgo_${RICHGO_VERSION}_linux_amd64.tar.gz" \
| tar -C "${HOME}"/bin -xz richgo
env:
RICHGO_VERSION: 0.3.10
- name: Run Tests
run: |
#!/usr/bin/env bash

View File

@ -1 +1 @@
1.12.0
1.25.2

View File

@ -1 +0,0 @@
1.4.0

View File

@ -12,7 +12,7 @@ jobs:
runs-on:
- ubuntu-latest
steps:
- uses: mheap/github-action-required-labels@v1
- uses: mheap/github-action-required-labels@v2
with:
count: 1
labels: semver:major, semver:minor, semver:patch
@ -22,7 +22,7 @@ jobs:
runs-on:
- ubuntu-latest
steps:
- uses: mheap/github-action-required-labels@v1
- uses: mheap/github-action-required-labels@v2
with:
count: 1
labels: type:bug, type:dependency-upgrade, type:documentation, type:enhancement, type:question, type:task

View File

@ -2,7 +2,7 @@ name: Synchronize Labels
"on":
push:
branches:
- main
- release-1.x
paths:
- .github/labels.yml
jobs:
@ -11,7 +11,7 @@ jobs:
runs-on:
- ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: micnncim/action-label-syncer@v1
env:
GITHUB_TOKEN: ${{ secrets.IMPLEMENTATION_GITHUB_TOKEN }}

View File

@ -3,29 +3,41 @@ name: Tests
pull_request: {}
push:
branches:
- main
- release-1.x
jobs:
unit:
name: Unit Test
runs-on:
- ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
path: ${{ env.HOME }}/go/pkg/mod
restore-keys: ${{ runner.os }}-go-
- uses: actions/setup-go@v2
- uses: actions/setup-go@v3
with:
go-version: "1.16"
go-version: "1.18"
- name: Install richgo
run: |
#!/usr/bin/env bash
set -euo pipefail
GO111MODULE=on go get -u -ldflags="-s -w" github.com/kyoh86/richgo
echo "Installing richgo ${RICHGO_VERSION}"
mkdir -p "${HOME}"/bin
echo "${HOME}/bin" >> "${GITHUB_PATH}"
curl \
--location \
--show-error \
--silent \
"https://github.com/kyoh86/richgo/releases/download/v${RICHGO_VERSION}/richgo_${RICHGO_VERSION}_linux_amd64.tar.gz" \
| tar -C "${HOME}"/bin -xz richgo
env:
RICHGO_VERSION: 0.3.10
- name: Run Tests
run: |
#!/usr/bin/env bash

View File

@ -2,7 +2,7 @@ name: Update Draft Release
"on":
push:
branches:
- main
- release-1.x
jobs:
update:
name: Update Draft Release

61
.github/workflows/pb-update-go.yml vendored Normal file
View File

@ -0,0 +1,61 @@
name: Update Go
"on":
schedule:
- cron: 0 2 * * 1
workflow_dispatch: {}
jobs:
update:
name: Update Go
runs-on:
- ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: "1.18"
- uses: actions/checkout@v3
- name: Update Go Version
id: update-go
run: |
#!/usr/bin/env bash
set -euo pipefail
if [ -z "${GO_VERSION:-}" ]; then
echo "No go version set"
exit 1
fi
OLD_GO_VERSION=$(grep -P '^go \d\.\d+' go.mod | cut -d ' ' -f 2)
go mod edit -go="$GO_VERSION"
go mod tidy
go get -u all
go mod tidy
git add go.mod go.sum
git checkout -- .
echo "::set-output name=old-go-version::${OLD_GO_VERSION}"
echo "::set-output name=go-version::${GO_VERSION}"
env:
GO_VERSION: "1.18"
- uses: peter-evans/create-pull-request@v4
with:
author: ${{ secrets.IMPLEMENTATION_GITHUB_USERNAME }} <${{ secrets.IMPLEMENTATION_GITHUB_USERNAME }}@users.noreply.github.com>
body: |-
Bumps Go from `${{ steps.update-go.outputs.old-go-version }}` to `${{ steps.update-go.outputs.go-version }}`.
<details>
<summary>Release Notes</summary>
${{ steps.pipeline.outputs.release-notes }}
</details>
branch: update/go
commit-message: |-
Bump Go from ${{ steps.update-go.outputs.old-go-version }} to ${{ steps.update-go.outputs.go-version }}
Bumps Go from ${{ steps.update-go.outputs.old-go-version }} to ${{ steps.update-go.outputs.go-version }}.
delete-branch: true
labels: semver:minor, type:task
signoff: true
title: Bump Go from ${{ steps.update-go.outputs.old-go-version }} to ${{ steps.update-go.outputs.go-version }}
token: ${{ secrets.IMPLEMENTATION_GITHUB_TOKEN }}

View File

@ -2,7 +2,7 @@ name: Update Pipeline
"on":
push:
branches:
- main
- release-1.x
paths:
- .github/pipeline-descriptor.yml
schedule:
@ -14,17 +14,17 @@ jobs:
runs-on:
- ubuntu-latest
steps:
- uses: actions/setup-go@v2
- uses: actions/setup-go@v3
with:
go-version: "1.16"
go-version: "1.18"
- name: Install octo
run: |
#!/usr/bin/env bash
set -euo pipefail
GO111MODULE=on go get -u -ldflags="-s -w" github.com/paketo-buildpacks/pipeline-builder/cmd/octo
- uses: actions/checkout@v2
go install -ldflags="-s -w" github.com/paketo-buildpacks/pipeline-builder/cmd/octo@latest
- uses: actions/checkout@v3
- name: Update Pipeline
id: pipeline
run: |
@ -38,6 +38,7 @@ jobs:
OLD_VERSION="0.0.0"
fi
rm .github/workflows/pb-*.yml || true
octo --descriptor "${DESCRIPTOR}"
PAYLOAD=$(gh api /repos/paketo-buildpacks/pipeline-builder/releases/latest)
@ -62,7 +63,7 @@ jobs:
env:
DESCRIPTOR: .github/pipeline-descriptor.yml
GITHUB_TOKEN: ${{ secrets.IMPLEMENTATION_GITHUB_TOKEN }}
- uses: peter-evans/create-pull-request@v3
- uses: peter-evans/create-pull-request@v4
with:
author: ${{ secrets.IMPLEMENTATION_GITHUB_USERNAME }} <${{ secrets.IMPLEMENTATION_GITHUB_USERNAME }}@users.noreply.github.com>
body: |-

View File

@ -48,6 +48,9 @@ type Process struct {
// Command is exec'd directly by the os (no profile.d scripts run)
Direct bool `toml:"direct,omitempty"`
// WorkingDirectory is a directory to execute the command in, removes the need to use a shell environment to CD into working directory
WorkingDirectory string `toml:"working-directory,omitempty"`
// Default can be set to true to indicate that the process
// type being defined should be the default process type for the app image.
Default bool `toml:"default,omitempty"`
@ -73,6 +76,8 @@ type LaunchTOML struct {
Slices []Slice `toml:"slices"`
// BOM is a collection of entries for the bill of materials.
//
// Deprecated: as of Buildpack API 0.7, write to `layer.BOMPath()` instead
BOM []BOMEntry `toml:"bom"`
}
@ -83,6 +88,8 @@ func (l LaunchTOML) isEmpty() bool {
// BuildTOML represents the contents of build.toml.
type BuildTOML struct {
// BOM contains the build-time bill of materials.
//
// Deprecated: as of Buildpack API 0.7, write to `layer.BOMPath()` instead
BOM []BOMEntry `toml:"bom"`
// Unmet is a collection of buildpack plan entries that should be passed through to subsequent providers.
@ -94,6 +101,8 @@ func (b BuildTOML) isEmpty() bool {
}
// BOMEntry contains a bill of materials entry.
//
// Deprecated: as of Buildpack API 0.7, BOM should use standard formats like CycloneDX going forward
type BOMEntry struct {
// Name represents the name of the entry.
Name string `toml:"name"`

116
build.go
View File

@ -25,6 +25,7 @@ import (
"strings"
"github.com/BurntSushi/toml"
"github.com/Masterminds/semver/v3"
"github.com/buildpacks/libcnb/internal"
"github.com/buildpacks/libcnb/poet"
@ -58,6 +59,8 @@ type BuildContext struct {
// BuildResult contains the results of detection.
type BuildResult struct {
// BOM contains entries to be appended to the app image Bill of Materials and/or build Bill of Materials.
//
// Deprecated: as of Buildpack API 0.7, write to `layer.BOMPath()` instead
BOM *BOM
// Labels are the image labels contributed by the buildpack.
@ -81,10 +84,21 @@ type BuildResult struct {
}
// BOM contains all Bill of Materials entries
//
// Deprecated: as of Buildpack API 0.7, write to `layer.BOMPath()` instead
type BOM struct {
Entries []BOMEntry
}
// Constants to track minimum and maximum supported Buildpack API versions
const (
// MinSupportedBPVersion indicates the minium supported version of the Buildpacks API
MinSupportedBPVersion = "0.5"
// MaxSupportedBPVersion indicates the maximum supported version of the Buildpacks API
MaxSupportedBPVersion = "0.8"
)
// NewBuildResult creates a new BuildResult instance, initializing empty fields.
func NewBuildResult() BuildResult {
return BuildResult{
@ -118,6 +132,7 @@ type Builder interface {
func Build(builder Builder, options ...Option) {
config := Config{
arguments: os.Args,
bomLabel: false,
environmentWriter: internal.EnvironmentWriter{},
exitHandler: internal.NewExitHandler(),
tomlWriter: internal.TOMLWriter{},
@ -127,11 +142,6 @@ func Build(builder Builder, options ...Option) {
config = option(config)
}
if len(config.arguments) != 4 {
config.exitHandler.Error(fmt.Errorf("expected 3 arguments and received %d", len(config.arguments)-1))
return
}
var (
err error
file string
@ -165,16 +175,47 @@ func Build(builder Builder, options ...Option) {
}
logger.Debugf("Buildpack: %+v", ctx.Buildpack)
API := strings.TrimSpace(ctx.Buildpack.API)
if API != "0.5" && API != "0.6" {
config.exitHandler.Error(errors.New("this version of libcnb is only compatible with buildpack APIs 0.5 and 0.6"))
API, err := semver.NewVersion(ctx.Buildpack.API)
if err != nil {
config.exitHandler.Error(errors.New("version cannot be parsed"))
return
}
ctx.Layers = Layers{config.arguments[1]}
logger.Debugf("Layers: %+v", ctx.Layers)
compatVersionCheck, _ := semver.NewConstraint(fmt.Sprintf(">= %s, <= %s", MinSupportedBPVersion, MaxSupportedBPVersion))
if !compatVersionCheck.Check(API) {
config.exitHandler.Error(fmt.Errorf("this version of libcnb is only compatible with buildpack APIs >= %s, <= %s", MinSupportedBPVersion, MaxSupportedBPVersion))
return
}
var buildpackPlanPath string
ctx.Platform.Path = config.arguments[2]
if API.LessThan(semver.MustParse("0.8")) {
if len(config.arguments) != 4 {
config.exitHandler.Error(fmt.Errorf("expected 3 arguments and received %d", len(config.arguments)-1))
return
}
ctx.Layers = Layers{config.arguments[1]}
ctx.Platform.Path = config.arguments[2]
buildpackPlanPath = config.arguments[3]
} else {
layersDir, ok := os.LookupEnv("CNB_LAYERS_DIR")
if !ok {
config.exitHandler.Error(fmt.Errorf("expected CNB_LAYERS_DIR to be set"))
return
}
ctx.Layers = Layers{layersDir}
ctx.Platform.Path, ok = os.LookupEnv("CNB_PLATFORM_DIR")
if !ok {
config.exitHandler.Error(fmt.Errorf("expected CNB_PLATFORM_DIR to be set"))
return
}
buildpackPlanPath, ok = os.LookupEnv("CNB_BP_PLAN_PATH")
if !ok {
config.exitHandler.Error(fmt.Errorf("expected CNB_BP_PLAN_PATH to be set"))
return
}
}
logger.Debugf("Layers: %+v", ctx.Layers)
if logger.IsDebugEnabled() {
logger.Debug(PlatformFormatter(ctx.Platform))
}
@ -201,9 +242,8 @@ func Build(builder Builder, options ...Option) {
ctx.PersistentMetadata = store.Metadata
logger.Debugf("Persistent Metadata: %+v", ctx.PersistentMetadata)
file = config.arguments[3]
if _, err = toml.DecodeFile(file, &ctx.Plan); err != nil && !os.IsNotExist(err) {
config.exitHandler.Error(fmt.Errorf("unable to decode buildpack plan %s\n%w", file, err))
if _, err = toml.DecodeFile(buildpackPlanPath, &ctx.Plan); err != nil && !os.IsNotExist(err) {
config.exitHandler.Error(fmt.Errorf("unable to decode buildpack plan %s\n%w", buildpackPlanPath, err))
return
}
logger.Debugf("Buildpack Plan: %+v", ctx.Plan)
@ -274,7 +314,7 @@ func Build(builder Builder, options ...Option) {
file = filepath.Join(ctx.Layers.Path, fmt.Sprintf("%s.toml", layer.Name))
logger.Debugf("Writing layer metadata: %s <= %+v", file, layer)
var toWrite interface{} = layer
if API == "0.5" {
if API.Equal(semver.MustParse("0.5")) {
toWrite = internal.LayerAPI5{
Build: layer.LayerTypes.Build,
Cache: layer.LayerTypes.Cache,
@ -302,8 +342,16 @@ func Build(builder Builder, options ...Option) {
}
}
if API.GreaterThan(semver.MustParse("0.7")) || API.Equal(semver.MustParse("0.7")) {
if err := validateSBOMFormats(ctx.Layers.Path, ctx.Buildpack.Info.SBOMFormats); err != nil {
config.exitHandler.Error(fmt.Errorf("unable to validate SBOM\n%w", err))
return
}
}
// Deprecated: as of Buildpack API 0.7, to be removed in a future version
var launchBOM, buildBOM []BOMEntry
if result.BOM != nil {
if result.BOM != nil && config.bomLabel {
for _, entry := range result.BOM.Entries {
if entry.Launch {
launchBOM = append(launchBOM, entry)
@ -325,7 +373,7 @@ func Build(builder Builder, options ...Option) {
file = filepath.Join(ctx.Layers.Path, "launch.toml")
logger.Debugf("Writing application metadata: %s <= %+v", file, launch)
if API == "0.5" {
if API.LessThan(semver.MustParse("0.6")) {
for _, process := range launch.Processes {
if process.Default {
logger.Info("WARNING: Launch layer is setting default=true, but that is not supported until API version 0.6. This setting will be ignored.")
@ -333,6 +381,15 @@ func Build(builder Builder, options ...Option) {
}
}
if API.LessThan(semver.MustParse("0.8")) {
for i, process := range launch.Processes {
if process.WorkingDirectory != "" {
logger.Infof("WARNING: Launch layer is setting working-directory=%s, but that is not supported until API version 0.8. This setting will be ignored.", process.WorkingDirectory)
launch.Processes[i].WorkingDirectory = ""
}
}
}
if err = config.tomlWriter.Write(file, launch); err != nil {
config.exitHandler.Error(fmt.Errorf("unable to write application metadata %s\n%w", file, err))
return
@ -347,6 +404,7 @@ func Build(builder Builder, options ...Option) {
if !build.isEmpty() {
file = filepath.Join(ctx.Layers.Path, "build.toml")
logger.Debugf("Writing build metadata: %s <= %+v", file, build)
if err = config.tomlWriter.Write(file, build); err != nil {
config.exitHandler.Error(fmt.Errorf("unable to write build metadata %s\n%w", file, err))
return
@ -375,3 +433,27 @@ func contains(candidates []string, s string) bool {
return false
}
func validateSBOMFormats(layersPath string, acceptedSBOMFormats []string) error {
sbomFiles, err := filepath.Glob(filepath.Join(layersPath, "*.sbom.*"))
if err != nil {
return fmt.Errorf("unable find SBOM files\n%w", err)
}
for _, sbomFile := range sbomFiles {
parts := strings.Split(filepath.Base(sbomFile), ".")
if len(parts) <= 2 {
return fmt.Errorf("invalid format %s", filepath.Base(sbomFile))
}
sbomFormat, err := SBOMFormatFromString(strings.Join(parts[len(parts)-2:], "."))
if err != nil {
return fmt.Errorf("unable to parse SBOM %s\n%w", sbomFormat, err)
}
if !contains(acceptedSBOMFormats, sbomFormat.MediaType()) {
return fmt.Errorf("unable to find actual SBOM Type %s in list of supported SBOM types %s", sbomFormat.MediaType(), acceptedSBOMFormats)
}
}
return nil
}

View File

@ -163,6 +163,9 @@ test-key = "test-value"
tomlWriter.On("Write", mock.Anything, mock.Anything).Return(nil)
Expect(os.Setenv("CNB_STACK_ID", "test-stack-id")).To(Succeed())
Expect(os.Setenv("CNB_LAYERS_DIR", layersPath)).To(Succeed())
Expect(os.Setenv("CNB_PLATFORM_DIR", platformPath)).To(Succeed())
Expect(os.Setenv("CNB_BP_PLAN_PATH", buildpackPlanPath)).To(Succeed())
workingDir, err = os.Getwd()
Expect(err).NotTo(HaveOccurred())
@ -173,6 +176,9 @@ test-key = "test-value"
Expect(os.Chdir(workingDir)).To(Succeed())
Expect(os.Unsetenv("CNB_BUILDPACK_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_STACK_ID")).To(Succeed())
Expect(os.Unsetenv("CNB_PLATFORM_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_BP_PLAN_PATH")).To(Succeed())
Expect(os.Unsetenv("CNB_LAYERS_DIR")).To(Succeed())
Expect(os.RemoveAll(applicationPath)).To(Succeed())
Expect(os.RemoveAll(buildpackPath)).To(Succeed())
@ -181,7 +187,7 @@ test-key = "test-value"
Expect(os.RemoveAll(platformPath)).To(Succeed())
})
context("buildpack API is not 0.5 or 0.6", func() {
context("buildpack API is not within the supported range", func() {
it.Before(func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
@ -198,20 +204,56 @@ version = "1.1.1"
it("fails", func() {
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(
"this version of libcnb is only compatible with buildpack APIs 0.5 and 0.6",
fmt.Sprintf("this version of libcnb is only compatible with buildpack APIs >= %s, <= %s", libcnb.MinSupportedBPVersion, libcnb.MaxSupportedBPVersion),
))
})
})
context("errors if required env vars are not set for buildpack API >=0.8", func() {
for _, e := range []string{"CNB_LAYERS_DIR", "CNB_PLATFORM_DIR", "CNB_BP_PLAN_PATH"} {
// We need to do this assignment because of the way that spec binds variables
envVar := e
context(fmt.Sprintf("when %s is unset", envVar), func() {
it.Before(func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
api = "0.8"
[buildpack]
id = "test-id"
name = "test-name"
version = "1.1.1"
`),
0600),
).To(Succeed())
os.Unsetenv(envVar)
})
it("fails", func() {
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath}),
libcnb.WithExitHandler(exitHandler),
)
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(
fmt.Sprintf("expected %s to be set", envVar),
))
})
})
}
})
it("encounters the wrong number of arguments", func() {
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath}),
libcnb.WithExitHandler(exitHandler),
)
@ -224,6 +266,7 @@ version = "1.1.1"
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
@ -231,64 +274,136 @@ version = "1.1.1"
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError("CNB_STACK_ID not set"))
})
it("creates context", func() {
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)
context("when BP API >= 0.8", func() {
it.Before(func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
api = "0.8"
[buildpack]
id = "test-id"
name = "test-name"
version = "1.1.1"
`),
0600),
).To(Succeed())
})
libcnb.Build(builder,
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
)
it("creates context", func() {
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)
ctx := builder.Calls[0].Arguments[0].(libcnb.BuildContext)
Expect(ctx.Application).To(Equal(libcnb.Application{Path: applicationPath}))
Expect(ctx.Buildpack).To(Equal(libcnb.Buildpack{
API: "0.6",
Info: libcnb.BuildpackInfo{
ID: "test-id",
Name: "test-name",
Version: "1.1.1",
ClearEnvironment: true,
Description: "A test buildpack",
Keywords: []string{"test", "buildpack"},
Licenses: []libcnb.License{
{Type: "Apache-2.0", URI: "https://spdx.org/licenses/Apache-2.0.html"},
{Type: "Apache-1.1", URI: "https://spdx.org/licenses/Apache-1.1.html"},
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath}),
)
ctx := builder.Calls[0].Arguments[0].(libcnb.BuildContext)
Expect(ctx.Application).To(Equal(libcnb.Application{Path: applicationPath}))
Expect(ctx.Buildpack).To(Equal(libcnb.Buildpack{
API: "0.8",
Info: libcnb.BuildpackInfo{
ID: "test-id",
Name: "test-name",
Version: "1.1.1",
},
},
Path: buildpackPath,
Stacks: []libcnb.BuildpackStack{
{
ID: "test-id",
Mixins: []string{"test-name"},
},
},
Metadata: map[string]interface{}{"test-key": "test-value"},
}))
Expect(ctx.Layers).To(Equal(libcnb.Layers{Path: layersPath}))
Expect(ctx.PersistentMetadata).To(Equal(map[string]interface{}{"test-key": "test-value"}))
Expect(ctx.Plan).To(Equal(libcnb.BuildpackPlan{
Entries: []libcnb.BuildpackPlanEntry{
{
Name: "test-name",
Metadata: map[string]interface{}{
"test-key": "test-value",
Path: buildpackPath,
}))
Expect(ctx.Layers).To(Equal(libcnb.Layers{Path: layersPath}))
Expect(ctx.PersistentMetadata).To(Equal(map[string]interface{}{"test-key": "test-value"}))
Expect(ctx.Plan).To(Equal(libcnb.BuildpackPlan{
Entries: []libcnb.BuildpackPlanEntry{
{
Name: "test-name",
Metadata: map[string]interface{}{
"test-key": "test-value",
},
},
},
},
}))
Expect(ctx.Platform).To(Equal(libcnb.Platform{
Bindings: libcnb.Bindings{
libcnb.Binding{
Name: "alpha",
Path: filepath.Join(platformPath, "bindings", "alpha"),
Secret: map[string]string{
"test-secret-key": "test-secret-value",
}))
Expect(ctx.Platform).To(Equal(libcnb.Platform{
Bindings: libcnb.Bindings{
libcnb.Binding{
Name: "alpha",
Path: filepath.Join(platformPath, "bindings", "alpha"),
Secret: map[string]string{
"test-secret-key": "test-secret-value",
},
},
},
},
Environment: map[string]string{"TEST_ENV": "test-value"},
Path: platformPath,
}))
Expect(ctx.StackID).To(Equal("test-stack-id"))
Environment: map[string]string{"TEST_ENV": "test-value"},
Path: platformPath,
}))
Expect(ctx.StackID).To(Equal("test-stack-id"))
})
})
context("when BP API < 0.8", func() {
it.Before(func() {
Expect(os.Unsetenv("CNB_PLATFORM_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_BP_PLAN_PATH")).To(Succeed())
Expect(os.Unsetenv("CNB_LAYERS_DIR")).To(Succeed())
})
it("creates context", func() {
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
)
ctx := builder.Calls[0].Arguments[0].(libcnb.BuildContext)
Expect(ctx.Application).To(Equal(libcnb.Application{Path: applicationPath}))
Expect(ctx.Buildpack).To(Equal(libcnb.Buildpack{
API: "0.6",
Info: libcnb.BuildpackInfo{
ID: "test-id",
Name: "test-name",
Version: "1.1.1",
ClearEnvironment: true,
Description: "A test buildpack",
Keywords: []string{"test", "buildpack"},
Licenses: []libcnb.License{
{Type: "Apache-2.0", URI: "https://spdx.org/licenses/Apache-2.0.html"},
{Type: "Apache-1.1", URI: "https://spdx.org/licenses/Apache-1.1.html"},
},
},
Path: buildpackPath,
Stacks: []libcnb.BuildpackStack{
{
ID: "test-id",
Mixins: []string{"test-name"},
},
},
Metadata: map[string]interface{}{"test-key": "test-value"},
}))
Expect(ctx.Layers).To(Equal(libcnb.Layers{Path: layersPath}))
Expect(ctx.PersistentMetadata).To(Equal(map[string]interface{}{"test-key": "test-value"}))
Expect(ctx.Plan).To(Equal(libcnb.BuildpackPlan{
Entries: []libcnb.BuildpackPlanEntry{
{
Name: "test-name",
Metadata: map[string]interface{}{
"test-key": "test-value",
},
},
},
}))
Expect(ctx.Platform).To(Equal(libcnb.Platform{
Bindings: libcnb.Bindings{
libcnb.Binding{
Name: "alpha",
Path: filepath.Join(platformPath, "bindings", "alpha"),
Secret: map[string]string{
"test-secret-key": "test-secret-value",
},
},
},
Environment: map[string]string{"TEST_ENV": "test-value"},
Path: platformPath,
}))
Expect(ctx.StackID).To(Equal("test-stack-id"))
})
})
it("extracts buildpack path from command path if CNB_BUILDPACK_PATH is not set", func() {
@ -297,6 +412,7 @@ version = "1.1.1"
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{filepath.Join(buildpackPath, commandPath), layersPath, platformPath, buildpackPlanPath}),
)
@ -309,6 +425,7 @@ version = "1.1.1"
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), fmt.Errorf("test-error"))
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
@ -323,6 +440,7 @@ version = "1.1.1"
Return(libcnb.BuildResult{Layers: []libcnb.LayerContributor{layerContributor}}, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
@ -339,6 +457,7 @@ version = "1.1.1"
builder.On("Build", mock.Anything).Return(result, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithEnvironmentWriter(environmentWriter),
)
@ -356,6 +475,7 @@ version = "1.1.1"
builder.On("Build", mock.Anything).Return(result, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithEnvironmentWriter(environmentWriter),
)
@ -373,6 +493,7 @@ version = "1.1.1"
builder.On("Build", mock.Anything).Return(result, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithEnvironmentWriter(environmentWriter),
@ -391,6 +512,7 @@ version = "1.1.1"
builder.On("Build", mock.Anything).Return(result, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithEnvironmentWriter(environmentWriter),
)
@ -422,6 +544,7 @@ version = "1.1.1"
builder.On("Build", mock.Anything).Return(result, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
@ -453,6 +576,7 @@ version = "1.1.1"
builder.On("Build", mock.Anything).Return(result, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
@ -501,6 +625,7 @@ version = "1.1.1"
}, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
@ -535,12 +660,79 @@ version = "1.1.1"
}))
})
it("ignore working-directory setting and writes launch.toml (API<0.8)", func() {
builder.On("Build", mock.Anything).Return(libcnb.BuildResult{
Processes: []libcnb.Process{
{
Type: "test-type",
Command: "test-command-in-dir",
Default: true,
WorkingDirectory: "/my/directory/",
},
},
}, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
Expect(tomlWriter.Calls[0].Arguments[0]).To(Equal(filepath.Join(layersPath, "launch.toml")))
Expect(tomlWriter.Calls[0].Arguments[1]).To(Equal(libcnb.LaunchTOML{
Processes: []libcnb.Process{
{
Type: "test-type",
Command: "test-command-in-dir",
Default: true,
},
},
}))
})
it("writes launch.toml with working-directory setting(API>=0.8)", func() {
var b bytes.Buffer
err := buildpackTOML.Execute(&b, map[string]string{"APIVersion": "0.8"})
Expect(err).ToNot(HaveOccurred())
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"), b.Bytes(), 0600)).To(Succeed())
builder.On("Build", mock.Anything).Return(libcnb.BuildResult{
Processes: []libcnb.Process{
{
Type: "test-type",
Command: "test-command-in-dir",
Default: true,
WorkingDirectory: "/my/directory/",
},
},
}, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
Expect(tomlWriter.Calls[0].Arguments[0]).To(Equal(filepath.Join(layersPath, "launch.toml")))
Expect(tomlWriter.Calls[0].Arguments[1]).To(Equal(libcnb.LaunchTOML{
Processes: []libcnb.Process{
{
Type: "test-type",
Command: "test-command-in-dir",
Default: true,
WorkingDirectory: "/my/directory/",
},
},
}))
})
it("writes persistent metadata", func() {
m := map[string]interface{}{"test-key": "test-value"}
builder.On("Build", mock.Anything).Return(libcnb.BuildResult{PersistentMetadata: m}, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
@ -553,6 +745,7 @@ version = "1.1.1"
builder.On("Build", mock.Anything).Return(libcnb.NewBuildResult(), nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
@ -573,6 +766,7 @@ version = "1.1.1"
Return(libcnb.BuildResult{Layers: []libcnb.LayerContributor{layerContributor}}, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
@ -605,6 +799,7 @@ version = "1.1.1"
}, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
@ -625,4 +820,213 @@ version = "1.1.1"
},
}))
})
context("Config bomLabel is false", func() {
it.Before(func() {
var err error
buildpackTOML, err = template.New("buildpack.toml").Parse(bpTOMLContents)
Expect(err).ToNot(HaveOccurred())
var b bytes.Buffer
err = buildpackTOML.Execute(&b, map[string]string{"APIVersion": "0.7"})
Expect(err).ToNot(HaveOccurred())
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"), b.Bytes(), 0600)).To(Succeed())
})
it("writes launch.toml without BOM entries", func() {
builder.On("Build", mock.Anything).Return(libcnb.BuildResult{
BOM: &libcnb.BOM{Entries: []libcnb.BOMEntry{
{
Name: "test-launch-bom-entry",
Metadata: map[string]interface{}{"test-key": "test-value"},
Launch: true,
},
{
Name: "test-build-bom-entry",
Metadata: map[string]interface{}{"test-key": "test-value"},
},
}},
Processes: []libcnb.Process{
{
Type: "test-type",
Command: "test-command",
Default: true,
},
},
}, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(false),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
Expect(tomlWriter.Calls[0].Arguments[0]).To(Equal(filepath.Join(layersPath, "launch.toml")))
Expect(tomlWriter.Calls[0].Arguments[1]).To(Equal(libcnb.LaunchTOML{
Processes: []libcnb.Process{
{
Type: "test-type",
Command: "test-command",
Default: true,
},
},
BOM: nil,
}))
})
it("writes build.toml without BOM entries", func() {
builder.On("Build", mock.Anything).Return(libcnb.BuildResult{
BOM: &libcnb.BOM{Entries: []libcnb.BOMEntry{
{
Name: "test-build-bom-entry",
Metadata: map[string]interface{}{"test-key": "test-value"},
Build: true,
},
{
Name: "test-launch-bom-entry",
Metadata: map[string]interface{}{"test-key": "test-value"},
Build: false,
},
}},
Unmet: []libcnb.UnmetPlanEntry{
{
Name: "test-entry",
},
},
}, nil)
libcnb.Build(builder,
libcnb.WithBOMLabel(false),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithTOMLWriter(tomlWriter),
)
Expect(tomlWriter.Calls[0].Arguments[0]).To(Equal(filepath.Join(layersPath, "build.toml")))
Expect(tomlWriter.Calls[0].Arguments[1]).To(Equal(libcnb.BuildTOML{
BOM: nil,
Unmet: []libcnb.UnmetPlanEntry{
{
Name: "test-entry",
},
},
}))
})
})
context("Validates SBOM entries", func() {
it.Before(func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
api = "0.7"
[buildpack]
id = "test-id"
name = "test-name"
version = "1.1.1"
sbom-formats = ["application/vnd.cyclonedx+json"]
`),
0600),
).To(Succeed())
builder.On("Build", mock.Anything).Return(libcnb.BuildResult{}, nil)
})
it("has no SBOM files", func() {
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
Expect(exitHandler.Calls).To(BeEmpty())
})
it("has no accepted formats", func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
api = "0.7"
[buildpack]
id = "test-id"
name = "test-name"
version = "1.1.1"
sbom-formats = []
`),
0600),
).To(Succeed())
Expect(ioutil.WriteFile(filepath.Join(layersPath, "launch.sbom.spdx.json"), []byte{}, 0600)).To(Succeed())
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError("unable to validate SBOM\nunable to find actual SBOM Type application/spdx+json in list of supported SBOM types []"))
})
it("skips if API is not 0.7", func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
api = "0.6"
[buildpack]
id = "test-id"
name = "test-name"
version = "1.1.1"
sbom-formats = []
`),
0600),
).To(Succeed())
Expect(ioutil.WriteFile(filepath.Join(layersPath, "launch.sbom.spdx.json"), []byte{}, 0600)).To(Succeed())
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
Expect(exitHandler.Calls).To(BeEmpty())
})
it("has no matching formats", func() {
Expect(ioutil.WriteFile(filepath.Join(layersPath, "launch.sbom.spdx.json"), []byte{}, 0600)).To(Succeed())
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError("unable to validate SBOM\nunable to find actual SBOM Type application/spdx+json in list of supported SBOM types [application/vnd.cyclonedx+json]"))
})
it("has a matching format", func() {
Expect(ioutil.WriteFile(filepath.Join(layersPath, "launch.sbom.cdx.json"), []byte{}, 0600)).To(Succeed())
Expect(ioutil.WriteFile(filepath.Join(layersPath, "layer.sbom.cdx.json"), []byte{}, 0600)).To(Succeed())
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
Expect(exitHandler.Calls).To(BeEmpty())
})
it("has a junk format", func() {
Expect(ioutil.WriteFile(filepath.Join(layersPath, "launch.sbom.random.json"), []byte{}, 0600)).To(Succeed())
Expect(ioutil.WriteFile(filepath.Join(layersPath, "layer.sbom.cdx.json"), []byte{}, 0600)).To(Succeed())
libcnb.Build(builder,
libcnb.WithBOMLabel(true),
libcnb.WithArguments([]string{commandPath, layersPath, platformPath, buildpackPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError("unable to validate SBOM\nunable to parse SBOM unknown\nunable to translate from random.json to SBOMFormat"))
})
})
}

View File

@ -41,6 +41,9 @@ type BuildpackInfo struct {
// Licenses a list of buildpack licenses.
Licenses []License `toml:"licenses"`
// SBOM is the list of supported SBOM media types
SBOMFormats []string `toml:"sbom-formats"`
}
// License contains information about a Software License
@ -91,7 +94,7 @@ type Buildpack struct {
Info BuildpackInfo `toml:"buildpack"`
// Path is the path to the buildpack.
Path string
Path string `toml:"-"`
// Stacks is the collection of stacks supported by the buildpack.
Stacks []BuildpackStack `toml:"stacks"`

51
buildpack_test.go Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright 2018-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package libcnb_test
import (
"bytes"
"testing"
"github.com/BurntSushi/toml"
"github.com/sclevine/spec"
"github.com/buildpacks/libcnb"
. "github.com/onsi/gomega"
)
func testBuildpackTOML(t *testing.T, context spec.G, it spec.S) {
var (
Expect = NewWithT(t).Expect
)
it("does not serialize the Path field", func() {
bp := libcnb.Buildpack{
API: "0.6",
Info: libcnb.BuildpackInfo{
ID: "test-buildpack/sample",
Name: "sample",
},
Path: "../buildpack",
}
output := &bytes.Buffer{}
Expect(toml.NewEncoder(output).Encode(bp)).To(Succeed())
Expect(output.String()).NotTo(Or(ContainSubstring("Path = "), ContainSubstring("path = ")))
})
}

View File

@ -65,6 +65,7 @@ type ExecDWriter interface {
// Config is an object that contains configurable properties for execution.
type Config struct {
arguments []string
bomLabel bool
environmentWriter EnvironmentWriter
exitHandler ExitHandler
tomlWriter TOMLWriter
@ -113,3 +114,12 @@ func WithExecDWriter(execdWriter ExecDWriter) Option {
return config
}
}
// WithBOMLabel creates an Option that enables/disables writing the BOM Label
// Deprecated: as of Buildpack API 0.7, to be removed in a future version
func WithBOMLabel(bomLabel bool) Option {
return func(config Config) Config {
config.bomLabel = bomLabel
return config
}
}

View File

@ -24,6 +24,7 @@ import (
"strings"
"github.com/BurntSushi/toml"
"github.com/Masterminds/semver/v3"
"github.com/buildpacks/libcnb/internal"
"github.com/buildpacks/libcnb/poet"
@ -77,11 +78,6 @@ func Detect(detector Detector, options ...Option) {
config = option(config)
}
if len(config.arguments) != 3 {
config.exitHandler.Error(fmt.Errorf("expected 2 arguments and received %d", len(config.arguments)-1))
return
}
var (
err error
file string
@ -115,20 +111,46 @@ func Detect(detector Detector, options ...Option) {
}
logger.Debugf("Buildpack: %+v", ctx.Buildpack)
API := strings.TrimSpace(ctx.Buildpack.API)
if API != "0.5" && API != "0.6" {
config.exitHandler.Error(errors.New("this version of libcnb is only compatible with buildpack API 0.5 and 0.6"))
API, err := semver.NewVersion(ctx.Buildpack.API)
if err != nil {
config.exitHandler.Error(errors.New("version cannot be parsed"))
return
}
ctx.Platform.Path = config.arguments[1]
compatVersionCheck, _ := semver.NewConstraint(fmt.Sprintf(">= %s, <= %s", MinSupportedBPVersion, MaxSupportedBPVersion))
if !compatVersionCheck.Check(API) {
config.exitHandler.Error(fmt.Errorf("this version of libcnb is only compatible with buildpack APIs >= %s, <= %s", MinSupportedBPVersion, MaxSupportedBPVersion))
return
}
var buildPlanPath string
if API.LessThan(semver.MustParse("0.8")) {
if len(config.arguments) != 3 {
config.exitHandler.Error(fmt.Errorf("expected 2 arguments and received %d", len(config.arguments)-1))
return
}
ctx.Platform.Path = config.arguments[1]
buildPlanPath = config.arguments[2]
} else {
ctx.Platform.Path, ok = os.LookupEnv("CNB_PLATFORM_DIR")
if !ok {
config.exitHandler.Error(fmt.Errorf("expected CNB_PLATFORM_DIR to be set"))
return
}
buildPlanPath, ok = os.LookupEnv("CNB_BUILD_PLAN_PATH")
if !ok {
config.exitHandler.Error(fmt.Errorf("expected CNB_BUILD_PLAN_PATH to be set"))
return
}
}
if logger.IsDebugEnabled() {
logger.Debug(PlatformFormatter(ctx.Platform))
}
file = filepath.Join(ctx.Platform.Path, "bindings")
if ctx.Platform.Bindings, err = NewBindingsFromPath(file); err != nil {
config.exitHandler.Error(fmt.Errorf("unable to read platform bindings %s\n%w", file, err))
if ctx.Platform.Bindings, err = NewBindingsForBuild(ctx.Platform.Path); err != nil {
config.exitHandler.Error(fmt.Errorf("unable to read platform bindings %s\n%w", ctx.Platform.Path, err))
return
}
logger.Debugf("Platform Bindings: %+v", ctx.Platform.Bindings)
@ -167,10 +189,9 @@ func Detect(detector Detector, options ...Option) {
plans.Or = result.Plans[1:]
}
file = config.arguments[2]
logger.Debugf("Writing build plans: %s <= %+v", file, plans)
if err := config.tomlWriter.Write(file, plans); err != nil {
config.exitHandler.Error(fmt.Errorf("unable to write buildplan %s\n%w", file, err))
logger.Debugf("Writing build plans: %s <= %+v", buildPlanPath, plans)
if err := config.tomlWriter.Write(buildPlanPath, plans); err != nil {
config.exitHandler.Error(fmt.Errorf("unable to write buildplan %s\n%w", buildPlanPath, err))
return
}
}

View File

@ -118,6 +118,8 @@ test-key = "test-value"
tomlWriter.On("Write", mock.Anything, mock.Anything).Return(nil)
Expect(os.Setenv("CNB_STACK_ID", "test-stack-id")).To(Succeed())
Expect(os.Setenv("CNB_PLATFORM_DIR", platformPath)).To(Succeed())
Expect(os.Setenv("CNB_BUILD_PLAN_PATH", buildPlanPath)).To(Succeed())
workingDir, err = os.Getwd()
Expect(err).NotTo(HaveOccurred())
@ -128,6 +130,8 @@ test-key = "test-value"
Expect(os.Chdir(workingDir)).To(Succeed())
Expect(os.Unsetenv("CNB_BUILDPACK_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_STACK_ID")).To(Succeed())
Expect(os.Unsetenv("CNB_PLATFORM_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_BUILD_PLAN_PATH")).To(Succeed())
Expect(os.RemoveAll(applicationPath)).To(Succeed())
Expect(os.RemoveAll(buildpackPath)).To(Succeed())
@ -135,7 +139,7 @@ test-key = "test-value"
Expect(os.RemoveAll(platformPath)).To(Succeed())
})
context("buildpack API is not 0.5 or 0.6", func() {
context("buildpack API is not within the supported range", func() {
it.Before(func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
@ -157,7 +161,7 @@ version = "1.1.1"
)
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(
"this version of libcnb is only compatible with buildpack API 0.5 and 0.6",
fmt.Sprintf("this version of libcnb is only compatible with buildpack APIs >= %s, <= %s", libcnb.MinSupportedBPVersion, libcnb.MaxSupportedBPVersion),
))
})
})
@ -185,53 +189,130 @@ version = "1.1.1"
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError("CNB_STACK_ID not set"))
})
it("creates context", func() {
detector.On("Detect", mock.Anything).Return(libcnb.DetectResult{Pass: true}, nil)
context("errors if required env vars are not set for buildpack API >=0.8", func() {
for _, e := range []string{"CNB_PLATFORM_DIR", "CNB_BUILD_PLAN_PATH"} {
// We need to do this assignment because of the way that spec binds variables
envVar := e
context(fmt.Sprintf("when %s is unset", envVar), func() {
it.Before(func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
api = "0.8"
[buildpack]
id = "test-id"
name = "test-name"
version = "1.1.1"
`),
0600),
).To(Succeed())
os.Unsetenv(envVar)
})
libcnb.Detect(detector,
libcnb.WithArguments([]string{commandPath, platformPath, buildPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
it("fails", func() {
libcnb.Detect(detector,
libcnb.WithArguments([]string{commandPath}),
libcnb.WithExitHandler(exitHandler),
)
Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(
fmt.Sprintf("expected %s to be set", envVar),
))
})
})
}
})
ctx := detector.Calls[0].Arguments[0].(libcnb.DetectContext)
Expect(ctx.Application).To(Equal(libcnb.Application{Path: applicationPath}))
Expect(ctx.Buildpack).To(Equal(libcnb.Buildpack{
API: "0.6",
Info: libcnb.BuildpackInfo{
ID: "test-id",
Name: "test-name",
Version: "1.1.1",
ClearEnvironment: true,
Description: "A test buildpack",
Keywords: []string{"test", "buildpack"},
Licenses: []libcnb.License{
{Type: "Apache-2.0", URI: "https://spdx.org/licenses/Apache-2.0.html"},
{Type: "Apache-1.1", URI: "https://spdx.org/licenses/Apache-1.1.html"},
context("when BP API >= 0.8", func() {
it.Before(func() {
Expect(ioutil.WriteFile(filepath.Join(buildpackPath, "buildpack.toml"),
[]byte(`
api = "0.8"
[buildpack]
id = "test-id"
name = "test-name"
version = "1.1.1"
`),
0600),
).To(Succeed())
})
it("creates context", func() {
detector.On("Detect", mock.Anything).Return(libcnb.DetectResult{Pass: true}, nil)
libcnb.Detect(detector,
libcnb.WithArguments([]string{commandPath}),
libcnb.WithExitHandler(exitHandler),
)
ctx := detector.Calls[0].Arguments[0].(libcnb.DetectContext)
Expect(ctx.Application).To(Equal(libcnb.Application{Path: applicationPath}))
Expect(ctx.Buildpack).To(Equal(libcnb.Buildpack{
API: "0.8",
Info: libcnb.BuildpackInfo{
ID: "test-id",
Name: "test-name",
Version: "1.1.1",
},
},
Path: buildpackPath,
Stacks: []libcnb.BuildpackStack{
{
ID: "test-id",
Mixins: []string{"test-name"},
},
},
Metadata: map[string]interface{}{"test-key": "test-value"},
}))
Expect(ctx.Platform).To(Equal(libcnb.Platform{
Bindings: libcnb.Bindings{
libcnb.Binding{
Name: "alpha",
Path: filepath.Join(platformPath, "bindings", "alpha"),
Secret: map[string]string{
"test-secret-key": "test-secret-value",
Path: buildpackPath,
}))
Expect(ctx.Platform).To(Equal(libcnb.Platform{
Bindings: libcnb.Bindings{
libcnb.Binding{
Name: "alpha",
Path: filepath.Join(platformPath, "bindings", "alpha"),
Secret: map[string]string{
"test-secret-key": "test-secret-value",
},
},
},
},
Environment: map[string]string{"TEST_ENV": "test-value"},
Path: platformPath,
}))
Expect(ctx.StackID).To(Equal("test-stack-id"))
Environment: map[string]string{"TEST_ENV": "test-value"},
Path: platformPath,
}))
Expect(ctx.StackID).To(Equal("test-stack-id"))
})
})
context("when BP API < 0.8", func() {
it.Before(func() {
Expect(os.Unsetenv("CNB_PLATFORM_DIR")).To(Succeed())
Expect(os.Unsetenv("CNB_BUILD_PLAN_PATH")).To(Succeed())
})
it("creates context", func() {
detector.On("Detect", mock.Anything).Return(libcnb.DetectResult{Pass: true}, nil)
libcnb.Detect(detector,
libcnb.WithArguments([]string{commandPath, platformPath, buildPlanPath}),
libcnb.WithExitHandler(exitHandler),
)
ctx := detector.Calls[0].Arguments[0].(libcnb.DetectContext)
Expect(ctx.Application).To(Equal(libcnb.Application{Path: applicationPath}))
Expect(ctx.Buildpack).To(Equal(libcnb.Buildpack{
API: "0.6",
Info: libcnb.BuildpackInfo{
ID: "test-id",
Name: "test-name",
Version: "1.1.1",
ClearEnvironment: true,
Description: "A test buildpack",
Keywords: []string{"test", "buildpack"},
Licenses: []libcnb.License{
{Type: "Apache-2.0", URI: "https://spdx.org/licenses/Apache-2.0.html"},
{Type: "Apache-1.1", URI: "https://spdx.org/licenses/Apache-1.1.html"},
},
},
Path: buildpackPath,
Stacks: []libcnb.BuildpackStack{
{
ID: "test-id",
Mixins: []string{"test-name"},
},
},
Metadata: map[string]interface{}{"test-key": "test-value"},
}))
})
})
it("extracts buildpack path from command path if CNB_BUILDPACK_PATH is not set", func() {

20
go.mod
View File

@ -1,10 +1,22 @@
module github.com/buildpacks/libcnb
go 1.15
go 1.17
require (
github.com/BurntSushi/toml v0.4.1
github.com/onsi/gomega v1.16.0
github.com/BurntSushi/toml v1.1.0
github.com/Masterminds/semver/v3 v3.1.1
github.com/onsi/gomega v1.19.0
github.com/sclevine/spec v1.4.0
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.8.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.4.0 // indirect
golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

51
go.sum
View File

@ -1,10 +1,14 @@
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -15,34 +19,38 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -53,8 +61,10 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0=
golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -64,24 +74,30 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e h1:NHvCuwuS43lGnYhten69ZWqi2QOj/CiDNcKbVqwVoew=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -90,17 +106,16 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -33,5 +33,6 @@ func TestUnit(t *testing.T) {
suite("Main", testMain)
suite("Platform", testPlatform)
suite("ExecD", testExecD)
suite("BuildpackTOML", testBuildpackTOML)
suite.Run(t)
}

View File

@ -38,6 +38,12 @@ func (w EnvironmentWriter) Write(path string, environment map[string]string) err
for key, value := range environment {
f := filepath.Join(path, key)
// required to support process-specific environment variables
if err := os.MkdirAll(filepath.Dir(f), 0755); err != nil {
return fmt.Errorf("unable to mkdir from key %s\n%w", filepath.Dir(f), err)
}
// #nosec
if err := ioutil.WriteFile(f, []byte(value), 0644); err != nil {
return fmt.Errorf("unable to write file %s\n%w", f, err)

View File

@ -63,6 +63,17 @@ func testEnvironmentWriter(t *testing.T, context spec.G, it spec.S) {
Expect(string(content)).To(Equal("other-content"))
})
it("writes the given environment with process specific envs to a directory", func() {
err := writer.Write(path, map[string]string{
"some-proc/some-name": "some-content",
})
Expect(err).NotTo(HaveOccurred())
content, err := ioutil.ReadFile(filepath.Join(path, "some-proc", "some-name"))
Expect(err).NotTo(HaveOccurred())
Expect(string(content)).To(Equal("some-content"))
})
it("writes does not create a directory of the env map is empty", func() {
err := writer.Write(path, map[string]string{})
Expect(err).NotTo(HaveOccurred())

View File

@ -26,9 +26,18 @@ import (
"github.com/buildpacks/libcnb/internal"
)
const (
BOMFormatCycloneDXExtension = "cdx.json"
BOMFormatSPDXExtension = "spdx.json"
BOMFormatSyftExtension = "syft.json"
BOMMediaTypeCycloneDX = "application/vnd.cyclonedx+json"
BOMMediaTypeSPDX = "application/spdx+json"
BOMMediaTypeSyft = "application/vnd.syft+json"
BOMUnknown = "unknown"
)
// Exec represents the exec.d layer location
type Exec struct {
// Path is the path to the exec.d directory.
Path string
}
@ -68,9 +77,47 @@ func (p Profile) ProcessAddf(processType string, name string, format string, a .
p.Addf(filepath.Join(processType, name), format, a...)
}
// Contribute represents a layer managed by the buildpack.
type Layer struct {
// BOMFormat indicates the format of the SBOM entry
type SBOMFormat int
const (
CycloneDXJSON SBOMFormat = iota
SPDXJSON
SyftJSON
UnknownFormat
)
func (b SBOMFormat) String() string {
return []string{
BOMFormatCycloneDXExtension,
BOMFormatSPDXExtension,
BOMFormatSyftExtension,
BOMUnknown}[b]
}
func (b SBOMFormat) MediaType() string {
return []string{
BOMMediaTypeCycloneDX,
BOMMediaTypeSPDX,
BOMMediaTypeSyft,
BOMUnknown}[b]
}
func SBOMFormatFromString(from string) (SBOMFormat, error) {
switch from {
case CycloneDXJSON.String():
return CycloneDXJSON, nil
case SPDXJSON.String():
return SPDXJSON, nil
case SyftJSON.String():
return SyftJSON, nil
}
return UnknownFormat, fmt.Errorf("unable to translate from %s to SBOMFormat", from)
}
// Layer represents a layer managed by the buildpack.
type Layer struct {
// LayerTypes indicates the type of layer
LayerTypes `toml:"types"`
@ -99,6 +146,10 @@ type Layer struct {
Exec Exec `toml:"-"`
}
func (l Layer) SBOMPath(bt SBOMFormat) string {
return filepath.Join(filepath.Dir(l.Path), fmt.Sprintf("%s.sbom.%s", l.Name, bt))
}
// LayerTypes describes which types apply to a given layer. A layer may have any combination of Launch, Build, and
// Cache types.
type LayerTypes struct {
@ -116,7 +167,6 @@ type LayerTypes struct {
// LayerContributor is an interface for types that create layers.
type LayerContributor interface {
// Contribute accepts a layer and transforms it, returning a layer.
Contribute(layer Layer) (Layer, error)
@ -126,7 +176,6 @@ type LayerContributor interface {
// Layers represents the layers part of the specification.
type Layers struct {
// Path is the layers filesystem location.
Path string
}
@ -162,3 +211,13 @@ func (l *Layers) Layer(name string) (Layer, error) {
return layer, nil
}
// BOMBuildPath returns the full path to the build SBoM file for the buildpack
func (l Layers) BuildSBOMPath(bt SBOMFormat) string {
return filepath.Join(l.Path, fmt.Sprintf("build.sbom.%s", bt))
}
// BOMLaunchPath returns the full path to the launch SBoM file for the buildpack
func (l Layers) LaunchSBOMPath(bt SBOMFormat) string {
return filepath.Join(l.Path, fmt.Sprintf("launch.sbom.%s", bt))
}

View File

@ -110,6 +110,36 @@ func testLayer(t *testing.T, context spec.G, it spec.S) {
Expect(l.Profile).To(Equal(libcnb.Profile{}))
})
it("generates SBOM paths", func() {
l, err := layers.Layer("test-name")
Expect(err).NotTo(HaveOccurred())
Expect(l.Path).To(Equal(filepath.Join(path, "test-name")))
Expect(layers.BuildSBOMPath(libcnb.CycloneDXJSON)).To(Equal(filepath.Join(path, "build.sbom.cdx.json")))
Expect(layers.BuildSBOMPath(libcnb.SPDXJSON)).To(Equal(filepath.Join(path, "build.sbom.spdx.json")))
Expect(layers.BuildSBOMPath(libcnb.SyftJSON)).To(Equal(filepath.Join(path, "build.sbom.syft.json")))
Expect(layers.LaunchSBOMPath(libcnb.SyftJSON)).To(Equal(filepath.Join(path, "launch.sbom.syft.json")))
Expect(l.SBOMPath(libcnb.SyftJSON)).To(Equal(filepath.Join(path, "test-name.sbom.syft.json")))
})
it("maps from string to SBOM Format", func() {
fmt, err := libcnb.SBOMFormatFromString("cdx.json")
Expect(err).ToNot(HaveOccurred())
Expect(fmt).To(Equal(libcnb.CycloneDXJSON))
fmt, err = libcnb.SBOMFormatFromString("spdx.json")
Expect(err).ToNot(HaveOccurred())
Expect(fmt).To(Equal(libcnb.SPDXJSON))
fmt, err = libcnb.SBOMFormatFromString("syft.json")
Expect(err).ToNot(HaveOccurred())
Expect(fmt).To(Equal(libcnb.SyftJSON))
fmt, err = libcnb.SBOMFormatFromString("foobar.json")
Expect(err).To(MatchError("unable to translate from foobar.json to SBOMFormat"))
Expect(fmt).To(Equal(libcnb.UnknownFormat))
})
it("reads existing 0.5 metadata", func() {
Expect(ioutil.WriteFile(
filepath.Join(path, "test-name.toml"),

View File

@ -43,6 +43,7 @@ const (
// EnvCNBBindings is the name of the environment variable that contains the path to the CNB bindings directory.
// See the CNB bindings extension spec for more details - https://github.com/buildpacks/spec/blob/main/extensions/bindings.md
//
// Deprecated: Use the Service Binding Specification for Kubernetes instead -
// https://github.com/buildpacks/rfcs/blob/main/text/0055-deprecate-service-bindings.md.
EnvCNBBindings = "CNB_BINDINGS"

View File

@ -1,7 +1,159 @@
module github.com/buildpacks/libcnb/tools
go 1.15
go 1.17
require golang.org/x/tools v0.1.4
require golang.org/x/tools v0.1.10
require github.com/golangci/golangci-lint v1.41.1
require github.com/golangci/golangci-lint v1.45.2
require (
4d63.com/gochecknoglobals v0.1.0 // indirect
github.com/Antonboom/errname v0.1.5 // indirect
github.com/Antonboom/nilnil v0.1.0 // indirect
github.com/BurntSushi/toml v1.0.0 // indirect
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/OpenPeeDeeP/depguard v1.1.0 // indirect
github.com/alexkohler/prealloc v1.0.0 // indirect
github.com/ashanbrown/forbidigo v1.3.0 // indirect
github.com/ashanbrown/makezero v1.1.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bkielbasa/cyclop v1.2.0 // indirect
github.com/blizzy78/varnamelen v0.6.1 // indirect
github.com/bombsimon/wsl/v3 v3.3.0 // indirect
github.com/breml/bidichk v0.2.2 // indirect
github.com/breml/errchkjson v0.2.3 // indirect
github.com/butuzov/ireturn v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/charithe/durationcheck v0.0.9 // indirect
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect
github.com/daixiang0/gci v0.3.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/denis-tingaikin/go-header v0.4.3 // indirect
github.com/esimonov/ifshort v1.0.4 // indirect
github.com/ettle/strcase v0.1.1 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/fzipp/gocyclo v0.4.0 // indirect
github.com/go-critic/go-critic v0.6.2 // indirect
github.com/go-toolsmith/astcast v1.0.0 // indirect
github.com/go-toolsmith/astcopy v1.0.0 // indirect
github.com/go-toolsmith/astequal v1.0.1 // indirect
github.com/go-toolsmith/astfmt v1.0.0 // indirect
github.com/go-toolsmith/astp v1.0.0 // indirect
github.com/go-toolsmith/strparse v1.0.0 // indirect
github.com/go-toolsmith/typep v1.0.2 // indirect
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 // indirect
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a // indirect
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect
github.com/golangci/misspell v0.3.5 // indirect
github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 // indirect
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 // indirect
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
github.com/gostaticanalysis/comment v1.4.2 // indirect
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-version v1.4.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jgautheron/goconst v1.5.1 // indirect
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect
github.com/julz/importas v0.1.0 // indirect
github.com/kisielk/errcheck v1.6.0 // indirect
github.com/kisielk/gotool v1.0.0 // indirect
github.com/kulti/thelper v0.5.1 // indirect
github.com/kunwardeep/paralleltest v1.0.3 // indirect
github.com/kyoh86/exportloopref v0.1.8 // indirect
github.com/ldez/gomoddirectives v0.2.2 // indirect
github.com/ldez/tagliatelle v0.3.1 // indirect
github.com/leonklingele/grouper v1.1.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/maratori/testpackage v1.0.1 // indirect
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mbilski/exhaustivestruct v1.2.0 // indirect
github.com/mgechev/revive v1.1.4 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/moricho/tparallel v0.2.1 // indirect
github.com/nakabonne/nestif v0.3.1 // indirect
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
github.com/nishanths/exhaustive v0.7.11 // indirect
github.com/nishanths/predeclared v0.2.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polyfloyd/go-errorlint v0.0.0-20211125173453-6d6d39c5bb8b // indirect
github.com/prometheus/client_golang v1.7.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.10.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/quasilyte/go-ruleguard v0.3.15 // indirect
github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3 // indirect
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect
github.com/ryancurrah/gomodguard v1.2.3 // indirect
github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect
github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect
github.com/securego/gosec/v2 v2.10.0 // indirect
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/sivchari/containedctx v1.0.2 // indirect
github.com/sivchari/tenv v1.4.7 // indirect
github.com/sonatard/noctx v0.0.1 // indirect
github.com/sourcegraph/go-diff v0.6.1 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.4.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.10.1 // indirect
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
github.com/stretchr/objx v0.1.1 // indirect
github.com/stretchr/testify v1.7.1 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/sylvia7788/contextcheck v1.0.4 // indirect
github.com/tdakkota/asciicheck v0.1.1 // indirect
github.com/tetafro/godot v1.4.11 // indirect
github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 // indirect
github.com/tomarrell/wrapcheck/v2 v2.5.0 // indirect
github.com/tommy-muehle/go-mnd/v2 v2.5.0 // indirect
github.com/ultraware/funlen v0.0.3 // indirect
github.com/ultraware/whitespace v0.0.5 // indirect
github.com/uudashr/gocognit v1.0.5 // indirect
github.com/yagipy/maintidx v1.0.0 // indirect
github.com/yeya24/promlinter v0.1.1-0.20210918184747-d757024714a1 // indirect
gitlab.com/bosi/decorder v0.2.1 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
honnef.co/go/tools v0.2.2 // indirect
mvdan.cc/gofumpt v0.3.0 // indirect
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect
mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 // indirect
)

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
//go:build tools
// +build tools
package tools