Skip to content

Commit

Permalink
Validate stack during analyze phase
Browse files Browse the repository at this point in the history
During analyze, Platform 0.7 and above will validate the build and stack image if the data is available to do so.

Addresses: #471

Signed-off-by: Jesse Brown <jabrown85@gmail.com>
  • Loading branch information
jabrown85 committed Jun 14, 2021
1 parent 8e9b27e commit 2cfc635
Show file tree
Hide file tree
Showing 12 changed files with 535 additions and 2 deletions.
196 changes: 195 additions & 1 deletion acceptance/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,36 @@ func TestAnalyzer(t *testing.T) {
h.AssertNil(t, os.RemoveAll(filepath.Join(targetDockerConfig, "config.json")))
h.RecursiveCopy(t, authRegistry.DockerDirectory, targetDockerConfig)

// build run-images into test registry
runImageContext := filepath.Join("testdata", "analyzer", "run-image")
buildAuthRegistryImage(
t,
"company/stack:bionic",
runImageContext,
"-f", filepath.Join(runImageContext, dockerfileName),
"--build-arg", "stackid=io.buildpacks.stacks.bionic",
)
buildAuthRegistryImage(
t,
"company/stack:centos",
runImageContext,
"-f", filepath.Join(runImageContext, dockerfileName),
"--build-arg", "stackid=io.company.centos",
)

// build run-image into daemon
h.DockerBuild(
t,
"localcompany/stack:bionic",
runImageContext,
h.WithArgs(
"-f", filepath.Join(runImageContext, dockerfileName),
"--build-arg", "stackid=io.buildpacks.stacks.bionic",
),
)

defer h.DockerImageRemove(t, "localcompany/stack:bionic")

// Setup test container

h.MakeAndCopyLifecycle(t, daemonOS, analyzerBinaryDir)
Expand All @@ -81,6 +111,7 @@ func TestAnalyzer(t *testing.T) {
analyzeDockerContext,
h.WithFlags(
"-f", filepath.Join(analyzeDockerContext, dockerfileName),
"--build-arg", "registry="+noAuthRegistry.Host+":"+noAuthRegistry.Port,
),
)
defer h.DockerImageRemove(t, analyzeImage)
Expand Down Expand Up @@ -253,7 +284,10 @@ func testAnalyzerFunc(platformAPI string) func(t *testing.T, when spec.G, it spe
copyDir,
ctrPath("/some-dir/some-analyzed.toml"),
analyzeImage,
h.WithFlags("--env", "CNB_PLATFORM_API="+platformAPI),
h.WithFlags(
"--network", registryNetwork,
"--env", "CNB_PLATFORM_API="+platformAPI,
),
h.WithArgs(execArgs...),
)

Expand All @@ -277,6 +311,7 @@ func testAnalyzerFunc(platformAPI string) func(t *testing.T, when spec.G, it spe
h.WithFlags(append(
dockerSocketMount,
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_STACK_PATH=/cnb/local-bionic-stack.toml", // /cnb/local-bionic-stack.toml has `io.buildpacks.stacks.bionic` and points to run image `localcompany/stack:bionic` with same stack id
)...),
h.WithArgs(execArgs...),
)
Expand Down Expand Up @@ -316,6 +351,7 @@ func testAnalyzerFunc(platformAPI string) func(t *testing.T, when spec.G, it spe
h.WithFlags(append(
dockerSocketMount,
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_STACK_PATH=/cnb/local-bionic-stack.toml", // /cnb/local-bionic-stack.toml has `io.buildpacks.stacks.bionic` and points to run image `localcompany/stack:bionic` with same stack id
)...),
h.WithArgs(
ctrPath(analyzerPath),
Expand Down Expand Up @@ -624,6 +660,7 @@ func testAnalyzerFunc(platformAPI string) func(t *testing.T, when spec.G, it spe
ctrPath("/layers/analyzed.toml"),
analyzeImage,
h.WithFlags(
"--network", registryNetwork,
"--env", "CNB_PLATFORM_API="+platformAPI,
),
h.WithArgs(ctrPath(analyzerPath), "some-image"),
Expand Down Expand Up @@ -1065,6 +1102,163 @@ func testAnalyzerFunc(platformAPI string) func(t *testing.T, when spec.G, it spe
assertAnalyzedMetadata(t, filepath.Join(copyDir, "some-other-layers", "analyzed.toml")) // analyzed.toml is written at the provided -layers directory: /some-other-layers
})
})

when("validating stack", func() {
it.Before(func() {
h.SkipIf(t, api.MustParse(platformAPI).Compare(api.MustParse("0.7")) < 0, "Platform API < 0.7 does not validate stack")
})

when("stack metadata is present", func() {
when("stacks match", func() {
it("passes validation", func() {
execArgs := []string{ctrPath(analyzerPath)}
h.DockerRun(t,
analyzeImage, // /cnb/stack.toml has `io.buildpacks.stacks.bionic` and points to run image `company/stack:bionic` with same stack id
h.WithFlags(
"--network", registryNetwork,
"--env", "CNB_PLATFORM_API="+platformAPI,
),
h.WithArgs(execArgs...),
)
})
})

when("CNB_RUN_IMAGE is present", func() {
it("uses CNB_RUN_IMAGE for validation", func() {
execArgs := []string{ctrPath(analyzerPath)}

h.DockerRun(t,
analyzeImage,
h.WithFlags(
"--network", registryNetwork,
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_STACK_PATH=/cnb/mismatch-stack.toml", // /cnb/mismatch-stack.toml points to run image `company/stack:centos`
"--env", "CNB_RUN_IMAGE="+noAuthRegistry.RepoName("company/stack:bionic"),
),
h.WithArgs(execArgs...),
)
})
})

when("stack metadata file is invalid", func() {
it("fails validation", func() {
cmd := exec.Command(
"docker", "run", "--rm",
"--network", registryNetwork,
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_STACK_PATH=/cnb/bad-stack.toml",
analyzeImage,
ctrPath(analyzerPath),
) // #nosec G204
output, err := cmd.CombinedOutput()

h.AssertNotNil(t, err)
expected := "get stack metadata"
h.AssertStringContains(t, string(output), expected)
})
})

when("run image inaccessible", func() {
it("fails validation", func() {
cmd := exec.Command(
"docker", "run", "--rm",
"--network", registryNetwork,
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_RUN_IMAGE=fake.example.com/company/example:20",
analyzeImage,
ctrPath(analyzerPath),
) // #nosec G204
output, err := cmd.CombinedOutput()

h.AssertNotNil(t, err)
expected := "failed to resolve run image"
h.AssertStringContains(t, string(output), expected)
})
})

when("run image has mirrors", func() {
it("uses expected mirror for run-image", func() {
execArgs := []string{ctrPath(analyzerPath), "--previous-image=" + noAuthRegistry.RepoName("apprepo/myapp")} // previous image located on same registry as mirror

h.DockerRunAndCopy(t,
containerName,
copyDir,
ctrPath("/layers/analyzed.toml"),
analyzeImage,
h.WithFlags(
"--network", registryNetwork,
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_STACK_PATH=/cnb/run-mirror-stack.toml", // /cnb/run-mirror-stack.toml points to run image on gcr.io and mirror on test registry
),
h.WithArgs(execArgs...),
)
})
})

when("daemon case", func() {
when("stacks match", func() {
it("passes validation", func() {
execArgs := []string{ctrPath(analyzerPath), "-daemon"}

h.DockerRunAndCopy(t,
containerName,
copyDir,
ctrPath("/layers/analyzed.toml"),
analyzeImage,
h.WithFlags(append(
dockerSocketMount,
"--network", registryNetwork,
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_STACK_PATH=/cnb/local-bionic-stack.toml", // /cnb/local-bionic-stack.toml has `io.buildpacks.stacks.bionic` and points to run image `localcompany/stack:bionic` with same stack id
)...),
h.WithArgs(execArgs...),
)
})
})
})
})

when("stack metadata is not present", func() {
when("CNB_RUN_IMAGE and CNB_STACK_ID are set", func() {
it("passes validation", func() {
execArgs := []string{ctrPath(analyzerPath)}

h.DockerRunAndCopy(t,
containerName,
copyDir,
ctrPath("/layers/analyzed.toml"),
analyzeImage,
h.WithFlags(
"--network", registryNetwork,
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_STACK_PATH=/cnb/file-does-not-exist.toml",
"--env", "CNB_RUN_IMAGE="+noAuthRegistry.RepoName("company/stack:bionic"),
"--env", "CNB_STACK_ID=io.buildpacks.stacks.bionic",
),
h.WithArgs(execArgs...),
)
})
})

when("run image and stack id are not provided as arguments or in the environment", func() {
it("fails validation", func() {
cmd := exec.Command(
"docker", "run", "--rm",
"--network", registryNetwork,
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_STACK_PATH=/cnb/file-does-not-exist.toml",
analyzeImage,
ctrPath(analyzerPath),
) // #nosec G204
output, err := cmd.CombinedOutput()

h.AssertNotNil(t, err)
expected := "a run image must be specified when there is no stack metadata available"
h.AssertStringContains(t, string(output), expected)
})
})
})
})
}
}

