Skip to content

Commit

Permalink
Add SBOM Support
Browse files Browse the repository at this point in the history
Adds SBOM support for installed dependencies: rustup-init, rustup and rust. Support is added for Syft JSON format.

This PR generates the Syft JSON directly and stores it on the layer for each installed dependency.

Signed-off-by: Daniel Mikusa <dmikusa@vmware.com>
  • Loading branch information
Daniel Mikusa authored and ForestEckhardt committed May 16, 2022
1 parent 5d5b926 commit d95bde8
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 52 deletions.
11 changes: 8 additions & 3 deletions buildpack.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.

api = "0.6"
api = "0.7"

[buildpack]
description = "A Cloud Native Buildpack that installs and executes `rustup` to install Rust"
homepage = "https://github.com/paketo-community/rustup"
id = "paketo-community/rustup"
keywords = ["rust", "rustup"]
name = "Paketo Rustup Buildpack"
sbom-formats = ["application/vnd.cyclonedx+json", "application/vnd.syft+json"]
version = "{{.version}}"

[[buildpack.licenses]]
Expand Down Expand Up @@ -67,8 +68,10 @@ api = "0.6"
name = "BP_RUSTUP_INIT_LIBC"

[[metadata.dependencies]]
id = "rustup-gnu"
cpes = ["cpe:2.3:a:rust:rustup:1.24.3:*:*:*:*:*:*:*"]
id = "rustup-init-gnu"
name = "Rustup (GNU libc)"
purl = "pkg:generic/rustup@1.24.3"
sha256 = "3dc5ef50861ee18657f9db2eeb7392f9c2a6c95c90ab41e45ab4ca71476b4338"
stacks = ["io.buildpacks.stacks.bionic", "io.paketo.stacks.tiny", "*"]
uri = "https://static.rust-lang.org/rustup/archive/1.24.3/x86_64-unknown-linux-gnu/rustup-init"
Expand All @@ -83,8 +86,10 @@ api = "0.6"
uri = "https://github.com/rust-lang/rustup/blob/master/LICENSE-MIT"

[[metadata.dependencies]]
id = "rustup-musl"
cpes = ["cpe:2.3:a:rust:rustup:1.24.3:*:*:*:*:*:*:*"]
id = "rustup-init-musl"
name = "Rustup (musl libc)"
purl = "pkg:generic/rustup@1.24.3"
sha256 = "bdf022eb7cba403d0285bb62cbc47211f610caec24589a72af70e1e900663be9"
stacks = ["io.buildpacks.stacks.bionic", "io.paketo.stacks.tiny", "*"]
uri = "https://static.rust-lang.org/rustup/archive/1.24.3/x86_64-unknown-linux-musl/rustup-init"
Expand Down
21 changes: 20 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/paketo-community/rustup

go 1.16
go 1.17

