diff --git a/remediation/docker/securedockerfile.go b/remediation/docker/securedockerfile.go index 6d9bbe5fc..53aaf2a16 100644 --- a/remediation/docker/securedockerfile.go +++ b/remediation/docker/securedockerfile.go @@ -71,6 +71,8 @@ func SecureDockerFile(inputDockerFile string) (*SecureDockerfileResponse, error) } new_cmd := strings.ReplaceAll(c.Original, c.Value[0], fmt.Sprintf("%s:%s@%s", image, tag, sha)) response.FinalOutput = strings.ReplaceAll(response.FinalOutput, c.Original, new_cmd) + // Revert the extra hash for already pinned docker images + response.FinalOutput = strings.ReplaceAll(response.FinalOutput, new_cmd+"@", c.Original+"@") response.IsChanged = true } diff --git a/remediation/docker/securedockerfile_test.go b/remediation/docker/securedockerfile_test.go index 1565f2945..d36ce9c79 100644 --- a/remediation/docker/securedockerfile_test.go +++ b/remediation/docker/securedockerfile_test.go @@ -45,6 +45,7 @@ func TestSecureDockerFile(t *testing.T) { }{ {fileName: "Dockerfile-not-pinned", isChanged: true}, {fileName: "Dockerfile-not-pinned-as", isChanged: true}, + {fileName: "Dockerfile-multiple-images", isChanged: true}, } for _, test := range tests { diff --git a/remediation/workflow/pin/pindocker.go b/remediation/workflow/pin/pindocker.go index 6e69ad6b6..2762e0859 100644 --- a/remediation/workflow/pin/pindocker.go +++ b/remediation/workflow/pin/pindocker.go @@ -28,7 +28,7 @@ func PinDocker(inputYaml string) (string, bool, error) { for jobName, job := range workflow.Jobs { for _, step := range job.Steps { - if len(step.Uses) > 0 && strings.HasPrefix(step.Uses, "docker://") { + if len(step.Uses) > 0 && strings.HasPrefix(step.Uses, "docker://") && !strings.Contains(step.Uses, "@") { localUpdated := false out, localUpdated = pinDocker(step.Uses, jobName, out) updated = updated || localUpdated @@ -42,7 +42,11 @@ func PinDocker(inputYaml string) (string, bool, error) { func pinDocker(action, jobName, inputYaml string) (string, bool) { updated := false leftOfAt := strings.Split(action, ":") - tag := leftOfAt[2] + tag := "latest" + // Reference :latest tag if no tag is present + if len(leftOfAt) > 2 { + tag = leftOfAt[2] + } image := leftOfAt[1][2:] ref, err := name.ParseReference(image, name.WithDefaultTag(tag)) @@ -62,8 +66,11 @@ func pinDocker(action, jobName, inputYaml string) (string, bool) { return inputYaml, updated } - pinnedAction := fmt.Sprintf("%s:%s@%s # %s", leftOfAt[0], leftOfAt[1], imghash.String(), tag) + pinnedAction := fmt.Sprintf("%s:%s:%s@%s", leftOfAt[0], leftOfAt[1], tag, imghash.String()) inputYaml = strings.ReplaceAll(inputYaml, action, pinnedAction) + // Revert the extra hash for already pinned docker actions + inputYaml = strings.ReplaceAll(inputYaml, pinnedAction+"@", action+"@") + inputYaml = strings.ReplaceAll(inputYaml, pinnedAction+":", action+":") updated = !strings.EqualFold(action, pinnedAction) return inputYaml, updated } diff --git a/testfiles/addworkflow/expected-dependency-review.yml b/testfiles/addworkflow/expected-dependency-review.yml index fe461b424..c6a105d72 100644 --- a/testfiles/addworkflow/expected-dependency-review.yml +++ b/testfiles/addworkflow/expected-dependency-review.yml @@ -1,9 +1,11 @@ # Dependency Review Action # -# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# This Action will scan dependency manifest files that change as part of a Pull Request, +# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. # # Source repository: https://github.com/actions/dependency-review-action -# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement name: 'Dependency Review' on: [pull_request] diff --git a/testfiles/dockerfiles/input/Dockerfile-multiple-images b/testfiles/dockerfiles/input/Dockerfile-multiple-images new file mode 100644 index 000000000..ac5b60561 --- /dev/null +++ b/testfiles/dockerfiles/input/Dockerfile-multiple-images @@ -0,0 +1,31 @@ +FROM python:3.7 AS builder + +RUN apt-get update +RUN apt-get install -y build-essential autoconf libxml2-dev libssl-dev zlib1g-dev curl + +# Install bomutils +RUN curl -L https://github.com/hogliux/bomutils/archive/0.2.tar.gz > bomutils.tar.gz && \ + echo "fb1f4ae37045eaa034ddd921ef6e16fb961e95f0364e5d76c9867bc8b92eb8a4 bomutils.tar.gz" | sha256sum --check && \ + tar -xzf bomutils.tar.gz +RUN cd bomutils-0.2 && make && make install + +# Install xar +RUN curl -L https://github.com/mackyle/xar/archive/refs/tags/xar-1.6.1.tar.gz > xar.tar.gz && \ + echo "5e7d50dab73f5cb1713b49fa67c455c2a0dd2b0a7770cbc81b675e21f6210e25 xar.tar.gz" | sha256sum --check && \ + tar -xzf xar.tar.gz +# Note this needs patching due to newer version of OpenSSL +# See https://github.com/mackyle/xar/pull/23 +COPY patch.txt . +RUN cd xar-xar-1.6.1/xar && patch < ../../patch.txt && autoconf && ./configure && make && make install + + +FROM python:3.7 + +FROM python:3.7 + +FROM python:3.7 + +RUN apt-get update && apt-get install -y --no-install-recommends libxml2 && rm -rf /var/lib/apt/lists/* +COPY --from=builder /usr/bin /usr/bin/ +COPY --from=builder /usr/local/bin /usr/local/bin/ +COPY --from=builder /usr/local/lib /usr/local/lib/ \ No newline at end of file diff --git a/testfiles/dockerfiles/output/Dockerfile-multiple-images b/testfiles/dockerfiles/output/Dockerfile-multiple-images new file mode 100644 index 000000000..708b56abf --- /dev/null +++ b/testfiles/dockerfiles/output/Dockerfile-multiple-images @@ -0,0 +1,31 @@ +FROM python:3.7@sha256:5fb6f4b9d73ddeb0e431c938bee25c69157a1e3c880a81ff72c43a8055628de5 AS builder + +RUN apt-get update +RUN apt-get install -y build-essential autoconf libxml2-dev libssl-dev zlib1g-dev curl + +# Install bomutils +RUN curl -L https://github.com/hogliux/bomutils/archive/0.2.tar.gz > bomutils.tar.gz && \ + echo "fb1f4ae37045eaa034ddd921ef6e16fb961e95f0364e5d76c9867bc8b92eb8a4 bomutils.tar.gz" | sha256sum --check && \ + tar -xzf bomutils.tar.gz +RUN cd bomutils-0.2 && make && make install + +# Install xar +RUN curl -L https://github.com/mackyle/xar/archive/refs/tags/xar-1.6.1.tar.gz > xar.tar.gz && \ + echo "5e7d50dab73f5cb1713b49fa67c455c2a0dd2b0a7770cbc81b675e21f6210e25 xar.tar.gz" | sha256sum --check && \ + tar -xzf xar.tar.gz +# Note this needs patching due to newer version of OpenSSL +# See https://github.com/mackyle/xar/pull/23 +COPY patch.txt . +RUN cd xar-xar-1.6.1/xar && patch < ../../patch.txt && autoconf && ./configure && make && make install + + +FROM python:3.7@sha256:5fb6f4b9d73ddeb0e431c938bee25c69157a1e3c880a81ff72c43a8055628de5 + +FROM python:3.7@sha256:5fb6f4b9d73ddeb0e431c938bee25c69157a1e3c880a81ff72c43a8055628de5 + +FROM python:3.7@sha256:5fb6f4b9d73ddeb0e431c938bee25c69157a1e3c880a81ff72c43a8055628de5 + +RUN apt-get update && apt-get install -y --no-install-recommends libxml2 && rm -rf /var/lib/apt/lists/* +COPY --from=builder /usr/bin /usr/bin/ +COPY --from=builder /usr/local/bin /usr/local/bin/ +COPY --from=builder /usr/local/lib /usr/local/lib/ \ No newline at end of file diff --git a/testfiles/pindockers/input/dockeraction.yml b/testfiles/pindockers/input/dockeraction.yml index 5b57ce5c8..9f7d5f263 100644 --- a/testfiles/pindockers/input/dockeraction.yml +++ b/testfiles/pindockers/input/dockeraction.yml @@ -38,12 +38,12 @@ jobs: with: args: sh -c "cd conker && make --jobs" - name: Perform make replace - uses: docker://docker.io/markstreet/conker:latest + uses: docker://docker.io/markstreet/conker:latest@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 with: args: sh -c "cd conker && make replace" - name: Perform make - uses: docker://docker.io/markstreet/conker:latest + uses: docker://docker.io/markstreet/conker with: args: make --jobs diff --git a/testfiles/pindockers/output/dockeraction.yml b/testfiles/pindockers/output/dockeraction.yml index f9ba6503b..9628fb482 100644 --- a/testfiles/pindockers/output/dockeraction.yml +++ b/testfiles/pindockers/output/dockeraction.yml @@ -25,30 +25,30 @@ jobs: run: echo ${{ secrets.CONKER_BASEROM_US }} | openssl enc -d -aes-256-cbc -pass stdin -pbkdf2 -in baserom/baserom.us.z64.aes -out baserom.us.z64 - name: Perform make extract (rom) - uses: docker://docker.io/markstreet/conker@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 # latest + uses: docker://docker.io/markstreet/conker:latest@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 with: args: make extract - name: Perform make extract (code) - uses: docker://docker.io/markstreet/conker@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 # latest + uses: docker://docker.io/markstreet/conker:latest@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 with: args: sh -c "cd conker && make extract" - name: Perform make (code) - uses: docker://docker.io/markstreet/conker@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 # latest + uses: docker://docker.io/markstreet/conker:latest@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 with: args: sh -c "cd conker && make --jobs" - name: Perform make replace - uses: docker://docker.io/markstreet/conker@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 # latest + uses: docker://docker.io/markstreet/conker:latest@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 with: args: sh -c "cd conker && make replace" - name: Perform make - uses: docker://docker.io/markstreet/conker@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 # latest + uses: docker://docker.io/markstreet/conker:latest@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 with: args: make --jobs - name: Create progress.csv - uses: docker://docker.io/markstreet/conker@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 # latest + uses: docker://docker.io/markstreet/conker:latest@sha256:1efef3bbdd297d1b321b9b4559092d3131961913bc68b7c92b681b4783d563f0 with: args: sh -c "cd conker && make progress" diff --git a/testfiles/pindockers/output/gcraction.yml b/testfiles/pindockers/output/gcraction.yml index 67edebdd0..72373830c 100644 --- a/testfiles/pindockers/output/gcraction.yml +++ b/testfiles/pindockers/output/gcraction.yml @@ -19,12 +19,12 @@ jobs: go-version: ${{ env.GO_VERSION }} - name: Container structure test (scratch) - uses: docker://gcr.io/gcp-runtimes/container-structure-test@sha256:4affda1c8f058f8d6c86dcad965cdb438a3d1d9a982828ff6737ea492b6bc8ce # latest + uses: docker://gcr.io/gcp-runtimes/container-structure-test:latest@sha256:4affda1c8f058f8d6c86dcad965cdb438a3d1d9a982828ff6737ea492b6bc8ce with: args: 'test --image ffurrer/semver:latest --config test/semver_container_test.yml' - name: Container structure test (alpine) - uses: docker://gcr.io/gcp-runtimes/container-structure-test@sha256:4affda1c8f058f8d6c86dcad965cdb438a3d1d9a982828ff6737ea492b6bc8ce # latest + uses: docker://gcr.io/gcp-runtimes/container-structure-test:latest@sha256:4affda1c8f058f8d6c86dcad965cdb438a3d1d9a982828ff6737ea492b6bc8ce with: args: 'test --image ffurrer/semver:alpine --config test/semver_alpine_container_test.yml' diff --git a/testfiles/pindockers/output/ghcraction.yml b/testfiles/pindockers/output/ghcraction.yml index cb8a0cd86..da9d85ea0 100644 --- a/testfiles/pindockers/output/ghcraction.yml +++ b/testfiles/pindockers/output/ghcraction.yml @@ -12,6 +12,6 @@ jobs: - name: Checkout uses: actions/checkout@v1 - name: Integration test - uses: docker://ghcr.io/step-security/integration-test/int@sha256:f1f95204dc1f12a41eaf41080185e2d289596b3e7637a8c50a3f6fbe17f99649 # latest + uses: docker://ghcr.io/step-security/integration-test/int:latest@sha256:f1f95204dc1f12a41eaf41080185e2d289596b3e7637a8c50a3f6fbe17f99649 env: PAT: ${{ secrets.PAT }} \ No newline at end of file diff --git a/workflow-templates/dependency-review.yml b/workflow-templates/dependency-review.yml index fe461b424..c6a105d72 100644 --- a/workflow-templates/dependency-review.yml +++ b/workflow-templates/dependency-review.yml @@ -1,9 +1,11 @@ # Dependency Review Action # -# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# This Action will scan dependency manifest files that change as part of a Pull Request, +# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. # # Source repository: https://github.com/actions/dependency-review-action -# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement name: 'Dependency Review' on: [pull_request]