Expand Down
41 changes: 41 additions & 0 deletions acceptance/testdata/analyzer/analyze-image/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,44 @@ RUN chown -R $CNB_USER_ID:$CNB_GROUP_ID /layers

# ensure docker config directory is root owned and NOT world readable
RUN chown -R root /docker-config; chmod -R 700 /docker-config

ARG registry

# write some stack.toml files to use in tests
RUN echo "\
[run-image]\n\
image = \"${registry}/company/stack:bionic\"\n\
mirrors = []\n\
[build-image]\n\
stack-id = \"io.buildpacks.stacks.bionic\"\n\
mixins = []\n\
" > /cnb/stack.toml

RUN echo "\
[run-image]\n\
image = \"${registry}/company/stack:centos\"\n\
mirrors = []\n\
[build-image]\n\
stack-id = \"io.buildpacks.stacks.bionic\"\n\
mixins = []\n\
" > /cnb/mismatch-stack.toml

RUN echo "\
[run-image]\n\
image = \"gcr.io/paketobuildpacks/invalidimg:20\"\n\
mirrors = [\"${registry}/company/stack:bionic\"]\n\
[build-image]\n\
stack-id = \"io.buildpacks.stacks.bionic\"\n\
mixins = []\n\
" > /cnb/run-mirror-stack.toml