require (
github.com/buildpacks/libcnb v1.26.0
Expand All @@ -10,3 +10,22 @@ require (
github.com/sclevine/spec v1.4.0
github.com/stretchr/testify v1.7.1
)

require (
github.com/BurntSushi/toml v1.1.0 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/creack/pty v1.1.18 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/pelletier/go-toml v1.9.5 // 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-20220513224357-95641704303c // indirect
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99 // indirect
)
20 changes: 14 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
Expand All @@ -66,8 +68,9 @@ github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
Expand All @@ -84,8 +87,9 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
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/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220513224357-95641704303c h1:nF9mHSvoKBLkQNQhJZNsc66z2UzAMUbLGjC95CF3pU0=
golang.org/x/net v0.0.0-20220513224357-95641704303c/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
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=
Expand All @@ -103,9 +107,12 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/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-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a h1:N2T1jUrTQE9Re6TFF5PhvEHXHCguynGhKjWVsIUt5cY=
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/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=
Expand Down Expand Up @@ -139,5 +146,6 @@ 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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99 h1:dbuHpmKjkDzSOMKAWl10QNlgaZUd3V1q99xc81tt2Kc=
gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
13 changes: 4 additions & 9 deletions rustup/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,15 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {
v, _ := cr.Resolve("BP_RUSTUP_INIT_VERSION")
libc, _ := cr.Resolve("BP_RUSTUP_INIT_LIBC")

rustupInitDependency, err := dr.Resolve(fmt.Sprintf("rustup-%s", libc), v)
rustupInitDependency, err := dr.Resolve(fmt.Sprintf("rustup-init-%s", libc), v)
if err != nil {
return libcnb.BuildResult{}, fmt.Errorf("unable to find dependency\n%w", err)
}

rustupInit, be := NewRustupInit(rustupInitDependency, dc)
rustupInit := NewRustupInit(rustupInitDependency, dc)
rustupInit.Logger = b.Logger

result.Layers = append(result.Layers, rustupInit)
result.BOM.Entries = append(result.BOM.Entries, be)

// make layer for cargo, which is installed by rust
cargo := Cargo{}
Expand All @@ -83,22 +82,18 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) {

// install rustup
profile, _ := cr.Resolve("BP_RUST_PROFILE")
rustup, be := NewRustup(rustupInitDependency.Version, profile)
rustup := NewRustup(rustupInitDependency.Version, profile)
rustup.Logger = b.Logger

result.Layers = append(result.Layers, rustup)
// TODO: add when layer is emitting BOM
// result.BOM.Entries = append(result.BOM.Entries, be)

// install rust
rustVersion, _ := cr.Resolve("BP_RUST_TOOLCHAIN")
additionalTarget := AdditionalTarget(cr, context.StackID)
rust, be := NewRust(profile, rustVersion, additionalTarget)
rust := NewRust(profile, rustVersion, additionalTarget)
rust.Logger = b.Logger

result.Layers = append(result.Layers, rust)
// TODO: add when layer is emitting BOM
// result.BOM.Entries = append(result.BOM.Entries, be)
}

return result, nil
Expand Down
21 changes: 5 additions & 16 deletions rustup/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
ctx.Buildpack.Metadata = map[string]interface{}{
"dependencies": []map[string]interface{}{
{
"id": "rustup-",
"id": "rustup-init-",
"version": "1.24.3",
"stacks": []interface{}{"test-stack-id"},
},
Expand All @@ -73,13 +73,10 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(err).NotTo(HaveOccurred())

Expect(result.Layers).To(HaveLen(4))
Expect(result.Layers[0].Name()).To(Equal("rustup-"))
Expect(result.Layers[0].Name()).To(Equal("rustup-init-"))
Expect(result.Layers[1].Name()).To(Equal("Cargo"))
Expect(result.Layers[2].Name()).To(Equal("Rustup"))
Expect(result.Layers[3].Name()).To(Equal("Rust"))

Expect(result.BOM.Entries).To(HaveLen(1))
Expect(result.BOM.Entries[0].Name).To(Equal("rustup-"))
})

context("$BP_RUSTUP_ENABLED is set", func() {
Expand All @@ -97,7 +94,6 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(err).NotTo(HaveOccurred())

Expect(result.Layers).To(HaveLen(0))
Expect(result.BOM.Entries).To(HaveLen(0))
Expect(result.Unmet).To(HaveLen(1))
Expect(result.Unmet[0].Name).To(Equal("rust"))
})
Expand All @@ -117,10 +113,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(err).NotTo(HaveOccurred())

Expect(result.Layers).To(HaveLen(4))
Expect(result.Layers[0].Name()).To(Equal("rustup-"))

Expect(result.BOM.Entries).To(HaveLen(1))
Expect(result.BOM.Entries[0].Name).To(Equal("rustup-"))
Expect(result.Layers[0].Name()).To(Equal("rustup-init-"))
})
})

Expand All @@ -138,7 +131,6 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(err).NotTo(HaveOccurred())

Expect(result.Layers).To(HaveLen(0))
Expect(result.BOM.Entries).To(HaveLen(0))
})
})
})
Expand All @@ -155,7 +147,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
ctx.Buildpack.Metadata = map[string]interface{}{
"dependencies": []map[string]interface{}{
{
"id": "rustup-musl",
"id": "rustup-init-musl",
"version": "1.24.3",
"stacks": []interface{}{"test-stack-id"},
},
Expand Down Expand Up @@ -184,10 +176,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) {
Expect(err).NotTo(HaveOccurred())

Expect(result.Layers).To(HaveLen(4))
Expect(result.Layers[0].Name()).To(Equal("rustup-musl"))

Expect(result.BOM.Entries).To(HaveLen(1))
Expect(result.BOM.Entries[0].Name).To(Equal("rustup-musl"))
Expect(result.Layers[0].Name()).To(Equal("rustup-init-musl"))
})
})

Expand Down
38 changes: 35 additions & 3 deletions rustup/rust.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/paketo-buildpacks/libpak"
"github.com/paketo-buildpacks/libpak/bard"
"github.com/paketo-buildpacks/libpak/effect"
"github.com/paketo-buildpacks/libpak/sbom"
)

// Rust will run `rustup` from the PATH to install a given toolchain
Expand All @@ -40,7 +41,7 @@ type Rust struct {
Profile string
}

func NewRust(profile, toolchain, target string) (Rust, libcnb.BOMEntry) {
func NewRust(profile, toolchain, target string) Rust {
return Rust{
LayerContributor: libpak.NewLayerContributor(
"Rust",
Expand All @@ -57,7 +58,7 @@ func NewRust(profile, toolchain, target string) (Rust, libcnb.BOMEntry) {
Profile: profile,
Toolchain: toolchain,
Target: target,
}, libcnb.BOMEntry{}
}
}

func (r Rust) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
Expand Down Expand Up @@ -122,6 +123,38 @@ func (r Rust) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
}
}

buf := &bytes.Buffer{}
if err := r.Executor.Execute(effect.Execution{
Command: "rustc",
Args: []string{"--version"},
Stdout: buf,
Stderr: buf,
}); err != nil {
return libcnb.Layer{}, fmt.Errorf("error executing 'rustc --version':\n Combined Output: %s: \n%w", buf.String(), err)
}
ver := strings.Split(strings.TrimSpace(buf.String()), " ")

