Skip to content

Commit

Permalink
Merge pull request #617 from buildpacks/jab/validate-stack
Browse files Browse the repository at this point in the history
Validate stack during analyze phase
  • Loading branch information
natalieparellano committed Jun 16, 2021
2 parents 162090f + 55c17a5 commit 7c5f36b
Show file tree
Hide file tree
Showing 14 changed files with 549 additions and 8 deletions.
199 changes: 198 additions & 1 deletion acceptance/analyzer_test.go
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,166 @@ 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), "some-image"}
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), "some-image"}

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),
"some-image",
) // #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),
"some-image",
) // #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), noAuthRegistry.RepoName("apprepo/myapp")} // 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", "some-image"}

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), "some-image"}

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),
"some-image",
) // #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
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
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
@@ -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
@@ -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
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

0 comments on commit 7c5f36b

Please sign in to comment.