RUN echo "\
[run-image]\n\
image = \"localcompany/stack:bionic\"\n\
mirrors = []\n\
[build-image]\n\
stack-id = \"io.buildpacks.stacks.bionic\"\n\
mixins = []\n\
" > /cnb/local-bionic-stack.toml

RUN echo "[run-images" > /cnb/bad-stack.toml
33 changes: 33 additions & 0 deletions acceptance/testdata/analyzer/analyze-image/Dockerfile.windows
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,36 @@ ENV CNB_USER_ID=1
ENV CNB_GROUP_ID=1

ENV CNB_PLATFORM_API=${cnb_platform_api}

ARG registry

# write some stack.toml files to use in tests
RUN echo [run-image] > /cnb/stack.toml &\
echo image = "%registry%/company/stack:bionic" >> /cnb/stack.toml &\
echo mirrors = [] >> /cnb/stack.toml &\
echo [build-image] >> /cnb/stack.toml &\
echo stack-id = "io.buildpacks.stacks.bionic" >> /cnb/stack.toml &\
echo mixins = [] >> /cnb/stack.toml

RUN echo [run-image] > /cnb/mismatch-stack.toml &\
echo image = "%registry%/company/stack:centos" >> /cnb/mismatch-stack.toml &\
echo mirrors = [] >> /cnb/mismatch-stack.toml &\
echo [build-image] >> /cnb/mismatch-stack.toml &\
echo stack-id = "io.buildpacks.stacks.bionic" >> /cnb/mismatch-stack.toml &\
echo mixins = [] >> /cnb/mismatch-stack.toml

RUN echo [run-image] > /cnb/run-mirror-stack.toml &\
echo image = "gcr.io/paketobuildpacks/invalidimg:20" >> /cnb/run-mirror-stack.toml &\
echo mirrors = ["%registry%/company/stack:bionic"] >> /cnb/run-mirror-stack.toml &\
echo [build-image] >> /cnb/run-mirror-stack.toml &\
echo stack-id = "io.buildpacks.stacks.bionic" >> /cnb/run-mirror-stack.toml &\
echo mixins = [] >> /cnb/run-mirror-stack.toml

RUN echo [run-image] > /cnb/local-bionic-stack.toml &\
echo image = "localcompany/stack:bionic" >> /cnb/local-bionic-stack.toml &\
echo mirrors = [] >> /cnb/local-bionic-stack.toml &\
echo [build-image] >> /cnb/local-bionic-stack.toml &\
echo stack-id = "io.buildpacks.stacks.bionic" >> /cnb/local-bionic-stack.toml &\
echo mixins = [] >> /cnb/local-bionic-stack.toml

RUN echo [run-images > /cnb/bad-stack.toml
4 changes: 4 additions & 0 deletions acceptance/testdata/analyzer/run-image/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM scratch

ARG stackid
LABEL io.buildpacks.stack.id=${stackid}
5 changes: 5 additions & 0 deletions acceptance/testdata/analyzer/run-image/Dockerfile.windows
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM mcr.microsoft.com/windows/nanoserver:1809
USER ContainerAdministrator

ARG stackid
LABEL io.buildpacks.stack.id=${stackid}
1 change: 1 addition & 0 deletions cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const (
EnvSkipLayers = "CNB_ANALYZE_SKIP_LAYERS" // defaults to false
EnvSkipRestore = "CNB_SKIP_RESTORE" // defaults to false
EnvStackPath = "CNB_STACK_PATH"
EnvStackID = "CNB_STACK_ID"
EnvUID = "CNB_USER_ID"
EnvUseDaemon = "CNB_USE_DAEMON" // defaults to false
)
Expand Down
Loading

0 comments on commit 2cfc635

Please sign in to comment.