sbomPath := layer.SBOMPath(libcnb.SyftJSON)
dep := sbom.NewSyftDependency(layer.Path, []sbom.SyftArtifact{
{
ID: "rust",
Name: "Rust",
Version: ver[1],
Type: "UnknownPackage",
FoundBy: "paketo-community/rustup",
Locations: []sbom.SyftLocation{
{Path: "paketo-community/rustup/rustup/rust.go"},
},
Licenses: []string{"Apache-2.0", "MIT"},
CPEs: []string{fmt.Sprintf("cpe:2.3:a:rust:rust:%s:*:*:*:*:*:*:*", ver[1])},
PURL: fmt.Sprintf("pkg:generic/rust@%s", ver[1]),
},
})
r.Logger.Debugf("Writing Syft SBOM at %s: %+v", sbomPath, dep)
if err := dep.WriteTo(sbomPath); err != nil {
return libcnb.Layer{}, fmt.Errorf("unable to write SBOM\n%w", err)
}

return layer, nil
})
if err != nil {
Expand All @@ -140,7 +173,6 @@ func (r Rust) Contribute(layer libcnb.Layer) (libcnb.Layer, error) {
}
layer.Metadata["installed"] = strings.TrimSpace(buf.String())

// TODO: populate & return BOM
return layer, nil
}

Expand Down
32 changes: 30 additions & 2 deletions rustup/rust_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,20 @@ func testRust(t *testing.T, context spec.G, it spec.S) {
layer, err := ctx.Layers.Layer("test-layer")
Expect(err).NotTo(HaveOccurred())

executor.On("Execute", mock.MatchedBy(func(ex effect.Execution) bool {
return ex.Args[0] == "--version" && ex.Command == "rustc"
})).Return(func(ex effect.Execution) error {
_, err := ex.Stdout.Write([]byte("rustc 1.2.3 (53cb7b09b 2021-06-17)\n"))
Expect(err).ToNot(HaveOccurred())
return nil
})

executor.On("Execute", mock.Anything).Return(nil).Run(func(args mock.Arguments) {
Expect(os.MkdirAll(layer.Path, 0755)).To(Succeed())
Expect(ioutil.WriteFile(filepath.Join(layer.Path, "env"), nil, 0644)).To(Succeed())
})

r, _ := rustup.NewRust("minimal", "1.2.3", "")
r := rustup.NewRust("minimal", "1.2.3", "")
r.Executor = executor

layer, err = r.Contribute(layer)
Expand All @@ -90,18 +98,32 @@ func testRust(t *testing.T, context spec.G, it spec.S) {
Expect(execShow.Command).To(Equal("rustup"))
Expect(execShow.Args).To(Equal([]string{"-q", "toolchain", "install", "--profile=minimal", "1.2.3"}))
Expect(execShow.Dir).To(Equal(layer.Path))

execVer := executor.Calls[2].Arguments[0].(effect.Execution)
Expect(execVer.Command).To(Equal("rustc"))
Expect(execVer.Args).To(Equal([]string{"--version"}))

Expect(layer.SBOMPath(libcnb.SyftJSON)).To(BeARegularFile())
})

it("contributes rust and a target", func() {
layer, err := ctx.Layers.Layer("test-layer")
Expect(err).NotTo(HaveOccurred())

executor.On("Execute", mock.MatchedBy(func(ex effect.Execution) bool {
return ex.Args[0] == "--version" && ex.Command == "rustc"
})).Return(func(ex effect.Execution) error {
_, err := ex.Stdout.Write([]byte("rustc 1.2.3 (53cb7b09b 2021-06-17)\n"))
Expect(err).ToNot(HaveOccurred())
return nil
})

executor.On("Execute", mock.Anything).Return(nil).Run(func(args mock.Arguments) {
Expect(os.MkdirAll(layer.Path, 0755)).To(Succeed())
Expect(ioutil.WriteFile(filepath.Join(layer.Path, "env"), nil, 0644)).To(Succeed())
})

r, _ := rustup.NewRust("minimal", "1.2.3", "foo")
r := rustup.NewRust("minimal", "1.2.3", "foo")
r.Executor = executor

layer, err = r.Contribute(layer)
Expand All @@ -124,6 +146,12 @@ func testRust(t *testing.T, context spec.G, it spec.S) {
Expect(execTarget.Command).To(Equal("rustup"))
Expect(execTarget.Args).To(Equal([]string{"-q", "target", "add", "--toolchain=1.2.3", "foo"}))
Expect(execTarget.Dir).To(Equal(layer.Path))

execVer := executor.Calls[3].Arguments[0].(effect.Execution)
Expect(execVer.Command).To(Equal("rustc"))
Expect(execVer.Args).To(Equal([]string{"--version"}))

Expect(layer.SBOMPath(libcnb.SyftJSON)).To(BeARegularFile())
})

}
Loading

0 comments on commit d95bde8

Please sign in to comment.