├── examples ├── scratch-base-vanilla │ ├── Dockerfile │ ├── oci-image-manifest-layer-history.json │ ├── oci-image-manifest-layer-history-slsa.json │ ├── oci-image-manifest-layer-history-simplified.json │ ├── simple-image-history.txt │ └── oci-image-manifest.json ├── postgres-base-vanilla │ ├── Dockerfile │ ├── oci-image-manifest.json │ ├── oci-image-manifest-layer-history-simplified.json │ └── oci-image-manifest-layer-history.json ├── scratch-base-singlestage │ ├── Dockerfile │ ├── oci-image-manifest.json │ ├── oci-image-manifest-layer-history-simplified.json │ ├── simple-image-history.txt │ ├── oci-image-manifest-layer-history.json │ └── oci-image-manifest-layer-history-slsa.json ├── postgres-base-singlestage │ ├── Dockerfile │ ├── oci-image-manifest.json │ └── oci-image-manifest-layer-history-simplified.json ├── scratch-base-multistage │ ├── oci-image-manifest.json │ ├── Dockerfile │ ├── simple-image-history.txt │ ├── oci-image-manifest-layer-history-simplified.json │ └── oci-image-manifest-layer-history.json └── postgres-base-multistage │ ├── Dockerfile │ ├── oci-image-manifest.json │ └── oci-image-manifest-layer-history-simplified.json ├── CODEOWNERS ├── cmd └── cli │ ├── main.go │ ├── root.go │ └── generate.go ├── Makefile ├── docs ├── media │ └── readme │ │ ├── unix-philosophy-provenance-sbom.png │ │ ├── provenance-doc-generation-and-push.png │ │ ├── image-formats-and-sboms-no-build-provenance.png │ │ ├── layer-history-foo-bar-ubuntu-imported-image.drawio.png │ │ ├── green-during-image-build-but-red-in-container-registry.png │ │ ├── layer-history-myapp-aspnet-mariner-scratch-image.drawio.png │ │ ├── layer-history-foo-bar-ubuntu-imported-image-vuln-in-ubuntu.drawio.png │ │ ├── layer-history-foo-bar-ubuntu-imported-image-with-provenance.drawio.png │ │ ├── layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-aspnet.drawio.png │ │ ├── layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-mariner.drawio.png │ │ ├── layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-myapp.drawio.png │ │ ├── layer-history-myapp-aspnet-mariner-scratch-image-with-provenance.drawio.png │ │ ├── image-layer-provenance-document-stored-as-oras-reference-artifact.drawio.png │ │ ├── image-layer-provenance-document-stored-as-oras-reference-artifact.drawio │ │ ├── layer-history-myapp-aspnet-mariner-scratch-image.drawio │ │ ├── layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-myapp.drawio │ │ ├── layer-history-foo-bar-ubuntu-imported-image-with-provenance.drawio │ │ ├── layer-history-myapp-aspnet-mariner-scratch-image-with-provenance.drawio │ │ ├── layer-history-foo-bar-ubuntu-imported-image-vuln-in-ubuntu.drawio │ │ ├── layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-aspnet.drawio │ │ └── layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-mariner.drawio └── current-limitations.md ├── SUPPORT.md ├── .github └── workflows │ ├── main.yml │ └── release.yml ├── CODE_OF_CONDUCT.md ├── .gitignore ├── scripts ├── acr-build-push-all-examples.sh ├── acr-generate-history-all-examples.sh ├── build-push-all-examples.sh └── generate-history-all-examples.sh ├── LICENSE ├── image ├── slsa │ ├── types.go │ └── slsa.go ├── history │ ├── constants.go │ └── types.go └── client │ └── client.go ├── go.mod ├── SECURITY.md ├── CONTRIBUTING.md └── go.sum /examples/scratch-base-vanilla/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM scratch 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @johnsonshi @toddysm @lachie83 @jeremyrickard 2 | -------------------------------------------------------------------------------- /cmd/cli/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | execute() 5 | } 6 | -------------------------------------------------------------------------------- /examples/scratch-base-vanilla/oci-image-manifest-layer-history.json: -------------------------------------------------------------------------------- 1 | null 2 | -------------------------------------------------------------------------------- /examples/scratch-base-vanilla/oci-image-manifest-layer-history-slsa.json: -------------------------------------------------------------------------------- 1 | null 2 | -------------------------------------------------------------------------------- /examples/scratch-base-vanilla/oci-image-manifest-layer-history-simplified.json: -------------------------------------------------------------------------------- 1 | null 2 | -------------------------------------------------------------------------------- /examples/postgres-base-vanilla/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/library/postgres:14-bullseye 2 | -------------------------------------------------------------------------------- /examples/scratch-base-vanilla/simple-image-history.txt: -------------------------------------------------------------------------------- 1 | IMAGE CREATED AT CREATED BY SIZE COMMENT 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build-cli 2 | build-cli: 3 | go build -v -o ./bin/image-layer-dockerfile-history ./cmd/cli 4 | chmod +x ./bin/image-layer-dockerfile-history 5 | -------------------------------------------------------------------------------- /docs/media/readme/unix-philosophy-provenance-sbom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/unix-philosophy-provenance-sbom.png -------------------------------------------------------------------------------- /docs/media/readme/provenance-doc-generation-and-push.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/provenance-doc-generation-and-push.png -------------------------------------------------------------------------------- /docs/media/readme/image-formats-and-sboms-no-build-provenance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/image-formats-and-sboms-no-build-provenance.png -------------------------------------------------------------------------------- /docs/media/readme/layer-history-foo-bar-ubuntu-imported-image.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/layer-history-foo-bar-ubuntu-imported-image.drawio.png -------------------------------------------------------------------------------- /docs/media/readme/green-during-image-build-but-red-in-container-registry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/green-during-image-build-but-red-in-container-registry.png -------------------------------------------------------------------------------- /docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image.drawio.png -------------------------------------------------------------------------------- /docs/media/readme/layer-history-foo-bar-ubuntu-imported-image-vuln-in-ubuntu.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/layer-history-foo-bar-ubuntu-imported-image-vuln-in-ubuntu.drawio.png -------------------------------------------------------------------------------- /docs/media/readme/layer-history-foo-bar-ubuntu-imported-image-with-provenance.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/layer-history-foo-bar-ubuntu-imported-image-with-provenance.drawio.png -------------------------------------------------------------------------------- /docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-aspnet.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-aspnet.drawio.png -------------------------------------------------------------------------------- /docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-mariner.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-mariner.drawio.png -------------------------------------------------------------------------------- /docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-myapp.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-myapp.drawio.png -------------------------------------------------------------------------------- /docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-with-provenance.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-with-provenance.drawio.png -------------------------------------------------------------------------------- /docs/media/readme/image-layer-provenance-document-stored-as-oras-reference-artifact.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deislabs/image-layer-provenance/HEAD/docs/media/readme/image-layer-provenance-document-stored-as-oras-reference-artifact.drawio.png -------------------------------------------------------------------------------- /examples/scratch-base-vanilla/oci-image-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.docker.distribution.manifest.v2+json", 4 | "config": { 5 | "mediaType": "application/vnd.docker.container.image.v1+json", 6 | "size": 229, 7 | "digest": "sha256:71de1148337f4d1845be01eb4caf15d78e4eb15a1ab96030809826698a5b7e30" 8 | }, 9 | "layers": [] 10 | } 11 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## How to file issues and get help 4 | 5 | ### GitHub Issues 6 | 7 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing GitHub Issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new Issue. 8 | 9 | The project maintainers will respond to the best of their abilities. 10 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: actions/setup-go@v3 17 | with: 18 | go-version: '^1.18.0' 19 | - run: go version 20 | 21 | - name: Build CLI 22 | run: make build-cli 23 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | .vscode/ 3 | 4 | # The following entries are from 5 | # https://github.com/github/gitignore/blob/main/Go.gitignore 6 | 7 | # Binaries for programs and plugins 8 | *.exe 9 | *.exe~ 10 | *.dll 11 | *.so 12 | *.dylib 13 | 14 | # Test binary, built with `go test -c` 15 | *.test 16 | 17 | # Output of the go coverage tool, specifically when used with LiteIDE 18 | *.out 19 | 20 | # Dependency directories (remove the comment below to include it) 21 | # vendor/ 22 | 23 | # Go workspace file 24 | go.work 25 | -------------------------------------------------------------------------------- /examples/scratch-base-singlestage/Dockerfile: -------------------------------------------------------------------------------- 1 | ############################################################################################## 2 | # Primary Stage – Primary Base Image: scratch 3 | ############################################################################################## 4 | FROM scratch 5 | 6 | ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz 7 | 8 | EXPOSE 5432/tcp 9 | EXPOSE 5432/udp 10 | ENV POSTGRES_ENV_1="postgres_env_val_1" 11 | 12 | ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz 13 | 14 | EXPOSE 5433/tcp 15 | EXPOSE 5433/udp 16 | ENV POSTGRES_ENV_2="postgres_env_val_2" 17 | 18 | ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz 19 | 20 | EXPOSE 5434/tcp 21 | EXPOSE 5434/udp 22 | ENV POSTGRES_ENV_3="postgres_env_val_3" 23 | -------------------------------------------------------------------------------- /scripts/acr-build-push-all-examples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -aueo pipefail 4 | 5 | if [ -z "$1" ]; then 6 | echo "Builds and pushes all images in the examples directory to an Azure Container Registry (ACR)." 7 | echo "Usage: $0 , e.g. $0 myregistry (not the URL, just the name)" 8 | exit 1 9 | fi 10 | 11 | acr_registry_name="$1" 12 | 13 | acr_access_token_output=$(az acr login --name "$acr_registry_name" --expose-token) 14 | acr_access_token_username="00000000-0000-0000-0000-000000000000" 15 | acr_access_token=$(echo "$acr_access_token_output" | jq --raw-output ".accessToken") 16 | acr_login_server=$(echo "$acr_access_token_output" | jq --raw-output ".loginServer") 17 | 18 | echo "$acr_access_token" | docker login "$acr_login_server" -u "$acr_access_token_username" --password-stdin 19 | 20 | ./scripts/build-push-all-examples.sh "$acr_login_server" 21 | -------------------------------------------------------------------------------- /cmd/cli/root.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "io" 6 | "os" 7 | 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | func newRootCmd(stdin io.Reader, stdout io.Writer, stderr io.Writer, args []string) *cobra.Command { 12 | cobraCmd := &cobra.Command{ 13 | Use: "image-layer-dockerfile-history", 14 | Short: "Command-line tool that shows the exact Dockerfile commands for each OCI Image Manifest Layer of a container image.", 15 | } 16 | 17 | cobraCmd.PersistentFlags().AddGoFlagSet(flag.CommandLine) 18 | flags := cobraCmd.PersistentFlags() 19 | 20 | cobraCmd.AddCommand( 21 | newGenerateCmd(stdin, stdout, stderr, args), 22 | ) 23 | 24 | _ = flags.Parse(args) 25 | 26 | return cobraCmd 27 | } 28 | 29 | func execute() { 30 | rootCmd := newRootCmd(os.Stdin, os.Stdout, os.Stderr, os.Args[1:]) 31 | err := rootCmd.Execute() 32 | if err != nil { 33 | os.Exit(1) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /scripts/acr-generate-history-all-examples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -aueo pipefail 4 | 5 | if [ -z "$1" ]; then 6 | echo "Generates the OCI image manifest layer histories for all images referenced in the examples directory." 7 | echo "Usage: $0 , e.g. $0 myregistry (not the URL, just the name)" 8 | exit 1 9 | fi 10 | 11 | acr_registry_name="$1" 12 | 13 | acr_access_token_output=$(az acr login --name "$acr_registry_name" --expose-token) 14 | acr_access_token_username="00000000-0000-0000-0000-000000000000" 15 | acr_access_token=$(echo "$acr_access_token_output" | jq --raw-output ".accessToken") 16 | acr_login_server=$(echo "$acr_access_token_output" | jq --raw-output ".loginServer") 17 | 18 | echo "$acr_access_token" | docker login "$acr_login_server" -u "$acr_access_token_username" --password-stdin 19 | 20 | ./scripts/generate-history-all-examples.sh "$acr_login_server" "$acr_access_token_username" "$acr_access_token" 21 | -------------------------------------------------------------------------------- /examples/scratch-base-singlestage/oci-image-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.docker.distribution.manifest.v2+json", 4 | "config": { 5 | "mediaType": "application/vnd.docker.container.image.v1+json", 6 | "size": 2565, 7 | "digest": "sha256:1cecc87939b2aff159f1f166a7b45315b3d69ffd2642441de8e5bc0b7ba625fc" 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 12 | "size": 1100327, 13 | "digest": "sha256:7942f3be722fa3927b29ccc51521f0f0d9b0b8979fc4148d3d94f05acc0bdf44" 14 | }, 15 | { 16 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 17 | "size": 2727414, 18 | "digest": "sha256:5a2bf799221e80ef7d379a58541383020761546107861b322d0d30c34840c74e" 19 | }, 20 | { 21 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 22 | "size": 22473758, 23 | "digest": "sha256:bef044d3345e7eef96b2658e006eb3761a621be5c069e559e975e98c154e5d0b" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /scripts/build-push-all-examples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -aueo pipefail 4 | 5 | if [ -z "$1" ]; then 6 | echo "Builds and pushes all images in the examples directory to the registry." 7 | echo "Usage: $0 , e.g. $0 myregistry.registry.io" 8 | exit 1 9 | fi 10 | 11 | registry_url="$1" 12 | namespace="$registry_url/image-manifest-layer-history" 13 | 14 | example_image_directory_names=( 15 | "examples/postgres-base-multistage" 16 | "examples/postgres-base-singlestage" 17 | "examples/postgres-base-vanilla" 18 | "examples/scratch-base-multistage" 19 | "examples/scratch-base-singlestage" 20 | "examples/scratch-base-vanilla" 21 | ) 22 | 23 | for example_image_directory_name in "${example_image_directory_names[@]}"; do 24 | image_ref="$namespace/$example_image_directory_name:latest" 25 | 26 | echo "[*] Building and pushing $image_ref" 27 | 28 | docker build -t "$image_ref" "$example_image_directory_name" 29 | docker push "$image_ref" 30 | done 31 | -------------------------------------------------------------------------------- /examples/postgres-base-singlestage/Dockerfile: -------------------------------------------------------------------------------- 1 | ############################################################################################## 2 | # Primary Stage – Primary Base Image: postgres 3 | ############################################################################################## 4 | FROM docker.io/library/postgres:14-bullseye 5 | 6 | ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz 7 | RUN echo "hello" > /hello.txt 8 | 9 | EXPOSE 5432/tcp 10 | EXPOSE 5432/udp 11 | ENV POSTGRES_ENV_1="postgres_env_val_1" 12 | 13 | ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz 14 | RUN echo "breakfast" > /breakfast.txt 15 | 16 | EXPOSE 5433/tcp 17 | EXPOSE 5433/udp 18 | ENV POSTGRES_ENV_2="postgres_env_val_2" 19 | 20 | ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz 21 | RUN echo "goodbye" > /goodbye.txt 22 | 23 | EXPOSE 5434/tcp 24 | EXPOSE 5434/udp 25 | ENV POSTGRES_ENV_3="postgres_env_val_3" 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /image/slsa/types.go: -------------------------------------------------------------------------------- 1 | package slsa 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/johnsonshi/image-manifest-layer-history/image/history" 7 | ) 8 | 9 | type ImageManifestLayerSlsaProvenance struct { 10 | LayerHistory history.ImageManifestLayerDockerfileCommandsHistory `json:"LayerHistory"` 11 | BuilderID string `json:"BuilderID"` 12 | BuildType string `json:"BuildType"` 13 | BuildInvocationID string `json:"BuildInvocationID"` 14 | BuildStartedOn *time.Time `json:"BuildStartedOn"` 15 | BuildFinishedOn *time.Time `json:"BuildFinishedOn"` 16 | RepoURIContainingImageSource string `json:"RepoURIContainingImageSource"` 17 | RepoGitCommit string `json:"RepoGitCommit"` 18 | RepoPathToImageSource string `json:"RepoPathToImageSource"` 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | tags: 5 | - "v*" 6 | 7 | jobs: 8 | version: 9 | name: Set Version from git ref 10 | runs-on: ubuntu-latest 11 | outputs: 12 | version: ${{ steps.version.outputs.version }} 13 | steps: 14 | - id: version 15 | run: echo "::set-output name=version::$(sed 's#^refs/tags/\(.*\)#\1#' <<< '${{ github.ref }}')" 16 | 17 | binaries: 18 | name: Binaries 19 | runs-on: ubuntu-latest 20 | needs: version 21 | env: 22 | VERSION: ${{ needs.version.outputs.version }} 23 | 24 | steps: 25 | - uses: actions/checkout@v3 26 | - uses: actions/setup-go@v3 27 | with: 28 | go-version: '^1.18.0' 29 | - run: go version 30 | 31 | - name: Build CLI 32 | run: make build-cli 33 | 34 | - name: Create Release 35 | id: create_release 36 | uses: ncipollo/release-action@v1 37 | with: 38 | tag: ${{ env.VERSION }} 39 | name: ${{ env.VERSION }} 40 | generateReleaseNotes: true 41 | prerelease: ${{ contains(env.VERSION, '-alpha.') || contains(env.VERSION, '-beta.') || contains(env.VERSION, '-rc.') || contains(env.VERSION, '-nightly.') }} 42 | artifacts: "bin/*" 43 | -------------------------------------------------------------------------------- /image/history/constants.go: -------------------------------------------------------------------------------- 1 | package history 2 | 3 | const ( 4 | // FROMPrimaryBaseImageLayer is the layer creation type for 5 | // primary base image layers (layers created by `FROM `). 6 | FROMPrimaryBaseImageLayer LayerCreationType = "FROM-PrimaryBaseImageLayer" 7 | 8 | // COPYFromMultistageBuildStageLayer is the layer creation type for 9 | // COPY from multistage build stage layers (layers created by `COPY --from= `). 10 | COPYFromMultistageBuildStageLayer LayerCreationType = "COPY-FromMultistageBuildStageLayer" 11 | 12 | // COPYCommandLayer is the layer creation type for 13 | // for non-multistage COPY commands (layers created by `COPY `). 14 | COPYCommandLayer LayerCreationType = "COPY-CommandLayer" 15 | 16 | // ADDCommandLayer is the layer creation type for 17 | // for layers created by `ADD`. 18 | ADDCommandLayer LayerCreationType = "ADD-CommandLayer" 19 | 20 | // RUNCommandLayer is the layer creation type for 21 | // for layers created by `RUN`. 22 | RUNCommandLayer LayerCreationType = "RUN-CommandLayer" 23 | 24 | // UNKNOWNDockerfileCommandLayer is the layer creation type for 25 | // for layers created by unknown Dockerfile commands. 26 | // This should not happen as this would imply that commands other than 27 | // {FROM, COPY, ADD, RUN} created a layer, which is impossible. 28 | UNKNOWNDockerfileCommandLayer LayerCreationType = "UNKNOWN-DockerfileCommandLayer" 29 | ) 30 | -------------------------------------------------------------------------------- /image/slsa/slsa.go: -------------------------------------------------------------------------------- 1 | package slsa 2 | 3 | import ( 4 | intoto "github.com/in-toto/in-toto-golang/in_toto" 5 | slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" 6 | ) 7 | 8 | func (s *ImageManifestLayerSlsaProvenance) GetImageManifestLayerSlsaProvenance() (*intoto.ProvenanceStatement, error) { 9 | return &intoto.ProvenanceStatement{ 10 | StatementHeader: intoto.StatementHeader{ 11 | Type: intoto.StatementInTotoV01, 12 | PredicateType: slsa.PredicateSLSAProvenance, 13 | Subject: []intoto.Subject{ 14 | { 15 | Name: string(s.LayerHistory.LayerDescriptor.Digest), 16 | Digest: slsa.DigestSet{ 17 | string(s.LayerHistory.LayerDescriptor.Digest.Algorithm()): s.LayerHistory.LayerDescriptor.Digest.Encoded(), 18 | }, 19 | }, 20 | }, 21 | }, 22 | Predicate: slsa.ProvenancePredicate{ 23 | Builder: slsa.ProvenanceBuilder{ID: s.BuilderID}, 24 | BuildType: s.BuildType, 25 | Invocation: slsa.ProvenanceInvocation{ 26 | ConfigSource: slsa.ConfigSource{ 27 | URI: s.RepoURIContainingImageSource, 28 | Digest: slsa.DigestSet{"commit": s.RepoGitCommit}, 29 | EntryPoint: s.RepoPathToImageSource, 30 | }, 31 | // NOTE: Invocation.Parameters is the only field that is customizable and allows for a custom JSON schema. 32 | Parameters: map[string]interface{}{ 33 | "LayerHistory": s.LayerHistory, 34 | }, 35 | }, 36 | Metadata: &slsa.ProvenanceMetadata{ 37 | BuildInvocationID: s.BuildInvocationID, 38 | BuildStartedOn: s.BuildStartedOn, 39 | BuildFinishedOn: s.BuildFinishedOn, 40 | }, 41 | }, 42 | }, nil 43 | } 44 | -------------------------------------------------------------------------------- /examples/scratch-base-multistage/oci-image-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.docker.distribution.manifest.v2+json", 4 | "config": { 5 | "mediaType": "application/vnd.docker.container.image.v1+json", 6 | "size": 3441, 7 | "digest": "sha256:90d8f10882cad534393695f5ebf45ddd3873f2562121c0775ab0764572da1bb0" 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 12 | "size": 1100327, 13 | "digest": "sha256:7942f3be722fa3927b29ccc51521f0f0d9b0b8979fc4148d3d94f05acc0bdf44" 14 | }, 15 | { 16 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 17 | "size": 115, 18 | "digest": "sha256:f0007634565752c57366439569258a233a2e5a8c209dd29d9df9d7daaf161c2e" 19 | }, 20 | { 21 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 22 | "size": 115, 23 | "digest": "sha256:718e9aa42f6902fdde956e8435f0f34857708fce6ef461a197ea2f22bf19e3f0" 24 | }, 25 | { 26 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 27 | "size": 2727414, 28 | "digest": "sha256:127c4f8180baccafd36c1ead43d6fd1cc5859f650f5d6867809e39b5d76d11ae" 29 | }, 30 | { 31 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 32 | "size": 115, 33 | "digest": "sha256:50b974a802e3f9089177263e1024a0f253949993d95bdfba97d923fc0b111a22" 34 | }, 35 | { 36 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 37 | "size": 115, 38 | "digest": "sha256:1fa6c8ba07a43357be8a6b0ab93fe7240256c6944d8dc7ff6d56460a902345e5" 39 | }, 40 | { 41 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 42 | "size": 22473758, 43 | "digest": "sha256:336f60ca2fdf8014edca08c0461e7491080d74554a3830e7d9167f0c2ccfb1f4" 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/johnsonshi/image-manifest-layer-history 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/asottile/dockerfile v3.1.0+incompatible 7 | github.com/docker/docker v20.10.17+incompatible 8 | github.com/in-toto/in-toto-golang v0.4.0-prerelease 9 | github.com/opencontainers/go-digest v1.0.0 10 | github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 11 | github.com/spf13/cobra v1.5.0 12 | oras.land/oras-go/v2 v2.0.0-rc.1 13 | ) 14 | 15 | require ( 16 | github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect 17 | github.com/Microsoft/go-winio v0.5.1 // indirect 18 | github.com/containerd/typeurl v1.0.2 // indirect 19 | github.com/docker/distribution v2.8.1+incompatible // indirect 20 | github.com/docker/go-connections v0.4.0 // indirect 21 | github.com/docker/go-units v0.4.0 // indirect 22 | github.com/gogo/protobuf v1.3.2 // indirect 23 | github.com/golang/protobuf v1.5.2 // indirect 24 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 25 | github.com/moby/buildkit v0.10.3 // indirect 26 | github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86 // indirect 27 | github.com/oras-project/artifacts-spec v1.0.0-rc.1.0.20220707054150-eddd1d8790c9 // indirect 28 | github.com/pkg/errors v0.9.1 // indirect 29 | github.com/secure-systems-lab/go-securesystemslib v0.1.0 // indirect 30 | github.com/shibumi/go-pathspec v1.2.0 // indirect 31 | github.com/sirupsen/logrus v1.9.0 // indirect 32 | github.com/spf13/pflag v1.0.5 // indirect 33 | golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect 34 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect 35 | golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect 36 | google.golang.org/protobuf v1.27.1 // indirect 37 | gotest.tools/v3 v3.3.0 // indirect 38 | ) 39 | -------------------------------------------------------------------------------- /examples/scratch-base-singlestage/oci-image-manifest-layer-history-simplified.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "LayerDigest": "sha256:7942f3be722fa3927b29ccc51521f0f0d9b0b8979fc4148d3d94f05acc0bdf44", 4 | "DockerfileLayerCreationType": "ADD-CommandLayer", 5 | "DockerfileCommands": [ 6 | "ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz" 7 | ], 8 | "BaseImage": "", 9 | "AttributedEntity": { 10 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 11 | } 12 | }, 13 | { 14 | "LayerDigest": "sha256:5a2bf799221e80ef7d379a58541383020761546107861b322d0d30c34840c74e", 15 | "DockerfileLayerCreationType": "ADD-CommandLayer", 16 | "DockerfileCommands": [ 17 | "ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz" 18 | ], 19 | "BaseImage": "", 20 | "AttributedEntity": { 21 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 22 | } 23 | }, 24 | { 25 | "LayerDigest": "sha256:bef044d3345e7eef96b2658e006eb3761a621be5c069e559e975e98c154e5d0b", 26 | "DockerfileLayerCreationType": "ADD-CommandLayer", 27 | "DockerfileCommands": [ 28 | "ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz" 29 | ], 30 | "BaseImage": "", 31 | "AttributedEntity": { 32 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 33 | } 34 | } 35 | ] 36 | -------------------------------------------------------------------------------- /examples/scratch-base-multistage/Dockerfile: -------------------------------------------------------------------------------- 1 | ############################################################################################## 2 | # Multistage Build Stage (Builder 1) – Multistage Base Image: node 3 | ############################################################################################## 4 | FROM docker.io/library/node:18-bullseye 5 | 6 | RUN echo "builder1Foo" > /builder1Foo.txt 7 | 8 | EXPOSE 8080/tcp 9 | EXPOSE 8080/udp 10 | ENV NODE_ENV_1="node_env_val_1" 11 | 12 | RUN echo "builder1Bar" > /builder1Bar.txt 13 | 14 | ############################################################################################## 15 | # Multistage Build Stage (Builder 2) – Multistage Base Image: python 16 | ############################################################################################## 17 | FROM docker.io/library/python:3-bullseye as builder2 18 | 19 | RUN echo "builder2Foo" > /builder2Foo.txt 20 | 21 | EXPOSE 5000/tcp 22 | EXPOSE 5000/udp 23 | ENV PYTHON_ENV_1="python_env_val_1" 24 | 25 | RUN echo "builder2Bar" > /builder2Bar.txt 26 | 27 | ############################################################################################## 28 | # Primary Stage – Primary Base Image: scratch 29 | ############################################################################################## 30 | FROM scratch 31 | 32 | ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz 33 | 34 | EXPOSE 5432/tcp 35 | EXPOSE 5432/udp 36 | ENV POSTGRES_ENV_1="postgres_env_val_1" 37 | 38 | # `COPY --from=0` is the same as `COPY --from=builder1` 39 | COPY --from=0 /builder1Foo.txt /builder1Foo.txt 40 | COPY --from=0 /builder1Bar.txt /builder1Bar.txt 41 | ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz 42 | 43 | EXPOSE 5433/tcp 44 | EXPOSE 5433/udp 45 | ENV POSTGRES_ENV_2="postgres_env_val_2" 46 | 47 | COPY --from=builder2 /builder2Foo.txt /builder2Foo.txt 48 | COPY --from=builder2 /builder2Bar.txt /builder2Bar.txt 49 | ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz 50 | 51 | EXPOSE 5434/tcp 52 | EXPOSE 5434/udp 53 | ENV POSTGRES_ENV_3="postgres_env_val_3" 54 | -------------------------------------------------------------------------------- /examples/postgres-base-multistage/Dockerfile: -------------------------------------------------------------------------------- 1 | ############################################################################################## 2 | # Multistage Build Stage (Builder 1) – Multistage Base Image: node 3 | ############################################################################################## 4 | FROM docker.io/library/node:18-bullseye 5 | 6 | RUN echo "builder1Foo" > /builder1Foo.txt 7 | 8 | EXPOSE 8080/tcp 9 | EXPOSE 8080/udp 10 | ENV NODE_ENV_1="node_env_val_1" 11 | 12 | RUN echo "builder1Bar" > /builder1Bar.txt 13 | 14 | ############################################################################################## 15 | # Multistage Build Stage (Builder 2) – Multistage Base Image: python 16 | ############################################################################################## 17 | FROM docker.io/library/python:3-bullseye as builder2 18 | 19 | RUN echo "builder2Foo" > /builder2Foo.txt 20 | 21 | EXPOSE 5000/tcp 22 | EXPOSE 5000/udp 23 | ENV PYTHON_ENV_1="python_env_val_1" 24 | 25 | RUN echo "builder2Bar" > /builder2Bar.txt 26 | 27 | ############################################################################################## 28 | # Primary Stage – Primary Base Image: postgres 29 | ############################################################################################## 30 | FROM docker.io/library/postgres:14-bullseye 31 | 32 | ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz 33 | RUN echo "hello" > /hello.txt 34 | 35 | EXPOSE 5432/tcp 36 | EXPOSE 5432/udp 37 | ENV POSTGRES_ENV_1="postgres_env_val_1" 38 | 39 | # `COPY --from=0` is the same as `COPY --from=builder1` 40 | COPY --from=0 /builder1Foo.txt /builder1Foo.txt 41 | COPY --from=0 /builder1Bar.txt /builder1Bar.txt 42 | ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz 43 | RUN echo "breakfast" > /breakfast.txt 44 | 45 | EXPOSE 5433/tcp 46 | EXPOSE 5433/udp 47 | ENV POSTGRES_ENV_2="postgres_env_val_2" 48 | 49 | COPY --from=builder2 /builder2Foo.txt /builder2Foo.txt 50 | COPY --from=builder2 /builder2Bar.txt /builder2Bar.txt 51 | ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz 52 | RUN echo "goodbye" > /goodbye.txt 53 | 54 | EXPOSE 5434/tcp 55 | EXPOSE 5434/udp 56 | ENV POSTGRES_ENV_3="postgres_env_val_3" 57 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /examples/postgres-base-vanilla/oci-image-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.docker.distribution.manifest.v2+json", 4 | "config": { 5 | "mediaType": "application/vnd.docker.container.image.v1+json", 6 | "size": 9433, 7 | "digest": "sha256:7ef47ad8e58e4484824028ddb1e80da918baaf5db11fd0a041dae4d05c6c9d72" 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 12 | "size": 31404121, 13 | "digest": "sha256:31b3f1ad4ce1f369084d0f959813c51df0ca17d9877d5ee88c2db6ff88341430" 14 | }, 15 | { 16 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 17 | "size": 4414809, 18 | "digest": "sha256:dc97844d0cd5332f8a27d4e812cb78fe28eb3a24d6447b298e11f4c1381ee04b" 19 | }, 20 | { 21 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 22 | "size": 1798, 23 | "digest": "sha256:9ad9b1166fde5ac579a870942e64b1252b809a74ce2716537b2ec7d29211aa0e" 24 | }, 25 | { 26 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 27 | "size": 1418427, 28 | "digest": "sha256:286c4682b24df07908e721b97e0e931e7094b0822d4dd0623c48684960c892c0" 29 | }, 30 | { 31 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 32 | "size": 8045146, 33 | "digest": "sha256:1d3679a4a1a1adeb649c1019cdb9ba6be5f79b5035e1ec221fcf583033a34926" 34 | }, 35 | { 36 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 37 | "size": 1261090, 38 | "digest": "sha256:5f2e6cdc8503192834c8294003826329e7af061a1f47f07993501623d7ccedea" 39 | }, 40 | { 41 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 42 | "size": 149, 43 | "digest": "sha256:0f7dc70f54e874e4d3bfa632e989030d30740819b8c4612427817302aa8add51" 44 | }, 45 | { 46 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 47 | "size": 3190, 48 | "digest": "sha256:a090c7442692840048d70c9acd1c55039a7f996487443a737aaa51ce10fea1d0" 49 | }, 50 | { 51 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 52 | "size": 91324554, 53 | "digest": "sha256:81bfe40fd0f61b92c803640298635127dceffdb8bb976b18deb65cea5fa8f1d7" 54 | }, 55 | { 56 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 57 | "size": 9533, 58 | "digest": "sha256:8ac8c22bbb38c7671d1717440beedb42a16d08d7ed1a32dfe04a86cd46d7ec50" 59 | }, 60 | { 61 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 62 | "size": 129, 63 | "digest": "sha256:96e51d1d3c6ed4891a0956205a17808f0f35d419a1eb42c975f1e30602dc432f" 64 | }, 65 | { 66 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 67 | "size": 200, 68 | "digest": "sha256:667bd4154fa25c0f9c5c66e563d1dce64f050067cf6019985909335aa140d018" 69 | }, 70 | { 71 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 72 | "size": 4697, 73 | "digest": "sha256:87267fb600a9542046b27cc191951fe9abb6fd7c2946ba94c604bf6911579b5b" 74 | } 75 | ] 76 | } 77 | -------------------------------------------------------------------------------- /docs/media/readme/image-layer-provenance-document-stored-as-oras-reference-artifact.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /examples/scratch-base-singlestage/simple-image-history.txt: -------------------------------------------------------------------------------- 1 | IMAGE CREATED AT CREATED BY SIZE COMMENT 2 | sha256:1cecc87939b2aff159f1f166a7b45315b3d69ffd2642441de8e5bc0b7ba625fc 2022-09-20T10:31:11-07:00 ENV POSTGRES_ENV_3=postgres_env_val_3 0 buildkit.dockerfile.v0 3 | 2022-09-20T10:31:11-07:00 EXPOSE map[5434/udp:{}] 0 buildkit.dockerfile.v0 4 | 2022-09-20T10:31:11-07:00 EXPOSE map[5434/tcp:{}] 0 buildkit.dockerfile.v0 5 | 2022-09-20T10:31:11-07:00 ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz # buildkit 22526996 buildkit.dockerfile.v0 6 | 2022-09-20T10:31:11-07:00 ENV POSTGRES_ENV_2=postgres_env_val_2 0 buildkit.dockerfile.v0 7 | 2022-09-20T10:31:11-07:00 EXPOSE map[5433/udp:{}] 0 buildkit.dockerfile.v0 8 | 2022-09-20T10:31:11-07:00 EXPOSE map[5433/tcp:{}] 0 buildkit.dockerfile.v0 9 | 2022-09-20T10:31:11-07:00 ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz # buildkit 2746121 buildkit.dockerfile.v0 10 | 2022-09-20T10:31:11-07:00 ENV POSTGRES_ENV_1=postgres_env_val_1 0 buildkit.dockerfile.v0 11 | 2022-09-20T10:31:11-07:00 EXPOSE map[5432/udp:{}] 0 buildkit.dockerfile.v0 12 | 2022-09-20T10:31:11-07:00 EXPOSE map[5432/tcp:{}] 0 buildkit.dockerfile.v0 13 | 2022-09-20T10:30:53-07:00 ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz # buildkit 1108750 buildkit.dockerfile.v0 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Project 2 | 3 | Welcome! We are very happy to accept community contributions to the project, whether those are [Pull Requests](#pull-requests), [Suggestions](#suggestions) or [Bug Reports](#bug-reports). Please note that by participating in this project, you agree to abide by the [Code of Conduct](./CODE_OF_CONDUCT.md), as well as the terms of the [CLA](#cla). 4 | 5 | ## Getting Started 6 | 7 | * Follow the installation and demo steps to run the [Proof of Concept CLI Tool](./README.md#proof-of-concept-cli-tool). 8 | 9 | ## Developing 10 | 11 | ### Components 12 | 13 | The project is composed of the following main components: 14 | 15 | * **CLI** (`./cmd/cli`): the CLI executable. 16 | * **Go SDK** (`./image`): Go SDK to generate container image layer history and provenance documents. 17 | * **Scripts** (`./scripts`): scripts to build, generate, and push provenance documents for container images. 18 | 19 | ### Tests 20 | 21 | * We are happy to accept contributions for additional tests in the CLI ([`./cmd/cli`](./cmd/cli)), the SDK ([`./image`](./image/)), and the scripts ([`./scripts`](./scripts/)). 22 | 23 | ### Running the CLI 24 | 25 | * Once built, run the CLI from the bin directory `./bin/image-layer-dockerfile-history` for a list of the available commands. 26 | * For any command the `--help` argument can be passed for more information and a list of possible arguments. 27 | 28 | ## Pull Requests 29 | 30 | If you'd like to start contributing, you can search for GitHub Issues. 31 | 32 | ## Suggestions 33 | 34 | * Please first search GitHub Issues before opening an issue to check whether your suggestion has already been suggested. If it has, feel free to add your own comments to the existing issue. 35 | * Ensure you have included a "What?" - what your feature entails, being as specific as possible, and giving mocked-up syntax examples where possible. 36 | * Ensure you have included a "Why?" - what the benefit of including this feature will be. 37 | 38 | ## Bug Reports 39 | 40 | * Please first search GitHub Issues before opening an issue to see if it has already been reported. 41 | * Try to be as specific as possible, including the version of the CLI or SDK used to reproduce the issue, and any example arguments needed to reproduce it. 42 | 43 | ## CLA 44 | 45 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 46 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 47 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 48 | 49 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 50 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 51 | provided by the bot. You will only need to do this once across all repos using our CLA. 52 | 53 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 54 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 55 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 56 | -------------------------------------------------------------------------------- /scripts/generate-history-all-examples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -aueo pipefail 4 | 5 | if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then 6 | echo "Generates the OCI image manifest layer histories for all images referenced in the examples directory." 7 | echo "Usage: $0 " 8 | echo " e.g. $0 myregistry.registry.io myregistryusername myregistrypassword" 9 | exit 1 10 | fi 11 | 12 | registry_url="$1" 13 | namespace="$registry_url/image-manifest-layer-history" 14 | 15 | username="$2" 16 | password="$3" 17 | 18 | example_image_directory_names=( 19 | "examples/postgres-base-multistage" 20 | "examples/postgres-base-singlestage" 21 | "examples/postgres-base-vanilla" 22 | "examples/scratch-base-multistage" 23 | "examples/scratch-base-singlestage" 24 | "examples/scratch-base-vanilla" 25 | ) 26 | 27 | make build-cli 28 | 29 | responsible_entity_id="ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 30 | 31 | for example_image_directory_name in "${example_image_directory_names[@]}"; do 32 | image_ref="$namespace/$example_image_directory_name:latest" 33 | dockerfile="$example_image_directory_name/Dockerfile" 34 | 35 | # Save a copy of the simple image history (i.e. the image history returned from `docker image history`). 36 | docker image history --no-trunc --human=false "$image_ref" > "$example_image_directory_name/simple-image-history.txt" 37 | 38 | # Save a copy of the OCI image manifest (i.e. the OCI image manifest returned from `docker manifest inspect`). 39 | docker manifest inspect "$image_ref" > "$example_image_directory_name/oci-image-manifest.json" 40 | 41 | echo -e "[*] Generating OCI image manifest layer history\n\tfor image: '$image_ref'\n\tbased on Dockerfile: '$dockerfile'\n" 42 | 43 | ./bin/image-layer-dockerfile-history \ 44 | generate \ 45 | --username "$username" \ 46 | --password "$password" \ 47 | --image-ref "$image_ref" \ 48 | --dockerfile "$dockerfile" \ 49 | --output-file "$example_image_directory_name/oci-image-manifest-layer-history.json" \ 50 | --attribution-annotation "responsible_entity_id: $responsible_entity_id" 51 | 52 | ./bin/image-layer-dockerfile-history \ 53 | generate \ 54 | --username "$username" \ 55 | --password "$password" \ 56 | --image-ref "$image_ref" \ 57 | --dockerfile "$dockerfile" \ 58 | --output-file "$example_image_directory_name/oci-image-manifest-layer-history-simplified.json" \ 59 | --simplified-json=true \ 60 | --attribution-annotation "responsible_entity_id: $responsible_entity_id" 61 | 62 | ./bin/image-layer-dockerfile-history \ 63 | generate \ 64 | --username "$username" \ 65 | --password "$password" \ 66 | --image-ref "$image_ref" \ 67 | --dockerfile "$dockerfile" \ 68 | --output-file "$example_image_directory_name/oci-image-manifest-layer-history-slsa.json" \ 69 | --slsa-provenance-json=true \ 70 | --attribution-annotation "responsible_entity_id: $responsible_entity_id" 71 | done 72 | -------------------------------------------------------------------------------- /image/history/types.go: -------------------------------------------------------------------------------- 1 | package history 2 | 3 | import ( 4 | "github.com/asottile/dockerfile" 5 | "github.com/docker/docker/api/types/image" 6 | "github.com/opencontainers/go-digest" 7 | ocispec "github.com/opencontainers/image-spec/specs-go/v1" 8 | ) 9 | 10 | // ImageHistory describes the overall history of an image. 11 | // It contains: 12 | // - the image's non-detailed layer history, 13 | // - This is the non-detailed layer history from Docker Engine API's ImageHistory operation (`docker image history`). 14 | // - the image's OCI image manifest, 15 | // - the image's Dockerfile. 16 | type ImageHistory struct { 17 | // ImageLayerHistory MUST be sorted from top layers (most recent layers) to bottom layers (base image layers). 18 | ImageLayerHistory []image.HistoryResponseItem `json:"ImageLayerHistory"` 19 | // OCI image manifest. See https://github.com/opencontainers/image-spec/blob/main/manifest.md. 20 | ImageManifest ocispec.Manifest `json:"ImageManifest"` 21 | // DockerfileCommands MUST be sorted based on the original order of commands in the Dockerfile. 22 | // E.g. if the Dockerfile contains the following commands: 23 | // FROM ubuntu:22.04 24 | // RUN apt-get update 25 | // RUN apt-get install -y vim 26 | // then dockerfileCommands should be: 27 | // []dockerfile.Command{ 28 | // dockerfile.Command{Original: "FROM ubuntu:22.04", Cmd: "FROM", Value: []string{"ubuntu:22.04"}}, 29 | // dockerfile.Command{Original: "RUN apt-get update", Cmd: "RUN", Value: []string{"apt-get", "update"}}, 30 | // dockerfile.Command{Original: "RUN apt-get install -y vim", Cmd: "RUN", Value: []string{"apt-get", "install", "-y", "vim"}}, 31 | // } 32 | DockerfileCommands []dockerfile.Command `json:"DockerfileCommands"` 33 | } 34 | 35 | // LayerCreationType describes the type of layer creation. 36 | type LayerCreationType string 37 | 38 | // LayerCreationParameters describes the exact Dockerfile parameters used to create the image manifest layer. 39 | type LayerCreationParameters struct { 40 | DockerfileLayerCreationType LayerCreationType `json:"DockerfileLayerCreationType"` 41 | DockerfileCommands []dockerfile.Command `json:"DockerfileCommands"` 42 | BaseImageRef string `json:"BaseImage"` 43 | } 44 | 45 | // ImageManifestLayerDockerfileCommandsHistory describes the exact Dockerfile history of an image manifest layer. 46 | type ImageManifestLayerDockerfileCommandsHistory struct { 47 | LayerDescriptor ocispec.Descriptor `json:"LayerDescriptor"` 48 | LayerCreationParameters LayerCreationParameters `json:"LayerCreationParameters"` 49 | AttributedEntity map[string]string `json:"AttributedEntity"` 50 | } 51 | 52 | // SimplifiedImageManifestLayerDockerfileCommandsHistory describes the exact Dockerfile history 53 | // of an image manifest layer (simplified format). 54 | type SimplifiedImageManifestLayerDockerfileCommandsHistory struct { 55 | LayerDigest digest.Digest `json:"LayerDigest"` 56 | DockerfileLayerCreationType LayerCreationType `json:"DockerfileLayerCreationType"` 57 | DockerfileCommands []string `json:"DockerfileCommands"` 58 | BaseImageRef string `json:"BaseImage"` 59 | AttributedEntity map[string]string `json:"AttributedEntity"` 60 | } 61 | -------------------------------------------------------------------------------- /examples/scratch-base-singlestage/oci-image-manifest-layer-history.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "LayerDescriptor": { 4 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 5 | "digest": "sha256:7942f3be722fa3927b29ccc51521f0f0d9b0b8979fc4148d3d94f05acc0bdf44", 6 | "size": 1100327 7 | }, 8 | "LayerCreationParameters": { 9 | "DockerfileLayerCreationType": "ADD-CommandLayer", 10 | "DockerfileCommands": [ 11 | { 12 | "Cmd": "ADD", 13 | "SubCmd": "", 14 | "Json": false, 15 | "Original": "ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz", 16 | "StartLine": 6, 17 | "EndLine": 6, 18 | "Flags": [], 19 | "Value": [ 20 | "https://github.com/kubernetes/client-go/archive/master.tar.gz", 21 | "/kubernetes/client-go.tar.gz" 22 | ] 23 | } 24 | ], 25 | "BaseImage": "" 26 | }, 27 | "AttributedEntity": { 28 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 29 | } 30 | }, 31 | { 32 | "LayerDescriptor": { 33 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 34 | "digest": "sha256:5a2bf799221e80ef7d379a58541383020761546107861b322d0d30c34840c74e", 35 | "size": 2727414 36 | }, 37 | "LayerCreationParameters": { 38 | "DockerfileLayerCreationType": "ADD-CommandLayer", 39 | "DockerfileCommands": [ 40 | { 41 | "Cmd": "ADD", 42 | "SubCmd": "", 43 | "Json": false, 44 | "Original": "ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz", 45 | "StartLine": 12, 46 | "EndLine": 12, 47 | "Flags": [], 48 | "Value": [ 49 | "https://github.com/kubernetes/kubectl/archive/master.tar.gz", 50 | "/kubernetes/kubectl.tar.gz" 51 | ] 52 | } 53 | ], 54 | "BaseImage": "" 55 | }, 56 | "AttributedEntity": { 57 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 58 | } 59 | }, 60 | { 61 | "LayerDescriptor": { 62 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 63 | "digest": "sha256:bef044d3345e7eef96b2658e006eb3761a621be5c069e559e975e98c154e5d0b", 64 | "size": 22473758 65 | }, 66 | "LayerCreationParameters": { 67 | "DockerfileLayerCreationType": "ADD-CommandLayer", 68 | "DockerfileCommands": [ 69 | { 70 | "Cmd": "ADD", 71 | "SubCmd": "", 72 | "Json": false, 73 | "Original": "ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz", 74 | "StartLine": 18, 75 | "EndLine": 18, 76 | "Flags": [], 77 | "Value": [ 78 | "https://github.com/kubernetes/dashboard/archive/master.tar.gz", 79 | "/kubernetes/dashboard.tar.gz" 80 | ] 81 | } 82 | ], 83 | "BaseImage": "" 84 | }, 85 | "AttributedEntity": { 86 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 87 | } 88 | } 89 | ] 90 | -------------------------------------------------------------------------------- /docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /examples/scratch-base-multistage/simple-image-history.txt: -------------------------------------------------------------------------------- 1 | IMAGE CREATED AT CREATED BY SIZE COMMENT 2 | sha256:90d8f10882cad534393695f5ebf45ddd3873f2562121c0775ab0764572da1bb0 2022-09-20T10:30:54-07:00 ENV POSTGRES_ENV_3=postgres_env_val_3 0 buildkit.dockerfile.v0 3 | 2022-09-20T10:30:54-07:00 EXPOSE map[5434/udp:{}] 0 buildkit.dockerfile.v0 4 | 2022-09-20T10:30:54-07:00 EXPOSE map[5434/tcp:{}] 0 buildkit.dockerfile.v0 5 | 2022-09-20T10:30:54-07:00 ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz # buildkit 22526996 buildkit.dockerfile.v0 6 | 2022-09-20T10:30:53-07:00 COPY /builder2Bar.txt /builder2Bar.txt # buildkit 12 buildkit.dockerfile.v0 7 | 2022-09-20T10:30:53-07:00 COPY /builder2Foo.txt /builder2Foo.txt # buildkit 12 buildkit.dockerfile.v0 8 | 2022-09-20T10:30:53-07:00 ENV POSTGRES_ENV_2=postgres_env_val_2 0 buildkit.dockerfile.v0 9 | 2022-09-20T10:30:53-07:00 EXPOSE map[5433/udp:{}] 0 buildkit.dockerfile.v0 10 | 2022-09-20T10:30:53-07:00 EXPOSE map[5433/tcp:{}] 0 buildkit.dockerfile.v0 11 | 2022-09-20T10:30:53-07:00 ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz # buildkit 2746121 buildkit.dockerfile.v0 12 | 2022-09-20T10:30:53-07:00 COPY /builder1Bar.txt /builder1Bar.txt # buildkit 12 buildkit.dockerfile.v0 13 | 2022-09-20T10:30:53-07:00 COPY /builder1Foo.txt /builder1Foo.txt # buildkit 12 buildkit.dockerfile.v0 14 | 2022-09-20T10:30:53-07:00 ENV POSTGRES_ENV_1=postgres_env_val_1 0 buildkit.dockerfile.v0 15 | 2022-09-20T10:30:53-07:00 EXPOSE map[5432/udp:{}] 0 buildkit.dockerfile.v0 16 | 2022-09-20T10:30:53-07:00 EXPOSE map[5432/tcp:{}] 0 buildkit.dockerfile.v0 17 | 2022-09-20T10:30:53-07:00 ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz # buildkit 1108750 buildkit.dockerfile.v0 18 | -------------------------------------------------------------------------------- /docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-myapp.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /examples/postgres-base-singlestage/oci-image-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.docker.distribution.manifest.v2+json", 4 | "config": { 5 | "mediaType": "application/vnd.docker.container.image.v1+json", 6 | "size": 12411, 7 | "digest": "sha256:c2730d8a55fb30de216dbf912a8910fd36798ce7587f483140ea64e99ab81b81" 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 12 | "size": 31404121, 13 | "digest": "sha256:31b3f1ad4ce1f369084d0f959813c51df0ca17d9877d5ee88c2db6ff88341430" 14 | }, 15 | { 16 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 17 | "size": 4414809, 18 | "digest": "sha256:dc97844d0cd5332f8a27d4e812cb78fe28eb3a24d6447b298e11f4c1381ee04b" 19 | }, 20 | { 21 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 22 | "size": 1798, 23 | "digest": "sha256:9ad9b1166fde5ac579a870942e64b1252b809a74ce2716537b2ec7d29211aa0e" 24 | }, 25 | { 26 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 27 | "size": 1418427, 28 | "digest": "sha256:286c4682b24df07908e721b97e0e931e7094b0822d4dd0623c48684960c892c0" 29 | }, 30 | { 31 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 32 | "size": 8045146, 33 | "digest": "sha256:1d3679a4a1a1adeb649c1019cdb9ba6be5f79b5035e1ec221fcf583033a34926" 34 | }, 35 | { 36 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 37 | "size": 1261090, 38 | "digest": "sha256:5f2e6cdc8503192834c8294003826329e7af061a1f47f07993501623d7ccedea" 39 | }, 40 | { 41 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 42 | "size": 149, 43 | "digest": "sha256:0f7dc70f54e874e4d3bfa632e989030d30740819b8c4612427817302aa8add51" 44 | }, 45 | { 46 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 47 | "size": 3190, 48 | "digest": "sha256:a090c7442692840048d70c9acd1c55039a7f996487443a737aaa51ce10fea1d0" 49 | }, 50 | { 51 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 52 | "size": 91324554, 53 | "digest": "sha256:81bfe40fd0f61b92c803640298635127dceffdb8bb976b18deb65cea5fa8f1d7" 54 | }, 55 | { 56 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 57 | "size": 9533, 58 | "digest": "sha256:8ac8c22bbb38c7671d1717440beedb42a16d08d7ed1a32dfe04a86cd46d7ec50" 59 | }, 60 | { 61 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 62 | "size": 129, 63 | "digest": "sha256:96e51d1d3c6ed4891a0956205a17808f0f35d419a1eb42c975f1e30602dc432f" 64 | }, 65 | { 66 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 67 | "size": 200, 68 | "digest": "sha256:667bd4154fa25c0f9c5c66e563d1dce64f050067cf6019985909335aa140d018" 69 | }, 70 | { 71 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 72 | "size": 4697, 73 | "digest": "sha256:87267fb600a9542046b27cc191951fe9abb6fd7c2946ba94c604bf6911579b5b" 74 | }, 75 | { 76 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 77 | "size": 1100364, 78 | "digest": "sha256:245e2967cc420fc67f6748f57b4c84f77e13438eb919963b6ec5cf617ca1935d" 79 | }, 80 | { 81 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 82 | "size": 135, 83 | "digest": "sha256:c676364f47f073e7ee3437e55416792524490544f53a3e60e4ae9e20f1319bed" 84 | }, 85 | { 86 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 87 | "size": 2727414, 88 | "digest": "sha256:5f112f02ac03c1c74fc56d4111f227c5240566d539b53cc3069d982956fdbb1e" 89 | }, 90 | { 91 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 92 | "size": 141, 93 | "digest": "sha256:e2bfa24d56ea5c13d905caf07d21811b5be1fd6dfa639daea34099b9b4d5a832" 94 | }, 95 | { 96 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 97 | "size": 22473758, 98 | "digest": "sha256:ea65f518ba4f1fe833c8b5a682d33b21777f73d19a35526c4af85b98aba05da6" 99 | }, 100 | { 101 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 102 | "size": 137, 103 | "digest": "sha256:466768514f44339060217fe50ec6db3477be27506b2735657db4832ea25f3891" 104 | } 105 | ] 106 | } 107 | -------------------------------------------------------------------------------- /docs/media/readme/layer-history-foo-bar-ubuntu-imported-image-with-provenance.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-with-provenance.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /docs/media/readme/layer-history-foo-bar-ubuntu-imported-image-vuln-in-ubuntu.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-aspnet.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /docs/media/readme/layer-history-myapp-aspnet-mariner-scratch-image-vuln-in-mariner.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /docs/current-limitations.md: -------------------------------------------------------------------------------- 1 | # Current Limitations in Container Image Vulnerability Experience 2 | 3 | ## Limitations of the Container Image History Format 4 | 5 | When `docker image history` is run, a simple image history is produced. 6 | The output shows how each non-empty layer (each layer's filesystem change) was created. 7 | 8 | ```tsv 9 | IMAGE CREATED CREATED BY SIZE COMMENT 10 | 1a06cd9c6d9d 12 minutes ago RUN /bin/sh -c echo file2 > /file2.txt # bui… 6B buildkit.dockerfile.v0 11 | 12 minutes ago RUN /bin/sh -c echo file1 > /file1.txt # bui… 6B buildkit.dockerfile.v0 12 | 7 days ago /bin/sh -c #(nop) COPY dir:540bddbe02c37f419… 20.3MB 13 | 7 days ago /bin/sh -c #(nop) ENV ASPNET_VERSION=6.0.8 0B 14 | 7 days ago /bin/sh -c ln -s /usr/share/dotnet/dotnet /u… 24B 15 | 7 days ago /bin/sh -c #(nop) COPY dir:a07d28c7e9124f9c9… 70.6MB 16 | 7 days ago /bin/sh -c #(nop) ENV DOTNET_VERSION=6.0.8 0B 17 | 7 days ago /bin/sh -c #(nop) ENV ASPNETCORE_URLS=http:… 0B 18 | 7 days ago /bin/sh -c apt-get update && apt-get ins… 37MB 19 | 2 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B 20 | 2 weeks ago /bin/sh -c #(nop) ADD file:0eae0dca665c7044b… 80.4MB 21 | ``` 22 | 23 | The simple history from `docker image history` has the following problems: 24 | 25 | * There is no information that indicates (1) which layers came from base images referenced in `FROM` statements or (2) which layers came from Dockerfile instructions built on top of base image layers. 26 | * No information that maps from a layer digest to a base image ref (registry url, repo, tag, digest). 27 | * In certain cases, the Dockerfile instruction that created a layer is mangled, as seen in the `ADD file:` and `COPY dir:` history entries above. 28 | 29 | When a vulnerable package is detected, scanners report the following: 30 | 31 | * the layer hash in which a vulnerable package was introduced to the filesystem, 32 | * the Dockerfile instruction that created the layer, which in some cases (as seen above) is mangled/obfuscated or contains hashed values. 33 | 34 | Reporting only (1) a layer hash and (2) a mangled Dockerfile instruction is not actionable. 35 | With only these 2 pieces of limited information, maintainers cannot differentiate vulnerability alerts between: 36 | 37 | * Actionable for vulnerabilities the user can actually fix in their layers, such as vulnerabilities introduced through Dockerfile `ADD, RUN, or COPY` instructions. 38 | * Vulnerabilities in dependent base image layers requiring further action, such as (1) patching the base image, and (2) rebuilding to pull the patched dependencies. 39 | 40 | ## Limitations of Vulnerability Scan Reports 41 | 42 | Vulnerability scanners typically output a long list of vulnerabilities when an image is scanned. 43 | Scanners typically make use of `docker image history` output when generating vulnerability provenance. 44 | 45 | A vulnerability report becomes unactionable if it cannot differentiate vulnerabilities between (1) newly-introduced layers or (2) vulnerabilities from base image layers. 46 | It also becomes unactionable if it does not pinpoint the exact source of the vulnerability, requiring manual investigation to do so. 47 | 48 | Here is a sample vulnerability report that is unactionable due to information gaps in `docker image history` output: 49 | 50 | * The layer command is obfuscated (`ADD file:`), preventing image builders from identifying the exact layer and Dockerfile instruction which introduced the vulnerable package. 51 | * There is also no indication whether the layer comes from a base image. 52 | It also does not contain the layer's originating base image ref. 53 | 54 | ``` 55 | Vulnerability Name: Ubuntu Security Notification for Sqlite3 Vulnerabilities (USN-2698-1) 56 | 57 | Vulnerable Package Information: 58 | { 59 | "VulnerablePackages": [ 60 | { 61 | "name": "libsqlite3-0", 62 | "installedVersion": "3.8.2-1ubuntu2", 63 | "requiredVersion": "3.8.2-1ubuntu2.1" 64 | } 65 | ] 66 | } 67 | 68 | Layer information where the vulnerable package was introduced: 69 | 70 | { 71 | "packageMapping": [ 72 | { 73 | "packageName": "libsqlite3-0", 74 | "packageVersion": "3.8.2-1ubuntu2", 75 | "layers": [ 76 | { 77 | "layerId": 1, 78 | "layerHash": "fef0f9958347a4b3c846fb8ea394fbcc554ec5440c7ec72b09786230d55ccc03", 79 | "layerCommand": "ADD file:0a5fd3a659be172e86491f2b94fe4fcc48be603847554a6a8d3bbc87854affec in /" 80 | } 81 | ] 82 | } 83 | ] 84 | } 85 | ``` 86 | -------------------------------------------------------------------------------- /examples/postgres-base-multistage/oci-image-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.docker.distribution.manifest.v2+json", 4 | "config": { 5 | "mediaType": "application/vnd.docker.container.image.v1+json", 6 | "size": 13281, 7 | "digest": "sha256:a6ccf6725d45ad4c41d5cccf3561754980b266071ea2f217fc3b7c0a32bc1792" 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 12 | "size": 31404121, 13 | "digest": "sha256:31b3f1ad4ce1f369084d0f959813c51df0ca17d9877d5ee88c2db6ff88341430" 14 | }, 15 | { 16 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 17 | "size": 4414809, 18 | "digest": "sha256:dc97844d0cd5332f8a27d4e812cb78fe28eb3a24d6447b298e11f4c1381ee04b" 19 | }, 20 | { 21 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 22 | "size": 1798, 23 | "digest": "sha256:9ad9b1166fde5ac579a870942e64b1252b809a74ce2716537b2ec7d29211aa0e" 24 | }, 25 | { 26 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 27 | "size": 1418427, 28 | "digest": "sha256:286c4682b24df07908e721b97e0e931e7094b0822d4dd0623c48684960c892c0" 29 | }, 30 | { 31 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 32 | "size": 8045146, 33 | "digest": "sha256:1d3679a4a1a1adeb649c1019cdb9ba6be5f79b5035e1ec221fcf583033a34926" 34 | }, 35 | { 36 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 37 | "size": 1261090, 38 | "digest": "sha256:5f2e6cdc8503192834c8294003826329e7af061a1f47f07993501623d7ccedea" 39 | }, 40 | { 41 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 42 | "size": 149, 43 | "digest": "sha256:0f7dc70f54e874e4d3bfa632e989030d30740819b8c4612427817302aa8add51" 44 | }, 45 | { 46 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 47 | "size": 3190, 48 | "digest": "sha256:a090c7442692840048d70c9acd1c55039a7f996487443a737aaa51ce10fea1d0" 49 | }, 50 | { 51 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 52 | "size": 91324554, 53 | "digest": "sha256:81bfe40fd0f61b92c803640298635127dceffdb8bb976b18deb65cea5fa8f1d7" 54 | }, 55 | { 56 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 57 | "size": 9533, 58 | "digest": "sha256:8ac8c22bbb38c7671d1717440beedb42a16d08d7ed1a32dfe04a86cd46d7ec50" 59 | }, 60 | { 61 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 62 | "size": 129, 63 | "digest": "sha256:96e51d1d3c6ed4891a0956205a17808f0f35d419a1eb42c975f1e30602dc432f" 64 | }, 65 | { 66 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 67 | "size": 200, 68 | "digest": "sha256:667bd4154fa25c0f9c5c66e563d1dce64f050067cf6019985909335aa140d018" 69 | }, 70 | { 71 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 72 | "size": 4697, 73 | "digest": "sha256:87267fb600a9542046b27cc191951fe9abb6fd7c2946ba94c604bf6911579b5b" 74 | }, 75 | { 76 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 77 | "size": 1100364, 78 | "digest": "sha256:245e2967cc420fc67f6748f57b4c84f77e13438eb919963b6ec5cf617ca1935d" 79 | }, 80 | { 81 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 82 | "size": 135, 83 | "digest": "sha256:c676364f47f073e7ee3437e55416792524490544f53a3e60e4ae9e20f1319bed" 84 | }, 85 | { 86 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 87 | "size": 115, 88 | "digest": "sha256:f0007634565752c57366439569258a233a2e5a8c209dd29d9df9d7daaf161c2e" 89 | }, 90 | { 91 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 92 | "size": 115, 93 | "digest": "sha256:718e9aa42f6902fdde956e8435f0f34857708fce6ef461a197ea2f22bf19e3f0" 94 | }, 95 | { 96 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 97 | "size": 2727414, 98 | "digest": "sha256:115069ef94395c54e8d20e56883b80d1d7970290e8e0f0b662c3fa251c547d4c" 99 | }, 100 | { 101 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 102 | "size": 141, 103 | "digest": "sha256:837bf7e7c4448b0e1cceb1a606bdb069a0e45f71d2b37b2a22266c8433a917dd" 104 | }, 105 | { 106 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 107 | "size": 115, 108 | "digest": "sha256:50b974a802e3f9089177263e1024a0f253949993d95bdfba97d923fc0b111a22" 109 | }, 110 | { 111 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 112 | "size": 115, 113 | "digest": "sha256:1fa6c8ba07a43357be8a6b0ab93fe7240256c6944d8dc7ff6d56460a902345e5" 114 | }, 115 | { 116 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 117 | "size": 22473758, 118 | "digest": "sha256:c9fa26122280d003b9c895361c2e2902919c448b4530d264d0cc29a0db360d2f" 119 | }, 120 | { 121 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 122 | "size": 137, 123 | "digest": "sha256:2f49cbff975702d5943ddd3782cd5ff2afc56566620d39755477073977a48a98" 124 | } 125 | ] 126 | } 127 | -------------------------------------------------------------------------------- /examples/scratch-base-multistage/oci-image-manifest-layer-history-simplified.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "LayerDigest": "sha256:7942f3be722fa3927b29ccc51521f0f0d9b0b8979fc4148d3d94f05acc0bdf44", 4 | "DockerfileLayerCreationType": "ADD-CommandLayer", 5 | "DockerfileCommands": [ 6 | "ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz" 7 | ], 8 | "BaseImage": "", 9 | "AttributedEntity": { 10 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 11 | } 12 | }, 13 | { 14 | "LayerDigest": "sha256:f0007634565752c57366439569258a233a2e5a8c209dd29d9df9d7daaf161c2e", 15 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 16 | "DockerfileCommands": [ 17 | "FROM docker.io/library/node:18-bullseye", 18 | "RUN echo \"builder1Foo\" \u003e /builder1Foo.txt", 19 | "EXPOSE 8080/tcp", 20 | "EXPOSE 8080/udp", 21 | "ENV NODE_ENV_1=\"node_env_val_1\"", 22 | "RUN echo \"builder1Bar\" \u003e /builder1Bar.txt", 23 | "COPY --from=0 /builder1Foo.txt /builder1Foo.txt" 24 | ], 25 | "BaseImage": "docker.io/library/node:18-bullseye", 26 | "AttributedEntity": { 27 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 28 | } 29 | }, 30 | { 31 | "LayerDigest": "sha256:718e9aa42f6902fdde956e8435f0f34857708fce6ef461a197ea2f22bf19e3f0", 32 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 33 | "DockerfileCommands": [ 34 | "FROM docker.io/library/node:18-bullseye", 35 | "RUN echo \"builder1Foo\" \u003e /builder1Foo.txt", 36 | "EXPOSE 8080/tcp", 37 | "EXPOSE 8080/udp", 38 | "ENV NODE_ENV_1=\"node_env_val_1\"", 39 | "RUN echo \"builder1Bar\" \u003e /builder1Bar.txt", 40 | "COPY --from=0 /builder1Bar.txt /builder1Bar.txt" 41 | ], 42 | "BaseImage": "docker.io/library/node:18-bullseye", 43 | "AttributedEntity": { 44 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 45 | } 46 | }, 47 | { 48 | "LayerDigest": "sha256:127c4f8180baccafd36c1ead43d6fd1cc5859f650f5d6867809e39b5d76d11ae", 49 | "DockerfileLayerCreationType": "ADD-CommandLayer", 50 | "DockerfileCommands": [ 51 | "ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz" 52 | ], 53 | "BaseImage": "", 54 | "AttributedEntity": { 55 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 56 | } 57 | }, 58 | { 59 | "LayerDigest": "sha256:50b974a802e3f9089177263e1024a0f253949993d95bdfba97d923fc0b111a22", 60 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 61 | "DockerfileCommands": [ 62 | "FROM docker.io/library/python:3-bullseye as builder2", 63 | "RUN echo \"builder2Foo\" \u003e /builder2Foo.txt", 64 | "EXPOSE 5000/tcp", 65 | "EXPOSE 5000/udp", 66 | "ENV PYTHON_ENV_1=\"python_env_val_1\"", 67 | "RUN echo \"builder2Bar\" \u003e /builder2Bar.txt", 68 | "COPY --from=builder2 /builder2Foo.txt /builder2Foo.txt" 69 | ], 70 | "BaseImage": "docker.io/library/python:3-bullseye", 71 | "AttributedEntity": { 72 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 73 | } 74 | }, 75 | { 76 | "LayerDigest": "sha256:1fa6c8ba07a43357be8a6b0ab93fe7240256c6944d8dc7ff6d56460a902345e5", 77 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 78 | "DockerfileCommands": [ 79 | "FROM docker.io/library/python:3-bullseye as builder2", 80 | "RUN echo \"builder2Foo\" \u003e /builder2Foo.txt", 81 | "EXPOSE 5000/tcp", 82 | "EXPOSE 5000/udp", 83 | "ENV PYTHON_ENV_1=\"python_env_val_1\"", 84 | "RUN echo \"builder2Bar\" \u003e /builder2Bar.txt", 85 | "COPY --from=builder2 /builder2Bar.txt /builder2Bar.txt" 86 | ], 87 | "BaseImage": "docker.io/library/python:3-bullseye", 88 | "AttributedEntity": { 89 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 90 | } 91 | }, 92 | { 93 | "LayerDigest": "sha256:336f60ca2fdf8014edca08c0461e7491080d74554a3830e7d9167f0c2ccfb1f4", 94 | "DockerfileLayerCreationType": "ADD-CommandLayer", 95 | "DockerfileCommands": [ 96 | "ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz" 97 | ], 98 | "BaseImage": "", 99 | "AttributedEntity": { 100 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 101 | } 102 | } 103 | ] 104 | -------------------------------------------------------------------------------- /image/client/client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "encoding/base64" 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | 10 | "github.com/docker/docker/api/types" 11 | "github.com/docker/docker/api/types/filters" 12 | "github.com/docker/docker/api/types/image" 13 | "github.com/docker/docker/client" 14 | "github.com/opencontainers/go-digest" 15 | ocispec "github.com/opencontainers/image-spec/specs-go/v1" 16 | "oras.land/oras-go/v2/content" 17 | "oras.land/oras-go/v2/registry" 18 | "oras.land/oras-go/v2/registry/remote" 19 | "oras.land/oras-go/v2/registry/remote/auth" 20 | ) 21 | 22 | type ImageClient struct { 23 | Username string 24 | Password string 25 | DockerEngineClient *client.Client 26 | ImageRef registry.Reference 27 | OrasRepoClient *remote.Repository 28 | } 29 | 30 | // NewImageClient returns a new ImageClient. 31 | func NewImageClient(username, password, imageRefStr string) (ImageClient, error) { 32 | imageClient := ImageClient{ 33 | Username: username, 34 | Password: password, 35 | } 36 | 37 | // Create a client to the Docker Engine (Docker daemon) referenced by local environment variables. 38 | dockerEngineClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) 39 | if err != nil { 40 | return imageClient, err 41 | } 42 | imageClient.DockerEngineClient = dockerEngineClient 43 | 44 | // Parse the image reference string to an ORAS artifact reference type. 45 | imageRef, err := registry.ParseReference(imageRefStr) 46 | if err != nil { 47 | return imageClient, err 48 | } 49 | imageClient.ImageRef = imageRef 50 | 51 | // Create an ORAS client to the image reference's repository. 52 | orasRepoClient, err := remote.NewRepository(imageClient.ImageRef.String()) 53 | if err != nil { 54 | return imageClient, err 55 | } 56 | orasRepoClient.Client = &auth.Client{ 57 | Credential: func(ctx context.Context, reg string) (auth.Credential, error) { 58 | return auth.Credential{ 59 | Username: imageClient.Username, 60 | Password: imageClient.Password, 61 | }, nil 62 | }, 63 | } 64 | imageClient.OrasRepoClient = orasRepoClient 65 | 66 | return imageClient, nil 67 | } 68 | 69 | // EnsureImageIsPulled ensures that the image is pulled 70 | // and present in the Docker Engine (Docker daemon). 71 | func (imageClient *ImageClient) EnsureImageIsPulled(ctx context.Context) error { 72 | // Create an encoded auth config for authenticating with the image reference's registry. 73 | // See https://docs.docker.com/engine/api/sdk/examples/#pull-an-image-with-authentication. 74 | authConfig := types.AuthConfig{ 75 | Username: imageClient.Username, 76 | Password: imageClient.Password, 77 | } 78 | encodedJSON, err := json.Marshal(authConfig) 79 | if err != nil { 80 | return err 81 | } 82 | authStr := base64.URLEncoding.EncodeToString(encodedJSON) 83 | 84 | out, err := imageClient.DockerEngineClient.ImagePull( 85 | ctx, 86 | imageClient.ImageRef.String(), 87 | types.ImagePullOptions{RegistryAuth: authStr}, 88 | ) 89 | if err != nil { 90 | return err 91 | } 92 | defer out.Close() 93 | 94 | // Fully read and consume to ensure the image is pulled 95 | // to the Docker Engine (Docker daemon). 96 | _, err = ioutil.ReadAll(out) 97 | if err != nil { 98 | // If reading the output reader fails, 99 | // then most likely pulling the image failed. 100 | return err 101 | } 102 | 103 | return nil 104 | } 105 | 106 | // GetImageHistory returns the image layer history. 107 | // The image layer history is sorted 108 | // from top layers (most recent layers) to bottom layers (base image layers). 109 | // See https://docs.docker.com/engine/reference/commandline/image_history/. 110 | func (imageClient *ImageClient) GetImageLayerHistory(ctx context.Context) ([]image.HistoryResponseItem, error) { 111 | // The image must be present in the Docker Engine (Docker daemon) 112 | // before its history can be obtained. 113 | err := imageClient.EnsureImageIsPulled(ctx) 114 | if err != nil { 115 | return nil, err 116 | } 117 | 118 | // The image history can only be obtained once the image has been pulled 119 | // and is present in the Docker Engine (Docker daemon). 120 | images, err := imageClient.DockerEngineClient.ImageList(ctx, types.ImageListOptions{ 121 | All: true, 122 | Filters: filters.NewArgs( 123 | filters.Arg("reference", imageClient.ImageRef.String()), 124 | ), 125 | }) 126 | if err != nil { 127 | return nil, err 128 | } 129 | if len(images) == 0 { 130 | return nil, fmt.Errorf("no image found for reference: %s", imageClient.ImageRef.String()) 131 | } 132 | if len(images) > 1 { 133 | return nil, fmt.Errorf("multiple images found for reference: %s", imageClient.ImageRef.String()) 134 | } 135 | 136 | imageID := images[0].ID 137 | imageLayerHistory, err := imageClient.DockerEngineClient.ImageHistory(ctx, imageID) 138 | if err != nil { 139 | return nil, err 140 | } 141 | 142 | return imageLayerHistory, nil 143 | } 144 | 145 | // GetImageManifest returns the OCI image manifest. 146 | // See https://github.com/opencontainers/image-spec/blob/main/manifest.md. 147 | func (imageClient *ImageClient) GetImageManifest(ctx context.Context) (ocispec.Manifest, error) { 148 | manifest := ocispec.Manifest{} 149 | 150 | descriptor, rc, err := imageClient.OrasRepoClient.FetchReference(ctx, imageClient.ImageRef.String()) 151 | if err != nil { 152 | return manifest, err 153 | } 154 | defer rc.Close() 155 | 156 | pulledBytes, err := content.FetchAll(ctx, imageClient.OrasRepoClient, descriptor) 157 | if err != nil { 158 | return manifest, err 159 | } 160 | if descriptor.Size != int64(len(pulledBytes)) || descriptor.Digest != digest.FromBytes(pulledBytes) { 161 | return manifest, fmt.Errorf("pulled bytes do not match descriptor") 162 | } 163 | 164 | err = json.Unmarshal(pulledBytes, &manifest) 165 | if err != nil { 166 | return manifest, err 167 | } 168 | 169 | return manifest, nil 170 | } 171 | -------------------------------------------------------------------------------- /examples/postgres-base-vanilla/oci-image-manifest-layer-history-simplified.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "LayerDigest": "sha256:31b3f1ad4ce1f369084d0f959813c51df0ca17d9877d5ee88c2db6ff88341430", 4 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 5 | "DockerfileCommands": [ 6 | "FROM docker.io/library/postgres:14-bullseye" 7 | ], 8 | "BaseImage": "docker.io/library/postgres:14-bullseye", 9 | "AttributedEntity": { 10 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 11 | } 12 | }, 13 | { 14 | "LayerDigest": "sha256:dc97844d0cd5332f8a27d4e812cb78fe28eb3a24d6447b298e11f4c1381ee04b", 15 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 16 | "DockerfileCommands": [ 17 | "FROM docker.io/library/postgres:14-bullseye" 18 | ], 19 | "BaseImage": "docker.io/library/postgres:14-bullseye", 20 | "AttributedEntity": { 21 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 22 | } 23 | }, 24 | { 25 | "LayerDigest": "sha256:9ad9b1166fde5ac579a870942e64b1252b809a74ce2716537b2ec7d29211aa0e", 26 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 27 | "DockerfileCommands": [ 28 | "FROM docker.io/library/postgres:14-bullseye" 29 | ], 30 | "BaseImage": "docker.io/library/postgres:14-bullseye", 31 | "AttributedEntity": { 32 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 33 | } 34 | }, 35 | { 36 | "LayerDigest": "sha256:286c4682b24df07908e721b97e0e931e7094b0822d4dd0623c48684960c892c0", 37 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 38 | "DockerfileCommands": [ 39 | "FROM docker.io/library/postgres:14-bullseye" 40 | ], 41 | "BaseImage": "docker.io/library/postgres:14-bullseye", 42 | "AttributedEntity": { 43 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 44 | } 45 | }, 46 | { 47 | "LayerDigest": "sha256:1d3679a4a1a1adeb649c1019cdb9ba6be5f79b5035e1ec221fcf583033a34926", 48 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 49 | "DockerfileCommands": [ 50 | "FROM docker.io/library/postgres:14-bullseye" 51 | ], 52 | "BaseImage": "docker.io/library/postgres:14-bullseye", 53 | "AttributedEntity": { 54 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 55 | } 56 | }, 57 | { 58 | "LayerDigest": "sha256:5f2e6cdc8503192834c8294003826329e7af061a1f47f07993501623d7ccedea", 59 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 60 | "DockerfileCommands": [ 61 | "FROM docker.io/library/postgres:14-bullseye" 62 | ], 63 | "BaseImage": "docker.io/library/postgres:14-bullseye", 64 | "AttributedEntity": { 65 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 66 | } 67 | }, 68 | { 69 | "LayerDigest": "sha256:0f7dc70f54e874e4d3bfa632e989030d30740819b8c4612427817302aa8add51", 70 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 71 | "DockerfileCommands": [ 72 | "FROM docker.io/library/postgres:14-bullseye" 73 | ], 74 | "BaseImage": "docker.io/library/postgres:14-bullseye", 75 | "AttributedEntity": { 76 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 77 | } 78 | }, 79 | { 80 | "LayerDigest": "sha256:a090c7442692840048d70c9acd1c55039a7f996487443a737aaa51ce10fea1d0", 81 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 82 | "DockerfileCommands": [ 83 | "FROM docker.io/library/postgres:14-bullseye" 84 | ], 85 | "BaseImage": "docker.io/library/postgres:14-bullseye", 86 | "AttributedEntity": { 87 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 88 | } 89 | }, 90 | { 91 | "LayerDigest": "sha256:81bfe40fd0f61b92c803640298635127dceffdb8bb976b18deb65cea5fa8f1d7", 92 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 93 | "DockerfileCommands": [ 94 | "FROM docker.io/library/postgres:14-bullseye" 95 | ], 96 | "BaseImage": "docker.io/library/postgres:14-bullseye", 97 | "AttributedEntity": { 98 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 99 | } 100 | }, 101 | { 102 | "LayerDigest": "sha256:8ac8c22bbb38c7671d1717440beedb42a16d08d7ed1a32dfe04a86cd46d7ec50", 103 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 104 | "DockerfileCommands": [ 105 | "FROM docker.io/library/postgres:14-bullseye" 106 | ], 107 | "BaseImage": "docker.io/library/postgres:14-bullseye", 108 | "AttributedEntity": { 109 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 110 | } 111 | }, 112 | { 113 | "LayerDigest": "sha256:96e51d1d3c6ed4891a0956205a17808f0f35d419a1eb42c975f1e30602dc432f", 114 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 115 | "DockerfileCommands": [ 116 | "FROM docker.io/library/postgres:14-bullseye" 117 | ], 118 | "BaseImage": "docker.io/library/postgres:14-bullseye", 119 | "AttributedEntity": { 120 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 121 | } 122 | }, 123 | { 124 | "LayerDigest": "sha256:667bd4154fa25c0f9c5c66e563d1dce64f050067cf6019985909335aa140d018", 125 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 126 | "DockerfileCommands": [ 127 | "FROM docker.io/library/postgres:14-bullseye" 128 | ], 129 | "BaseImage": "docker.io/library/postgres:14-bullseye", 130 | "AttributedEntity": { 131 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 132 | } 133 | }, 134 | { 135 | "LayerDigest": "sha256:87267fb600a9542046b27cc191951fe9abb6fd7c2946ba94c604bf6911579b5b", 136 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 137 | "DockerfileCommands": [ 138 | "FROM docker.io/library/postgres:14-bullseye" 139 | ], 140 | "BaseImage": "docker.io/library/postgres:14-bullseye", 141 | "AttributedEntity": { 142 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 143 | } 144 | } 145 | ] 146 | -------------------------------------------------------------------------------- /cmd/cli/generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "os" 9 | "regexp" 10 | "time" 11 | 12 | "github.com/asottile/dockerfile" 13 | intoto "github.com/in-toto/in-toto-golang/in_toto" 14 | "github.com/spf13/cobra" 15 | 16 | "github.com/johnsonshi/image-manifest-layer-history/image/client" 17 | "github.com/johnsonshi/image-manifest-layer-history/image/history" 18 | "github.com/johnsonshi/image-manifest-layer-history/image/slsa" 19 | ) 20 | 21 | type generateCmdOpts struct { 22 | stdin io.Reader 23 | stdout io.Writer 24 | stderr io.Writer 25 | username string 26 | password string 27 | imageRef string 28 | dockerfilePath string 29 | outputFilePath string 30 | simplifiedJsonOutput bool 31 | slsaProvenanceJsonOutput bool 32 | attributionAnnotations []string 33 | } 34 | 35 | func newGenerateCmd(stdin io.Reader, stdout io.Writer, stderr io.Writer, args []string) *cobra.Command { 36 | opts := &generateCmdOpts{ 37 | stdin: stdin, 38 | stdout: stdout, 39 | stderr: stderr, 40 | } 41 | 42 | cobraCmd := &cobra.Command{ 43 | Use: "generate", 44 | Short: "Generate the history (including the exact Dockerfile commands) for each OCI Image Manifest Layer of a container image.", 45 | Example: `generate -u username -p password -i imageRef -d dockerfilePath -o outputFilePath [-s] [-a "key: value"]`, 46 | RunE: func(_ *cobra.Command, args []string) error { 47 | return opts.run() 48 | }, 49 | } 50 | 51 | f := cobraCmd.Flags() 52 | 53 | f.StringVarP(&opts.username, "username", "u", "", "username to use for authentication with the registry") 54 | cobraCmd.MarkFlagRequired("username") 55 | 56 | // TODO add support for --password-stdin (reading password from stdin) for more secure password input. 57 | f.StringVarP(&opts.password, "password", "p", "", "password to use for authentication with the registry") 58 | cobraCmd.MarkFlagRequired("password") 59 | 60 | cobraCmd.MarkFlagsRequiredTogether("username", "password") 61 | 62 | f.StringVarP(&opts.imageRef, "image-ref", "i", "", "full image reference including registry, repository, and tag/digest, e.g. myregistry.azurecr.io/library/ubuntu:22.04 or myregistry.azurecr.io/library/ubuntu@sha256:123456") 63 | cobraCmd.MarkFlagRequired("image-ref") 64 | 65 | f.StringVarP(&opts.dockerfilePath, "dockerfile", "d", "", "path to the Dockerfile") 66 | cobraCmd.MarkFlagRequired("dockerfile") 67 | 68 | f.StringVarP(&opts.outputFilePath, "output-file", "o", "", "optional path to an output file") 69 | 70 | f.BoolVar(&opts.simplifiedJsonOutput, "simplified-json", false, "optional flag to output in simplified JSON format") 71 | 72 | f.BoolVar(&opts.slsaProvenanceJsonOutput, "slsa-provenance-json", false, "optional flag to output in SLSA Provenance JSON format") 73 | 74 | cobraCmd.MarkFlagsMutuallyExclusive("simplified-json", "slsa-provenance-json") 75 | 76 | f.StringArrayVarP(&opts.attributionAnnotations, "attribution-annotation", "a", []string{}, "optional flag to add 'string-key:string-value' attributions to the manifest layer history (only added for layers not 'FROM ')") 77 | 78 | return cobraCmd 79 | } 80 | 81 | func (opts *generateCmdOpts) run() error { 82 | ctx := context.Background() 83 | 84 | annotationsMap, err := getAnnotationsMap(opts.attributionAnnotations) 85 | if err != nil { 86 | return err 87 | } 88 | 89 | imageClient, err := client.NewImageClient(opts.username, opts.password, opts.imageRef) 90 | if err != nil { 91 | return err 92 | } 93 | 94 | // imageLayerHistory is sorted from top layers (most recent layers) to bottom layers (base image layers). 95 | imageLayerHistory, err := imageClient.GetImageLayerHistory(ctx) 96 | if err != nil { 97 | return err 98 | } 99 | 100 | imageManifest, err := imageClient.GetImageManifest(ctx) 101 | if err != nil { 102 | return err 103 | } 104 | 105 | // dockerfileCommands is sorted based on the original order of commands in the Dockerfile. 106 | // E.g. if the Dockerfile contains the following commands: 107 | // FROM ubuntu:22.04 108 | // RUN apt-get update 109 | // RUN apt-get install -y vim 110 | // then dockerfileCommands will be: 111 | // []dockerfile.Command{ 112 | // dockerfile.Command{Original: "FROM ubuntu:22.04", Cmd: "FROM", Value: []string{"ubuntu:22.04"}}, 113 | // dockerfile.Command{Original: "RUN apt-get update", Cmd: "RUN", Value: []string{"apt-get", "update"}}, 114 | // dockerfile.Command{Original: "RUN apt-get install -y vim", Cmd: "run", Value: []string{"apt-get", "install", "-y", "vim"}}, 115 | // } 116 | dockerfileCommands, err := dockerfile.ParseFile(opts.dockerfilePath) 117 | if err != nil { 118 | return err 119 | } 120 | 121 | h := history.ImageHistory{ 122 | ImageLayerHistory: imageLayerHistory, 123 | ImageManifest: imageManifest, 124 | DockerfileCommands: dockerfileCommands, 125 | } 126 | 127 | manifestLayerHistory, err := h.GetImageManifestLayerDockerfileCommandsHistory(annotationsMap) 128 | if err != nil { 129 | return err 130 | } 131 | 132 | return opts.writeManifestLayerHistory(manifestLayerHistory) 133 | 134 | } 135 | 136 | func (opts *generateCmdOpts) writeManifestLayerHistory(manifestLayerHistory []history.ImageManifestLayerDockerfileCommandsHistory) error { 137 | output, err := json.MarshalIndent(manifestLayerHistory, "", " ") 138 | if err != nil { 139 | return err 140 | } 141 | 142 | if opts.simplifiedJsonOutput { 143 | simplified := history.GetSimplifiedImageManifestLayerDockerfileCommandsHistory(manifestLayerHistory) 144 | output, err = json.MarshalIndent(simplified, "", " ") 145 | if err != nil { 146 | return err 147 | } 148 | } else if opts.slsaProvenanceJsonOutput { 149 | var imageSlsaProvenanceStatements []*intoto.ProvenanceStatement 150 | timeNow := time.Now() 151 | for _, layerHistory := range manifestLayerHistory { 152 | layerSlsaProvenance := slsa.ImageManifestLayerSlsaProvenance{ 153 | LayerHistory: layerHistory, 154 | BuilderID: "Build pipeline URI.", 155 | BuildType: "Type of image build, such as 'dockerfile-build', 'buildkit-build', 'bazel-build', etc.", 156 | BuildInvocationID: "Build pipeline ID number", 157 | BuildStartedOn: &timeNow, 158 | BuildFinishedOn: &timeNow, 159 | RepoURIContainingImageSource: "URI to Git repo of image config. For Dockerfile builds, this is a git URI to the Dockerfile (e.g. github.com/org/repo/tree/main/Dockerfile)", 160 | RepoGitCommit: "Git commit SHA that kicked off the build.", 161 | RepoPathToImageSource: "Path to image config in the repo (e.g. path/to/Dockerfile)", 162 | } 163 | layerSlsaProvenanceStatement, err := layerSlsaProvenance.GetImageManifestLayerSlsaProvenance() 164 | if err != nil { 165 | return err 166 | } 167 | imageSlsaProvenanceStatements = append(imageSlsaProvenanceStatements, layerSlsaProvenanceStatement) 168 | } 169 | output, err = json.MarshalIndent(imageSlsaProvenanceStatements, "", " ") 170 | if err != nil { 171 | return err 172 | } 173 | } 174 | 175 | output = append(output, '\n') 176 | 177 | if opts.outputFilePath != "" { 178 | return writeToFile(opts.outputFilePath, output) 179 | } 180 | 181 | _, err = opts.stdout.Write(output) 182 | return err 183 | } 184 | 185 | // getAnnotationsMap returns a map of annotations from a slice of annotation strings. 186 | // strings in the slice should conform to the following format: "key: value". 187 | func getAnnotationsMap(annotationSlice []string) (map[string]string, error) { 188 | re := regexp.MustCompile(`:\s*`) 189 | annotationsMap := make(map[string]string) 190 | for _, rawAnnotation := range annotationSlice { 191 | annotation := re.Split(rawAnnotation, 2) 192 | if len(annotation) != 2 { 193 | return nil, fmt.Errorf("invalid annotation: %s", rawAnnotation) 194 | } 195 | annotationsMap[annotation[0]] = annotation[1] 196 | } 197 | return annotationsMap, nil 198 | } 199 | 200 | func writeToFile(path string, data []byte) error { 201 | f, err := os.Create(path) 202 | if err != nil { 203 | return err 204 | } 205 | defer f.Close() 206 | _, err = f.Write(data) 207 | return err 208 | } 209 | -------------------------------------------------------------------------------- /examples/scratch-base-singlestage/oci-image-manifest-layer-history-slsa.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_type": "https://in-toto.io/Statement/v0.1", 4 | "predicateType": "https://slsa.dev/provenance/v0.2", 5 | "subject": [ 6 | { 7 | "name": "sha256:7942f3be722fa3927b29ccc51521f0f0d9b0b8979fc4148d3d94f05acc0bdf44", 8 | "digest": { 9 | "sha256": "7942f3be722fa3927b29ccc51521f0f0d9b0b8979fc4148d3d94f05acc0bdf44" 10 | } 11 | } 12 | ], 13 | "predicate": { 14 | "builder": { 15 | "id": "Build pipeline URI." 16 | }, 17 | "buildType": "Type of image build, such as 'dockerfile-build', 'buildkit-build', 'bazel-build', etc.", 18 | "invocation": { 19 | "configSource": { 20 | "uri": "URI to Git repo of image config. For Dockerfile builds, this is a git URI to the Dockerfile (e.g. github.com/org/repo/tree/main/Dockerfile)", 21 | "digest": { 22 | "commit": "Git commit SHA that kicked off the build." 23 | }, 24 | "entryPoint": "Path to image config in the repo (e.g. path/to/Dockerfile)" 25 | }, 26 | "parameters": { 27 | "LayerHistory": { 28 | "LayerDescriptor": { 29 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 30 | "digest": "sha256:7942f3be722fa3927b29ccc51521f0f0d9b0b8979fc4148d3d94f05acc0bdf44", 31 | "size": 1100327 32 | }, 33 | "LayerCreationParameters": { 34 | "DockerfileLayerCreationType": "ADD-CommandLayer", 35 | "DockerfileCommands": [ 36 | { 37 | "Cmd": "ADD", 38 | "SubCmd": "", 39 | "Json": false, 40 | "Original": "ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz", 41 | "StartLine": 6, 42 | "EndLine": 6, 43 | "Flags": [], 44 | "Value": [ 45 | "https://github.com/kubernetes/client-go/archive/master.tar.gz", 46 | "/kubernetes/client-go.tar.gz" 47 | ] 48 | } 49 | ], 50 | "BaseImage": "" 51 | }, 52 | "AttributedEntity": { 53 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 54 | } 55 | } 56 | } 57 | }, 58 | "metadata": { 59 | "buildInvocationID": "Build pipeline ID number", 60 | "buildStartedOn": "2022-09-20T10:34:02.331149123-07:00", 61 | "buildFinishedOn": "2022-09-20T10:34:02.331149123-07:00", 62 | "completeness": { 63 | "parameters": false, 64 | "environment": false, 65 | "materials": false 66 | }, 67 | "reproducible": false 68 | } 69 | } 70 | }, 71 | { 72 | "_type": "https://in-toto.io/Statement/v0.1", 73 | "predicateType": "https://slsa.dev/provenance/v0.2", 74 | "subject": [ 75 | { 76 | "name": "sha256:5a2bf799221e80ef7d379a58541383020761546107861b322d0d30c34840c74e", 77 | "digest": { 78 | "sha256": "5a2bf799221e80ef7d379a58541383020761546107861b322d0d30c34840c74e" 79 | } 80 | } 81 | ], 82 | "predicate": { 83 | "builder": { 84 | "id": "Build pipeline URI." 85 | }, 86 | "buildType": "Type of image build, such as 'dockerfile-build', 'buildkit-build', 'bazel-build', etc.", 87 | "invocation": { 88 | "configSource": { 89 | "uri": "URI to Git repo of image config. For Dockerfile builds, this is a git URI to the Dockerfile (e.g. github.com/org/repo/tree/main/Dockerfile)", 90 | "digest": { 91 | "commit": "Git commit SHA that kicked off the build." 92 | }, 93 | "entryPoint": "Path to image config in the repo (e.g. path/to/Dockerfile)" 94 | }, 95 | "parameters": { 96 | "LayerHistory": { 97 | "LayerDescriptor": { 98 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 99 | "digest": "sha256:5a2bf799221e80ef7d379a58541383020761546107861b322d0d30c34840c74e", 100 | "size": 2727414 101 | }, 102 | "LayerCreationParameters": { 103 | "DockerfileLayerCreationType": "ADD-CommandLayer", 104 | "DockerfileCommands": [ 105 | { 106 | "Cmd": "ADD", 107 | "SubCmd": "", 108 | "Json": false, 109 | "Original": "ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz", 110 | "StartLine": 12, 111 | "EndLine": 12, 112 | "Flags": [], 113 | "Value": [ 114 | "https://github.com/kubernetes/kubectl/archive/master.tar.gz", 115 | "/kubernetes/kubectl.tar.gz" 116 | ] 117 | } 118 | ], 119 | "BaseImage": "" 120 | }, 121 | "AttributedEntity": { 122 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 123 | } 124 | } 125 | } 126 | }, 127 | "metadata": { 128 | "buildInvocationID": "Build pipeline ID number", 129 | "buildStartedOn": "2022-09-20T10:34:02.331149123-07:00", 130 | "buildFinishedOn": "2022-09-20T10:34:02.331149123-07:00", 131 | "completeness": { 132 | "parameters": false, 133 | "environment": false, 134 | "materials": false 135 | }, 136 | "reproducible": false 137 | } 138 | } 139 | }, 140 | { 141 | "_type": "https://in-toto.io/Statement/v0.1", 142 | "predicateType": "https://slsa.dev/provenance/v0.2", 143 | "subject": [ 144 | { 145 | "name": "sha256:bef044d3345e7eef96b2658e006eb3761a621be5c069e559e975e98c154e5d0b", 146 | "digest": { 147 | "sha256": "bef044d3345e7eef96b2658e006eb3761a621be5c069e559e975e98c154e5d0b" 148 | } 149 | } 150 | ], 151 | "predicate": { 152 | "builder": { 153 | "id": "Build pipeline URI." 154 | }, 155 | "buildType": "Type of image build, such as 'dockerfile-build', 'buildkit-build', 'bazel-build', etc.", 156 | "invocation": { 157 | "configSource": { 158 | "uri": "URI to Git repo of image config. For Dockerfile builds, this is a git URI to the Dockerfile (e.g. github.com/org/repo/tree/main/Dockerfile)", 159 | "digest": { 160 | "commit": "Git commit SHA that kicked off the build." 161 | }, 162 | "entryPoint": "Path to image config in the repo (e.g. path/to/Dockerfile)" 163 | }, 164 | "parameters": { 165 | "LayerHistory": { 166 | "LayerDescriptor": { 167 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 168 | "digest": "sha256:bef044d3345e7eef96b2658e006eb3761a621be5c069e559e975e98c154e5d0b", 169 | "size": 22473758 170 | }, 171 | "LayerCreationParameters": { 172 | "DockerfileLayerCreationType": "ADD-CommandLayer", 173 | "DockerfileCommands": [ 174 | { 175 | "Cmd": "ADD", 176 | "SubCmd": "", 177 | "Json": false, 178 | "Original": "ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz", 179 | "StartLine": 18, 180 | "EndLine": 18, 181 | "Flags": [], 182 | "Value": [ 183 | "https://github.com/kubernetes/dashboard/archive/master.tar.gz", 184 | "/kubernetes/dashboard.tar.gz" 185 | ] 186 | } 187 | ], 188 | "BaseImage": "" 189 | }, 190 | "AttributedEntity": { 191 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 192 | } 193 | } 194 | } 195 | }, 196 | "metadata": { 197 | "buildInvocationID": "Build pipeline ID number", 198 | "buildStartedOn": "2022-09-20T10:34:02.331149123-07:00", 199 | "buildFinishedOn": "2022-09-20T10:34:02.331149123-07:00", 200 | "completeness": { 201 | "parameters": false, 202 | "environment": false, 203 | "materials": false 204 | }, 205 | "reproducible": false 206 | } 207 | } 208 | } 209 | ] 210 | -------------------------------------------------------------------------------- /examples/postgres-base-singlestage/oci-image-manifest-layer-history-simplified.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "LayerDigest": "sha256:31b3f1ad4ce1f369084d0f959813c51df0ca17d9877d5ee88c2db6ff88341430", 4 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 5 | "DockerfileCommands": [ 6 | "FROM docker.io/library/postgres:14-bullseye" 7 | ], 8 | "BaseImage": "docker.io/library/postgres:14-bullseye", 9 | "AttributedEntity": { 10 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 11 | } 12 | }, 13 | { 14 | "LayerDigest": "sha256:dc97844d0cd5332f8a27d4e812cb78fe28eb3a24d6447b298e11f4c1381ee04b", 15 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 16 | "DockerfileCommands": [ 17 | "FROM docker.io/library/postgres:14-bullseye" 18 | ], 19 | "BaseImage": "docker.io/library/postgres:14-bullseye", 20 | "AttributedEntity": { 21 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 22 | } 23 | }, 24 | { 25 | "LayerDigest": "sha256:9ad9b1166fde5ac579a870942e64b1252b809a74ce2716537b2ec7d29211aa0e", 26 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 27 | "DockerfileCommands": [ 28 | "FROM docker.io/library/postgres:14-bullseye" 29 | ], 30 | "BaseImage": "docker.io/library/postgres:14-bullseye", 31 | "AttributedEntity": { 32 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 33 | } 34 | }, 35 | { 36 | "LayerDigest": "sha256:286c4682b24df07908e721b97e0e931e7094b0822d4dd0623c48684960c892c0", 37 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 38 | "DockerfileCommands": [ 39 | "FROM docker.io/library/postgres:14-bullseye" 40 | ], 41 | "BaseImage": "docker.io/library/postgres:14-bullseye", 42 | "AttributedEntity": { 43 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 44 | } 45 | }, 46 | { 47 | "LayerDigest": "sha256:1d3679a4a1a1adeb649c1019cdb9ba6be5f79b5035e1ec221fcf583033a34926", 48 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 49 | "DockerfileCommands": [ 50 | "FROM docker.io/library/postgres:14-bullseye" 51 | ], 52 | "BaseImage": "docker.io/library/postgres:14-bullseye", 53 | "AttributedEntity": { 54 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 55 | } 56 | }, 57 | { 58 | "LayerDigest": "sha256:5f2e6cdc8503192834c8294003826329e7af061a1f47f07993501623d7ccedea", 59 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 60 | "DockerfileCommands": [ 61 | "FROM docker.io/library/postgres:14-bullseye" 62 | ], 63 | "BaseImage": "docker.io/library/postgres:14-bullseye", 64 | "AttributedEntity": { 65 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 66 | } 67 | }, 68 | { 69 | "LayerDigest": "sha256:0f7dc70f54e874e4d3bfa632e989030d30740819b8c4612427817302aa8add51", 70 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 71 | "DockerfileCommands": [ 72 | "FROM docker.io/library/postgres:14-bullseye" 73 | ], 74 | "BaseImage": "docker.io/library/postgres:14-bullseye", 75 | "AttributedEntity": { 76 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 77 | } 78 | }, 79 | { 80 | "LayerDigest": "sha256:a090c7442692840048d70c9acd1c55039a7f996487443a737aaa51ce10fea1d0", 81 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 82 | "DockerfileCommands": [ 83 | "FROM docker.io/library/postgres:14-bullseye" 84 | ], 85 | "BaseImage": "docker.io/library/postgres:14-bullseye", 86 | "AttributedEntity": { 87 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 88 | } 89 | }, 90 | { 91 | "LayerDigest": "sha256:81bfe40fd0f61b92c803640298635127dceffdb8bb976b18deb65cea5fa8f1d7", 92 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 93 | "DockerfileCommands": [ 94 | "FROM docker.io/library/postgres:14-bullseye" 95 | ], 96 | "BaseImage": "docker.io/library/postgres:14-bullseye", 97 | "AttributedEntity": { 98 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 99 | } 100 | }, 101 | { 102 | "LayerDigest": "sha256:8ac8c22bbb38c7671d1717440beedb42a16d08d7ed1a32dfe04a86cd46d7ec50", 103 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 104 | "DockerfileCommands": [ 105 | "FROM docker.io/library/postgres:14-bullseye" 106 | ], 107 | "BaseImage": "docker.io/library/postgres:14-bullseye", 108 | "AttributedEntity": { 109 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 110 | } 111 | }, 112 | { 113 | "LayerDigest": "sha256:96e51d1d3c6ed4891a0956205a17808f0f35d419a1eb42c975f1e30602dc432f", 114 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 115 | "DockerfileCommands": [ 116 | "FROM docker.io/library/postgres:14-bullseye" 117 | ], 118 | "BaseImage": "docker.io/library/postgres:14-bullseye", 119 | "AttributedEntity": { 120 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 121 | } 122 | }, 123 | { 124 | "LayerDigest": "sha256:667bd4154fa25c0f9c5c66e563d1dce64f050067cf6019985909335aa140d018", 125 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 126 | "DockerfileCommands": [ 127 | "FROM docker.io/library/postgres:14-bullseye" 128 | ], 129 | "BaseImage": "docker.io/library/postgres:14-bullseye", 130 | "AttributedEntity": { 131 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 132 | } 133 | }, 134 | { 135 | "LayerDigest": "sha256:87267fb600a9542046b27cc191951fe9abb6fd7c2946ba94c604bf6911579b5b", 136 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 137 | "DockerfileCommands": [ 138 | "FROM docker.io/library/postgres:14-bullseye" 139 | ], 140 | "BaseImage": "docker.io/library/postgres:14-bullseye", 141 | "AttributedEntity": { 142 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 143 | } 144 | }, 145 | { 146 | "LayerDigest": "sha256:245e2967cc420fc67f6748f57b4c84f77e13438eb919963b6ec5cf617ca1935d", 147 | "DockerfileLayerCreationType": "ADD-CommandLayer", 148 | "DockerfileCommands": [ 149 | "ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz" 150 | ], 151 | "BaseImage": "", 152 | "AttributedEntity": { 153 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 154 | } 155 | }, 156 | { 157 | "LayerDigest": "sha256:c676364f47f073e7ee3437e55416792524490544f53a3e60e4ae9e20f1319bed", 158 | "DockerfileLayerCreationType": "RUN-CommandLayer", 159 | "DockerfileCommands": [ 160 | "RUN echo \"hello\" \u003e /hello.txt" 161 | ], 162 | "BaseImage": "", 163 | "AttributedEntity": { 164 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 165 | } 166 | }, 167 | { 168 | "LayerDigest": "sha256:5f112f02ac03c1c74fc56d4111f227c5240566d539b53cc3069d982956fdbb1e", 169 | "DockerfileLayerCreationType": "ADD-CommandLayer", 170 | "DockerfileCommands": [ 171 | "ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz" 172 | ], 173 | "BaseImage": "", 174 | "AttributedEntity": { 175 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 176 | } 177 | }, 178 | { 179 | "LayerDigest": "sha256:e2bfa24d56ea5c13d905caf07d21811b5be1fd6dfa639daea34099b9b4d5a832", 180 | "DockerfileLayerCreationType": "RUN-CommandLayer", 181 | "DockerfileCommands": [ 182 | "RUN echo \"breakfast\" \u003e /breakfast.txt" 183 | ], 184 | "BaseImage": "", 185 | "AttributedEntity": { 186 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 187 | } 188 | }, 189 | { 190 | "LayerDigest": "sha256:ea65f518ba4f1fe833c8b5a682d33b21777f73d19a35526c4af85b98aba05da6", 191 | "DockerfileLayerCreationType": "ADD-CommandLayer", 192 | "DockerfileCommands": [ 193 | "ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz" 194 | ], 195 | "BaseImage": "", 196 | "AttributedEntity": { 197 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 198 | } 199 | }, 200 | { 201 | "LayerDigest": "sha256:466768514f44339060217fe50ec6db3477be27506b2735657db4832ea25f3891", 202 | "DockerfileLayerCreationType": "RUN-CommandLayer", 203 | "DockerfileCommands": [ 204 | "RUN echo \"goodbye\" \u003e /goodbye.txt" 205 | ], 206 | "BaseImage": "", 207 | "AttributedEntity": { 208 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 209 | } 210 | } 211 | ] 212 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= 2 | github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= 3 | github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= 4 | github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= 5 | github.com/asottile/dockerfile v3.1.0+incompatible h1:DovtIJuWXp2xbTxT4OkF753kfAkwizIgmewMrq/T/ok= 6 | github.com/asottile/dockerfile v3.1.0+incompatible/go.mod h1:z3uYnlNGA9635hb4kbb2DRnlR9XLQ4HsYsDer3slsjA= 7 | github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= 8 | github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= 9 | github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= 10 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 11 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 13 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14 | github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= 15 | github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 16 | github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE= 17 | github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 18 | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= 19 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= 20 | github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= 21 | github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 22 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 23 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 24 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 25 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 26 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 27 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 28 | github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= 29 | github.com/in-toto/in-toto-golang v0.4.0-prerelease h1:70ri0AeRoMUD/bHbetiHURPuOVa2C2L1bu8T6wY5HB4= 30 | github.com/in-toto/in-toto-golang v0.4.0-prerelease/go.mod h1:GviRIbq8Azwe0KsyGanAlpafHZ+qVbekc9SuI3yVp4E= 31 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 32 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 33 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 34 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 35 | github.com/moby/buildkit v0.10.3 h1:/dGykD8FW+H4p++q5+KqKEo6gAkYKyBQHdawdjVwVAU= 36 | github.com/moby/buildkit v0.10.3/go.mod h1:jxeOuly98l9gWHai0Ojrbnczrk/rf+o9/JqNhY+UCSo= 37 | github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= 38 | github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= 39 | github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86 h1:Oumw+lPnO8qNLTY2mrqPJZMoGExLi/0h/DdikoLTXVU= 40 | github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86/go.mod h1:aA4vdXRS8E1TG7pLZOz85InHi3BiPdErh8IpJN6E0x4= 41 | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 42 | github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= 43 | github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= 44 | github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= 45 | github.com/oras-project/artifacts-spec v1.0.0-rc.1.0.20220707054150-eddd1d8790c9 h1:VucBcP8TBtYhqrquIcloJe7hUE+f6NumYEA7bzmJ5sc= 46 | github.com/oras-project/artifacts-spec v1.0.0-rc.1.0.20220707054150-eddd1d8790c9/go.mod h1:Xch2aLzSwtkhbFFN6LUzTfLtukYvMMdXJ4oZ8O7BOdc= 47 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 48 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 49 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 50 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 51 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 52 | github.com/secure-systems-lab/go-securesystemslib v0.1.0 h1:wZNQ7t1UTOQtDL/+PBPzxI52gLQGyC7qfXyJh6Lgf1Y= 53 | github.com/secure-systems-lab/go-securesystemslib v0.1.0/go.mod h1:eIjBmIP8LD2MLBL/DkQWayLiz006Q4p+hCu79rvWleY= 54 | github.com/shibumi/go-pathspec v1.2.0 h1:KVKEDHYk7bQolRMs7nfzjT3SBOCgcXFJzccnj9bsGbA= 55 | github.com/shibumi/go-pathspec v1.2.0/go.mod h1:bDxCftD0fST3qXIlHoQ/fChsU4mWMVklXp1yPErQaaY= 56 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 57 | github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= 58 | github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 59 | github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= 60 | github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= 61 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 62 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 63 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 64 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 65 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 66 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 67 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 68 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 69 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 70 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 71 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 72 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 73 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 74 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 75 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 76 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 77 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 78 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 79 | golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= 80 | golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 81 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 82 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 83 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 84 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= 85 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 86 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 87 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 88 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 89 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 90 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 91 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 92 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= 93 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 94 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 95 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 96 | golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ= 97 | golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 98 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 99 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 100 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 101 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 102 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 103 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 104 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 105 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 106 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 107 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 108 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 109 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 110 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 111 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 112 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 113 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 114 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 115 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 116 | gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo= 117 | gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= 118 | oras.land/oras-go/v2 v2.0.0-rc.1 h1:PtQ+/mCiumx7IwT9EIuirQWtGRWBJQR/gjQMu9uY/pk= 119 | oras.land/oras-go/v2 v2.0.0-rc.1/go.mod h1:L0vZVPSGR2a8i6+tIiva8HGLroO4JF2ifeaBMy6dYa8= 120 | -------------------------------------------------------------------------------- /examples/postgres-base-vanilla/oci-image-manifest-layer-history.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "LayerDescriptor": { 4 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 5 | "digest": "sha256:31b3f1ad4ce1f369084d0f959813c51df0ca17d9877d5ee88c2db6ff88341430", 6 | "size": 31404121 7 | }, 8 | "LayerCreationParameters": { 9 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 10 | "DockerfileCommands": [ 11 | { 12 | "Cmd": "FROM", 13 | "SubCmd": "", 14 | "Json": false, 15 | "Original": "FROM docker.io/library/postgres:14-bullseye", 16 | "StartLine": 1, 17 | "EndLine": 1, 18 | "Flags": [], 19 | "Value": [ 20 | "docker.io/library/postgres:14-bullseye" 21 | ] 22 | } 23 | ], 24 | "BaseImage": "docker.io/library/postgres:14-bullseye" 25 | }, 26 | "AttributedEntity": { 27 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 28 | } 29 | }, 30 | { 31 | "LayerDescriptor": { 32 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 33 | "digest": "sha256:dc97844d0cd5332f8a27d4e812cb78fe28eb3a24d6447b298e11f4c1381ee04b", 34 | "size": 4414809 35 | }, 36 | "LayerCreationParameters": { 37 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 38 | "DockerfileCommands": [ 39 | { 40 | "Cmd": "FROM", 41 | "SubCmd": "", 42 | "Json": false, 43 | "Original": "FROM docker.io/library/postgres:14-bullseye", 44 | "StartLine": 1, 45 | "EndLine": 1, 46 | "Flags": [], 47 | "Value": [ 48 | "docker.io/library/postgres:14-bullseye" 49 | ] 50 | } 51 | ], 52 | "BaseImage": "docker.io/library/postgres:14-bullseye" 53 | }, 54 | "AttributedEntity": { 55 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 56 | } 57 | }, 58 | { 59 | "LayerDescriptor": { 60 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 61 | "digest": "sha256:9ad9b1166fde5ac579a870942e64b1252b809a74ce2716537b2ec7d29211aa0e", 62 | "size": 1798 63 | }, 64 | "LayerCreationParameters": { 65 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 66 | "DockerfileCommands": [ 67 | { 68 | "Cmd": "FROM", 69 | "SubCmd": "", 70 | "Json": false, 71 | "Original": "FROM docker.io/library/postgres:14-bullseye", 72 | "StartLine": 1, 73 | "EndLine": 1, 74 | "Flags": [], 75 | "Value": [ 76 | "docker.io/library/postgres:14-bullseye" 77 | ] 78 | } 79 | ], 80 | "BaseImage": "docker.io/library/postgres:14-bullseye" 81 | }, 82 | "AttributedEntity": { 83 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 84 | } 85 | }, 86 | { 87 | "LayerDescriptor": { 88 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 89 | "digest": "sha256:286c4682b24df07908e721b97e0e931e7094b0822d4dd0623c48684960c892c0", 90 | "size": 1418427 91 | }, 92 | "LayerCreationParameters": { 93 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 94 | "DockerfileCommands": [ 95 | { 96 | "Cmd": "FROM", 97 | "SubCmd": "", 98 | "Json": false, 99 | "Original": "FROM docker.io/library/postgres:14-bullseye", 100 | "StartLine": 1, 101 | "EndLine": 1, 102 | "Flags": [], 103 | "Value": [ 104 | "docker.io/library/postgres:14-bullseye" 105 | ] 106 | } 107 | ], 108 | "BaseImage": "docker.io/library/postgres:14-bullseye" 109 | }, 110 | "AttributedEntity": { 111 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 112 | } 113 | }, 114 | { 115 | "LayerDescriptor": { 116 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 117 | "digest": "sha256:1d3679a4a1a1adeb649c1019cdb9ba6be5f79b5035e1ec221fcf583033a34926", 118 | "size": 8045146 119 | }, 120 | "LayerCreationParameters": { 121 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 122 | "DockerfileCommands": [ 123 | { 124 | "Cmd": "FROM", 125 | "SubCmd": "", 126 | "Json": false, 127 | "Original": "FROM docker.io/library/postgres:14-bullseye", 128 | "StartLine": 1, 129 | "EndLine": 1, 130 | "Flags": [], 131 | "Value": [ 132 | "docker.io/library/postgres:14-bullseye" 133 | ] 134 | } 135 | ], 136 | "BaseImage": "docker.io/library/postgres:14-bullseye" 137 | }, 138 | "AttributedEntity": { 139 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 140 | } 141 | }, 142 | { 143 | "LayerDescriptor": { 144 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 145 | "digest": "sha256:5f2e6cdc8503192834c8294003826329e7af061a1f47f07993501623d7ccedea", 146 | "size": 1261090 147 | }, 148 | "LayerCreationParameters": { 149 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 150 | "DockerfileCommands": [ 151 | { 152 | "Cmd": "FROM", 153 | "SubCmd": "", 154 | "Json": false, 155 | "Original": "FROM docker.io/library/postgres:14-bullseye", 156 | "StartLine": 1, 157 | "EndLine": 1, 158 | "Flags": [], 159 | "Value": [ 160 | "docker.io/library/postgres:14-bullseye" 161 | ] 162 | } 163 | ], 164 | "BaseImage": "docker.io/library/postgres:14-bullseye" 165 | }, 166 | "AttributedEntity": { 167 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 168 | } 169 | }, 170 | { 171 | "LayerDescriptor": { 172 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 173 | "digest": "sha256:0f7dc70f54e874e4d3bfa632e989030d30740819b8c4612427817302aa8add51", 174 | "size": 149 175 | }, 176 | "LayerCreationParameters": { 177 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 178 | "DockerfileCommands": [ 179 | { 180 | "Cmd": "FROM", 181 | "SubCmd": "", 182 | "Json": false, 183 | "Original": "FROM docker.io/library/postgres:14-bullseye", 184 | "StartLine": 1, 185 | "EndLine": 1, 186 | "Flags": [], 187 | "Value": [ 188 | "docker.io/library/postgres:14-bullseye" 189 | ] 190 | } 191 | ], 192 | "BaseImage": "docker.io/library/postgres:14-bullseye" 193 | }, 194 | "AttributedEntity": { 195 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 196 | } 197 | }, 198 | { 199 | "LayerDescriptor": { 200 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 201 | "digest": "sha256:a090c7442692840048d70c9acd1c55039a7f996487443a737aaa51ce10fea1d0", 202 | "size": 3190 203 | }, 204 | "LayerCreationParameters": { 205 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 206 | "DockerfileCommands": [ 207 | { 208 | "Cmd": "FROM", 209 | "SubCmd": "", 210 | "Json": false, 211 | "Original": "FROM docker.io/library/postgres:14-bullseye", 212 | "StartLine": 1, 213 | "EndLine": 1, 214 | "Flags": [], 215 | "Value": [ 216 | "docker.io/library/postgres:14-bullseye" 217 | ] 218 | } 219 | ], 220 | "BaseImage": "docker.io/library/postgres:14-bullseye" 221 | }, 222 | "AttributedEntity": { 223 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 224 | } 225 | }, 226 | { 227 | "LayerDescriptor": { 228 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 229 | "digest": "sha256:81bfe40fd0f61b92c803640298635127dceffdb8bb976b18deb65cea5fa8f1d7", 230 | "size": 91324554 231 | }, 232 | "LayerCreationParameters": { 233 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 234 | "DockerfileCommands": [ 235 | { 236 | "Cmd": "FROM", 237 | "SubCmd": "", 238 | "Json": false, 239 | "Original": "FROM docker.io/library/postgres:14-bullseye", 240 | "StartLine": 1, 241 | "EndLine": 1, 242 | "Flags": [], 243 | "Value": [ 244 | "docker.io/library/postgres:14-bullseye" 245 | ] 246 | } 247 | ], 248 | "BaseImage": "docker.io/library/postgres:14-bullseye" 249 | }, 250 | "AttributedEntity": { 251 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 252 | } 253 | }, 254 | { 255 | "LayerDescriptor": { 256 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 257 | "digest": "sha256:8ac8c22bbb38c7671d1717440beedb42a16d08d7ed1a32dfe04a86cd46d7ec50", 258 | "size": 9533 259 | }, 260 | "LayerCreationParameters": { 261 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 262 | "DockerfileCommands": [ 263 | { 264 | "Cmd": "FROM", 265 | "SubCmd": "", 266 | "Json": false, 267 | "Original": "FROM docker.io/library/postgres:14-bullseye", 268 | "StartLine": 1, 269 | "EndLine": 1, 270 | "Flags": [], 271 | "Value": [ 272 | "docker.io/library/postgres:14-bullseye" 273 | ] 274 | } 275 | ], 276 | "BaseImage": "docker.io/library/postgres:14-bullseye" 277 | }, 278 | "AttributedEntity": { 279 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 280 | } 281 | }, 282 | { 283 | "LayerDescriptor": { 284 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 285 | "digest": "sha256:96e51d1d3c6ed4891a0956205a17808f0f35d419a1eb42c975f1e30602dc432f", 286 | "size": 129 287 | }, 288 | "LayerCreationParameters": { 289 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 290 | "DockerfileCommands": [ 291 | { 292 | "Cmd": "FROM", 293 | "SubCmd": "", 294 | "Json": false, 295 | "Original": "FROM docker.io/library/postgres:14-bullseye", 296 | "StartLine": 1, 297 | "EndLine": 1, 298 | "Flags": [], 299 | "Value": [ 300 | "docker.io/library/postgres:14-bullseye" 301 | ] 302 | } 303 | ], 304 | "BaseImage": "docker.io/library/postgres:14-bullseye" 305 | }, 306 | "AttributedEntity": { 307 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 308 | } 309 | }, 310 | { 311 | "LayerDescriptor": { 312 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 313 | "digest": "sha256:667bd4154fa25c0f9c5c66e563d1dce64f050067cf6019985909335aa140d018", 314 | "size": 200 315 | }, 316 | "LayerCreationParameters": { 317 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 318 | "DockerfileCommands": [ 319 | { 320 | "Cmd": "FROM", 321 | "SubCmd": "", 322 | "Json": false, 323 | "Original": "FROM docker.io/library/postgres:14-bullseye", 324 | "StartLine": 1, 325 | "EndLine": 1, 326 | "Flags": [], 327 | "Value": [ 328 | "docker.io/library/postgres:14-bullseye" 329 | ] 330 | } 331 | ], 332 | "BaseImage": "docker.io/library/postgres:14-bullseye" 333 | }, 334 | "AttributedEntity": { 335 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 336 | } 337 | }, 338 | { 339 | "LayerDescriptor": { 340 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 341 | "digest": "sha256:87267fb600a9542046b27cc191951fe9abb6fd7c2946ba94c604bf6911579b5b", 342 | "size": 4697 343 | }, 344 | "LayerCreationParameters": { 345 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 346 | "DockerfileCommands": [ 347 | { 348 | "Cmd": "FROM", 349 | "SubCmd": "", 350 | "Json": false, 351 | "Original": "FROM docker.io/library/postgres:14-bullseye", 352 | "StartLine": 1, 353 | "EndLine": 1, 354 | "Flags": [], 355 | "Value": [ 356 | "docker.io/library/postgres:14-bullseye" 357 | ] 358 | } 359 | ], 360 | "BaseImage": "docker.io/library/postgres:14-bullseye" 361 | }, 362 | "AttributedEntity": { 363 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 364 | } 365 | } 366 | ] 367 | -------------------------------------------------------------------------------- /examples/postgres-base-multistage/oci-image-manifest-layer-history-simplified.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "LayerDigest": "sha256:31b3f1ad4ce1f369084d0f959813c51df0ca17d9877d5ee88c2db6ff88341430", 4 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 5 | "DockerfileCommands": [ 6 | "FROM docker.io/library/postgres:14-bullseye" 7 | ], 8 | "BaseImage": "docker.io/library/postgres:14-bullseye", 9 | "AttributedEntity": { 10 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 11 | } 12 | }, 13 | { 14 | "LayerDigest": "sha256:dc97844d0cd5332f8a27d4e812cb78fe28eb3a24d6447b298e11f4c1381ee04b", 15 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 16 | "DockerfileCommands": [ 17 | "FROM docker.io/library/postgres:14-bullseye" 18 | ], 19 | "BaseImage": "docker.io/library/postgres:14-bullseye", 20 | "AttributedEntity": { 21 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 22 | } 23 | }, 24 | { 25 | "LayerDigest": "sha256:9ad9b1166fde5ac579a870942e64b1252b809a74ce2716537b2ec7d29211aa0e", 26 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 27 | "DockerfileCommands": [ 28 | "FROM docker.io/library/postgres:14-bullseye" 29 | ], 30 | "BaseImage": "docker.io/library/postgres:14-bullseye", 31 | "AttributedEntity": { 32 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 33 | } 34 | }, 35 | { 36 | "LayerDigest": "sha256:286c4682b24df07908e721b97e0e931e7094b0822d4dd0623c48684960c892c0", 37 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 38 | "DockerfileCommands": [ 39 | "FROM docker.io/library/postgres:14-bullseye" 40 | ], 41 | "BaseImage": "docker.io/library/postgres:14-bullseye", 42 | "AttributedEntity": { 43 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 44 | } 45 | }, 46 | { 47 | "LayerDigest": "sha256:1d3679a4a1a1adeb649c1019cdb9ba6be5f79b5035e1ec221fcf583033a34926", 48 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 49 | "DockerfileCommands": [ 50 | "FROM docker.io/library/postgres:14-bullseye" 51 | ], 52 | "BaseImage": "docker.io/library/postgres:14-bullseye", 53 | "AttributedEntity": { 54 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 55 | } 56 | }, 57 | { 58 | "LayerDigest": "sha256:5f2e6cdc8503192834c8294003826329e7af061a1f47f07993501623d7ccedea", 59 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 60 | "DockerfileCommands": [ 61 | "FROM docker.io/library/postgres:14-bullseye" 62 | ], 63 | "BaseImage": "docker.io/library/postgres:14-bullseye", 64 | "AttributedEntity": { 65 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 66 | } 67 | }, 68 | { 69 | "LayerDigest": "sha256:0f7dc70f54e874e4d3bfa632e989030d30740819b8c4612427817302aa8add51", 70 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 71 | "DockerfileCommands": [ 72 | "FROM docker.io/library/postgres:14-bullseye" 73 | ], 74 | "BaseImage": "docker.io/library/postgres:14-bullseye", 75 | "AttributedEntity": { 76 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 77 | } 78 | }, 79 | { 80 | "LayerDigest": "sha256:a090c7442692840048d70c9acd1c55039a7f996487443a737aaa51ce10fea1d0", 81 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 82 | "DockerfileCommands": [ 83 | "FROM docker.io/library/postgres:14-bullseye" 84 | ], 85 | "BaseImage": "docker.io/library/postgres:14-bullseye", 86 | "AttributedEntity": { 87 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 88 | } 89 | }, 90 | { 91 | "LayerDigest": "sha256:81bfe40fd0f61b92c803640298635127dceffdb8bb976b18deb65cea5fa8f1d7", 92 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 93 | "DockerfileCommands": [ 94 | "FROM docker.io/library/postgres:14-bullseye" 95 | ], 96 | "BaseImage": "docker.io/library/postgres:14-bullseye", 97 | "AttributedEntity": { 98 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 99 | } 100 | }, 101 | { 102 | "LayerDigest": "sha256:8ac8c22bbb38c7671d1717440beedb42a16d08d7ed1a32dfe04a86cd46d7ec50", 103 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 104 | "DockerfileCommands": [ 105 | "FROM docker.io/library/postgres:14-bullseye" 106 | ], 107 | "BaseImage": "docker.io/library/postgres:14-bullseye", 108 | "AttributedEntity": { 109 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 110 | } 111 | }, 112 | { 113 | "LayerDigest": "sha256:96e51d1d3c6ed4891a0956205a17808f0f35d419a1eb42c975f1e30602dc432f", 114 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 115 | "DockerfileCommands": [ 116 | "FROM docker.io/library/postgres:14-bullseye" 117 | ], 118 | "BaseImage": "docker.io/library/postgres:14-bullseye", 119 | "AttributedEntity": { 120 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 121 | } 122 | }, 123 | { 124 | "LayerDigest": "sha256:667bd4154fa25c0f9c5c66e563d1dce64f050067cf6019985909335aa140d018", 125 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 126 | "DockerfileCommands": [ 127 | "FROM docker.io/library/postgres:14-bullseye" 128 | ], 129 | "BaseImage": "docker.io/library/postgres:14-bullseye", 130 | "AttributedEntity": { 131 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 132 | } 133 | }, 134 | { 135 | "LayerDigest": "sha256:87267fb600a9542046b27cc191951fe9abb6fd7c2946ba94c604bf6911579b5b", 136 | "DockerfileLayerCreationType": "FROM-PrimaryBaseImageLayer", 137 | "DockerfileCommands": [ 138 | "FROM docker.io/library/postgres:14-bullseye" 139 | ], 140 | "BaseImage": "docker.io/library/postgres:14-bullseye", 141 | "AttributedEntity": { 142 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 143 | } 144 | }, 145 | { 146 | "LayerDigest": "sha256:245e2967cc420fc67f6748f57b4c84f77e13438eb919963b6ec5cf617ca1935d", 147 | "DockerfileLayerCreationType": "ADD-CommandLayer", 148 | "DockerfileCommands": [ 149 | "ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz" 150 | ], 151 | "BaseImage": "", 152 | "AttributedEntity": { 153 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 154 | } 155 | }, 156 | { 157 | "LayerDigest": "sha256:c676364f47f073e7ee3437e55416792524490544f53a3e60e4ae9e20f1319bed", 158 | "DockerfileLayerCreationType": "RUN-CommandLayer", 159 | "DockerfileCommands": [ 160 | "RUN echo \"hello\" \u003e /hello.txt" 161 | ], 162 | "BaseImage": "", 163 | "AttributedEntity": { 164 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 165 | } 166 | }, 167 | { 168 | "LayerDigest": "sha256:f0007634565752c57366439569258a233a2e5a8c209dd29d9df9d7daaf161c2e", 169 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 170 | "DockerfileCommands": [ 171 | "FROM docker.io/library/node:18-bullseye", 172 | "RUN echo \"builder1Foo\" \u003e /builder1Foo.txt", 173 | "EXPOSE 8080/tcp", 174 | "EXPOSE 8080/udp", 175 | "ENV NODE_ENV_1=\"node_env_val_1\"", 176 | "RUN echo \"builder1Bar\" \u003e /builder1Bar.txt", 177 | "COPY --from=0 /builder1Foo.txt /builder1Foo.txt" 178 | ], 179 | "BaseImage": "docker.io/library/node:18-bullseye", 180 | "AttributedEntity": { 181 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 182 | } 183 | }, 184 | { 185 | "LayerDigest": "sha256:718e9aa42f6902fdde956e8435f0f34857708fce6ef461a197ea2f22bf19e3f0", 186 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 187 | "DockerfileCommands": [ 188 | "FROM docker.io/library/node:18-bullseye", 189 | "RUN echo \"builder1Foo\" \u003e /builder1Foo.txt", 190 | "EXPOSE 8080/tcp", 191 | "EXPOSE 8080/udp", 192 | "ENV NODE_ENV_1=\"node_env_val_1\"", 193 | "RUN echo \"builder1Bar\" \u003e /builder1Bar.txt", 194 | "COPY --from=0 /builder1Bar.txt /builder1Bar.txt" 195 | ], 196 | "BaseImage": "docker.io/library/node:18-bullseye", 197 | "AttributedEntity": { 198 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 199 | } 200 | }, 201 | { 202 | "LayerDigest": "sha256:115069ef94395c54e8d20e56883b80d1d7970290e8e0f0b662c3fa251c547d4c", 203 | "DockerfileLayerCreationType": "ADD-CommandLayer", 204 | "DockerfileCommands": [ 205 | "ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz" 206 | ], 207 | "BaseImage": "", 208 | "AttributedEntity": { 209 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 210 | } 211 | }, 212 | { 213 | "LayerDigest": "sha256:837bf7e7c4448b0e1cceb1a606bdb069a0e45f71d2b37b2a22266c8433a917dd", 214 | "DockerfileLayerCreationType": "RUN-CommandLayer", 215 | "DockerfileCommands": [ 216 | "RUN echo \"breakfast\" \u003e /breakfast.txt" 217 | ], 218 | "BaseImage": "", 219 | "AttributedEntity": { 220 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 221 | } 222 | }, 223 | { 224 | "LayerDigest": "sha256:50b974a802e3f9089177263e1024a0f253949993d95bdfba97d923fc0b111a22", 225 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 226 | "DockerfileCommands": [ 227 | "FROM docker.io/library/python:3-bullseye as builder2", 228 | "RUN echo \"builder2Foo\" \u003e /builder2Foo.txt", 229 | "EXPOSE 5000/tcp", 230 | "EXPOSE 5000/udp", 231 | "ENV PYTHON_ENV_1=\"python_env_val_1\"", 232 | "RUN echo \"builder2Bar\" \u003e /builder2Bar.txt", 233 | "COPY --from=builder2 /builder2Foo.txt /builder2Foo.txt" 234 | ], 235 | "BaseImage": "docker.io/library/python:3-bullseye", 236 | "AttributedEntity": { 237 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 238 | } 239 | }, 240 | { 241 | "LayerDigest": "sha256:1fa6c8ba07a43357be8a6b0ab93fe7240256c6944d8dc7ff6d56460a902345e5", 242 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 243 | "DockerfileCommands": [ 244 | "FROM docker.io/library/python:3-bullseye as builder2", 245 | "RUN echo \"builder2Foo\" \u003e /builder2Foo.txt", 246 | "EXPOSE 5000/tcp", 247 | "EXPOSE 5000/udp", 248 | "ENV PYTHON_ENV_1=\"python_env_val_1\"", 249 | "RUN echo \"builder2Bar\" \u003e /builder2Bar.txt", 250 | "COPY --from=builder2 /builder2Bar.txt /builder2Bar.txt" 251 | ], 252 | "BaseImage": "docker.io/library/python:3-bullseye", 253 | "AttributedEntity": { 254 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 255 | } 256 | }, 257 | { 258 | "LayerDigest": "sha256:c9fa26122280d003b9c895361c2e2902919c448b4530d264d0cc29a0db360d2f", 259 | "DockerfileLayerCreationType": "ADD-CommandLayer", 260 | "DockerfileCommands": [ 261 | "ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz" 262 | ], 263 | "BaseImage": "", 264 | "AttributedEntity": { 265 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 266 | } 267 | }, 268 | { 269 | "LayerDigest": "sha256:2f49cbff975702d5943ddd3782cd5ff2afc56566620d39755477073977a48a98", 270 | "DockerfileLayerCreationType": "RUN-CommandLayer", 271 | "DockerfileCommands": [ 272 | "RUN echo \"goodbye\" \u003e /goodbye.txt" 273 | ], 274 | "BaseImage": "", 275 | "AttributedEntity": { 276 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 277 | } 278 | } 279 | ] 280 | -------------------------------------------------------------------------------- /examples/scratch-base-multistage/oci-image-manifest-layer-history.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "LayerDescriptor": { 4 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 5 | "digest": "sha256:7942f3be722fa3927b29ccc51521f0f0d9b0b8979fc4148d3d94f05acc0bdf44", 6 | "size": 1100327 7 | }, 8 | "LayerCreationParameters": { 9 | "DockerfileLayerCreationType": "ADD-CommandLayer", 10 | "DockerfileCommands": [ 11 | { 12 | "Cmd": "ADD", 13 | "SubCmd": "", 14 | "Json": false, 15 | "Original": "ADD https://github.com/kubernetes/client-go/archive/master.tar.gz /kubernetes/client-go.tar.gz", 16 | "StartLine": 32, 17 | "EndLine": 32, 18 | "Flags": [], 19 | "Value": [ 20 | "https://github.com/kubernetes/client-go/archive/master.tar.gz", 21 | "/kubernetes/client-go.tar.gz" 22 | ] 23 | } 24 | ], 25 | "BaseImage": "" 26 | }, 27 | "AttributedEntity": { 28 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 29 | } 30 | }, 31 | { 32 | "LayerDescriptor": { 33 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 34 | "digest": "sha256:f0007634565752c57366439569258a233a2e5a8c209dd29d9df9d7daaf161c2e", 35 | "size": 115 36 | }, 37 | "LayerCreationParameters": { 38 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 39 | "DockerfileCommands": [ 40 | { 41 | "Cmd": "FROM", 42 | "SubCmd": "", 43 | "Json": false, 44 | "Original": "FROM docker.io/library/node:18-bullseye", 45 | "StartLine": 4, 46 | "EndLine": 4, 47 | "Flags": [], 48 | "Value": [ 49 | "docker.io/library/node:18-bullseye" 50 | ] 51 | }, 52 | { 53 | "Cmd": "RUN", 54 | "SubCmd": "", 55 | "Json": false, 56 | "Original": "RUN echo \"builder1Foo\" \u003e /builder1Foo.txt", 57 | "StartLine": 6, 58 | "EndLine": 6, 59 | "Flags": [], 60 | "Value": [ 61 | "echo \"builder1Foo\" \u003e /builder1Foo.txt" 62 | ] 63 | }, 64 | { 65 | "Cmd": "EXPOSE", 66 | "SubCmd": "", 67 | "Json": false, 68 | "Original": "EXPOSE 8080/tcp", 69 | "StartLine": 8, 70 | "EndLine": 8, 71 | "Flags": [], 72 | "Value": [ 73 | "8080/tcp" 74 | ] 75 | }, 76 | { 77 | "Cmd": "EXPOSE", 78 | "SubCmd": "", 79 | "Json": false, 80 | "Original": "EXPOSE 8080/udp", 81 | "StartLine": 9, 82 | "EndLine": 9, 83 | "Flags": [], 84 | "Value": [ 85 | "8080/udp" 86 | ] 87 | }, 88 | { 89 | "Cmd": "ENV", 90 | "SubCmd": "", 91 | "Json": false, 92 | "Original": "ENV NODE_ENV_1=\"node_env_val_1\"", 93 | "StartLine": 10, 94 | "EndLine": 10, 95 | "Flags": [], 96 | "Value": [ 97 | "NODE_ENV_1", 98 | "\"node_env_val_1\"" 99 | ] 100 | }, 101 | { 102 | "Cmd": "RUN", 103 | "SubCmd": "", 104 | "Json": false, 105 | "Original": "RUN echo \"builder1Bar\" \u003e /builder1Bar.txt", 106 | "StartLine": 12, 107 | "EndLine": 12, 108 | "Flags": [], 109 | "Value": [ 110 | "echo \"builder1Bar\" \u003e /builder1Bar.txt" 111 | ] 112 | }, 113 | { 114 | "Cmd": "COPY", 115 | "SubCmd": "", 116 | "Json": false, 117 | "Original": "COPY --from=0 /builder1Foo.txt /builder1Foo.txt", 118 | "StartLine": 39, 119 | "EndLine": 39, 120 | "Flags": [ 121 | "--from=0" 122 | ], 123 | "Value": [ 124 | "/builder1Foo.txt", 125 | "/builder1Foo.txt" 126 | ] 127 | } 128 | ], 129 | "BaseImage": "docker.io/library/node:18-bullseye" 130 | }, 131 | "AttributedEntity": { 132 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 133 | } 134 | }, 135 | { 136 | "LayerDescriptor": { 137 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 138 | "digest": "sha256:718e9aa42f6902fdde956e8435f0f34857708fce6ef461a197ea2f22bf19e3f0", 139 | "size": 115 140 | }, 141 | "LayerCreationParameters": { 142 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 143 | "DockerfileCommands": [ 144 | { 145 | "Cmd": "FROM", 146 | "SubCmd": "", 147 | "Json": false, 148 | "Original": "FROM docker.io/library/node:18-bullseye", 149 | "StartLine": 4, 150 | "EndLine": 4, 151 | "Flags": [], 152 | "Value": [ 153 | "docker.io/library/node:18-bullseye" 154 | ] 155 | }, 156 | { 157 | "Cmd": "RUN", 158 | "SubCmd": "", 159 | "Json": false, 160 | "Original": "RUN echo \"builder1Foo\" \u003e /builder1Foo.txt", 161 | "StartLine": 6, 162 | "EndLine": 6, 163 | "Flags": [], 164 | "Value": [ 165 | "echo \"builder1Foo\" \u003e /builder1Foo.txt" 166 | ] 167 | }, 168 | { 169 | "Cmd": "EXPOSE", 170 | "SubCmd": "", 171 | "Json": false, 172 | "Original": "EXPOSE 8080/tcp", 173 | "StartLine": 8, 174 | "EndLine": 8, 175 | "Flags": [], 176 | "Value": [ 177 | "8080/tcp" 178 | ] 179 | }, 180 | { 181 | "Cmd": "EXPOSE", 182 | "SubCmd": "", 183 | "Json": false, 184 | "Original": "EXPOSE 8080/udp", 185 | "StartLine": 9, 186 | "EndLine": 9, 187 | "Flags": [], 188 | "Value": [ 189 | "8080/udp" 190 | ] 191 | }, 192 | { 193 | "Cmd": "ENV", 194 | "SubCmd": "", 195 | "Json": false, 196 | "Original": "ENV NODE_ENV_1=\"node_env_val_1\"", 197 | "StartLine": 10, 198 | "EndLine": 10, 199 | "Flags": [], 200 | "Value": [ 201 | "NODE_ENV_1", 202 | "\"node_env_val_1\"" 203 | ] 204 | }, 205 | { 206 | "Cmd": "RUN", 207 | "SubCmd": "", 208 | "Json": false, 209 | "Original": "RUN echo \"builder1Bar\" \u003e /builder1Bar.txt", 210 | "StartLine": 12, 211 | "EndLine": 12, 212 | "Flags": [], 213 | "Value": [ 214 | "echo \"builder1Bar\" \u003e /builder1Bar.txt" 215 | ] 216 | }, 217 | { 218 | "Cmd": "COPY", 219 | "SubCmd": "", 220 | "Json": false, 221 | "Original": "COPY --from=0 /builder1Bar.txt /builder1Bar.txt", 222 | "StartLine": 40, 223 | "EndLine": 40, 224 | "Flags": [ 225 | "--from=0" 226 | ], 227 | "Value": [ 228 | "/builder1Bar.txt", 229 | "/builder1Bar.txt" 230 | ] 231 | } 232 | ], 233 | "BaseImage": "docker.io/library/node:18-bullseye" 234 | }, 235 | "AttributedEntity": { 236 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 237 | } 238 | }, 239 | { 240 | "LayerDescriptor": { 241 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 242 | "digest": "sha256:127c4f8180baccafd36c1ead43d6fd1cc5859f650f5d6867809e39b5d76d11ae", 243 | "size": 2727414 244 | }, 245 | "LayerCreationParameters": { 246 | "DockerfileLayerCreationType": "ADD-CommandLayer", 247 | "DockerfileCommands": [ 248 | { 249 | "Cmd": "ADD", 250 | "SubCmd": "", 251 | "Json": false, 252 | "Original": "ADD https://github.com/kubernetes/kubectl/archive/master.tar.gz /kubernetes/kubectl.tar.gz", 253 | "StartLine": 41, 254 | "EndLine": 41, 255 | "Flags": [], 256 | "Value": [ 257 | "https://github.com/kubernetes/kubectl/archive/master.tar.gz", 258 | "/kubernetes/kubectl.tar.gz" 259 | ] 260 | } 261 | ], 262 | "BaseImage": "" 263 | }, 264 | "AttributedEntity": { 265 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 266 | } 267 | }, 268 | { 269 | "LayerDescriptor": { 270 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 271 | "digest": "sha256:50b974a802e3f9089177263e1024a0f253949993d95bdfba97d923fc0b111a22", 272 | "size": 115 273 | }, 274 | "LayerCreationParameters": { 275 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 276 | "DockerfileCommands": [ 277 | { 278 | "Cmd": "FROM", 279 | "SubCmd": "", 280 | "Json": false, 281 | "Original": "FROM docker.io/library/python:3-bullseye as builder2", 282 | "StartLine": 17, 283 | "EndLine": 17, 284 | "Flags": [], 285 | "Value": [ 286 | "docker.io/library/python:3-bullseye", 287 | "as", 288 | "builder2" 289 | ] 290 | }, 291 | { 292 | "Cmd": "RUN", 293 | "SubCmd": "", 294 | "Json": false, 295 | "Original": "RUN echo \"builder2Foo\" \u003e /builder2Foo.txt", 296 | "StartLine": 19, 297 | "EndLine": 19, 298 | "Flags": [], 299 | "Value": [ 300 | "echo \"builder2Foo\" \u003e /builder2Foo.txt" 301 | ] 302 | }, 303 | { 304 | "Cmd": "EXPOSE", 305 | "SubCmd": "", 306 | "Json": false, 307 | "Original": "EXPOSE 5000/tcp", 308 | "StartLine": 21, 309 | "EndLine": 21, 310 | "Flags": [], 311 | "Value": [ 312 | "5000/tcp" 313 | ] 314 | }, 315 | { 316 | "Cmd": "EXPOSE", 317 | "SubCmd": "", 318 | "Json": false, 319 | "Original": "EXPOSE 5000/udp", 320 | "StartLine": 22, 321 | "EndLine": 22, 322 | "Flags": [], 323 | "Value": [ 324 | "5000/udp" 325 | ] 326 | }, 327 | { 328 | "Cmd": "ENV", 329 | "SubCmd": "", 330 | "Json": false, 331 | "Original": "ENV PYTHON_ENV_1=\"python_env_val_1\"", 332 | "StartLine": 23, 333 | "EndLine": 23, 334 | "Flags": [], 335 | "Value": [ 336 | "PYTHON_ENV_1", 337 | "\"python_env_val_1\"" 338 | ] 339 | }, 340 | { 341 | "Cmd": "RUN", 342 | "SubCmd": "", 343 | "Json": false, 344 | "Original": "RUN echo \"builder2Bar\" \u003e /builder2Bar.txt", 345 | "StartLine": 25, 346 | "EndLine": 25, 347 | "Flags": [], 348 | "Value": [ 349 | "echo \"builder2Bar\" \u003e /builder2Bar.txt" 350 | ] 351 | }, 352 | { 353 | "Cmd": "COPY", 354 | "SubCmd": "", 355 | "Json": false, 356 | "Original": "COPY --from=builder2 /builder2Foo.txt /builder2Foo.txt", 357 | "StartLine": 47, 358 | "EndLine": 47, 359 | "Flags": [ 360 | "--from=builder2" 361 | ], 362 | "Value": [ 363 | "/builder2Foo.txt", 364 | "/builder2Foo.txt" 365 | ] 366 | } 367 | ], 368 | "BaseImage": "docker.io/library/python:3-bullseye" 369 | }, 370 | "AttributedEntity": { 371 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 372 | } 373 | }, 374 | { 375 | "LayerDescriptor": { 376 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 377 | "digest": "sha256:1fa6c8ba07a43357be8a6b0ab93fe7240256c6944d8dc7ff6d56460a902345e5", 378 | "size": 115 379 | }, 380 | "LayerCreationParameters": { 381 | "DockerfileLayerCreationType": "COPY-FromMultistageBuildStageLayer", 382 | "DockerfileCommands": [ 383 | { 384 | "Cmd": "FROM", 385 | "SubCmd": "", 386 | "Json": false, 387 | "Original": "FROM docker.io/library/python:3-bullseye as builder2", 388 | "StartLine": 17, 389 | "EndLine": 17, 390 | "Flags": [], 391 | "Value": [ 392 | "docker.io/library/python:3-bullseye", 393 | "as", 394 | "builder2" 395 | ] 396 | }, 397 | { 398 | "Cmd": "RUN", 399 | "SubCmd": "", 400 | "Json": false, 401 | "Original": "RUN echo \"builder2Foo\" \u003e /builder2Foo.txt", 402 | "StartLine": 19, 403 | "EndLine": 19, 404 | "Flags": [], 405 | "Value": [ 406 | "echo \"builder2Foo\" \u003e /builder2Foo.txt" 407 | ] 408 | }, 409 | { 410 | "Cmd": "EXPOSE", 411 | "SubCmd": "", 412 | "Json": false, 413 | "Original": "EXPOSE 5000/tcp", 414 | "StartLine": 21, 415 | "EndLine": 21, 416 | "Flags": [], 417 | "Value": [ 418 | "5000/tcp" 419 | ] 420 | }, 421 | { 422 | "Cmd": "EXPOSE", 423 | "SubCmd": "", 424 | "Json": false, 425 | "Original": "EXPOSE 5000/udp", 426 | "StartLine": 22, 427 | "EndLine": 22, 428 | "Flags": [], 429 | "Value": [ 430 | "5000/udp" 431 | ] 432 | }, 433 | { 434 | "Cmd": "ENV", 435 | "SubCmd": "", 436 | "Json": false, 437 | "Original": "ENV PYTHON_ENV_1=\"python_env_val_1\"", 438 | "StartLine": 23, 439 | "EndLine": 23, 440 | "Flags": [], 441 | "Value": [ 442 | "PYTHON_ENV_1", 443 | "\"python_env_val_1\"" 444 | ] 445 | }, 446 | { 447 | "Cmd": "RUN", 448 | "SubCmd": "", 449 | "Json": false, 450 | "Original": "RUN echo \"builder2Bar\" \u003e /builder2Bar.txt", 451 | "StartLine": 25, 452 | "EndLine": 25, 453 | "Flags": [], 454 | "Value": [ 455 | "echo \"builder2Bar\" \u003e /builder2Bar.txt" 456 | ] 457 | }, 458 | { 459 | "Cmd": "COPY", 460 | "SubCmd": "", 461 | "Json": false, 462 | "Original": "COPY --from=builder2 /builder2Bar.txt /builder2Bar.txt", 463 | "StartLine": 48, 464 | "EndLine": 48, 465 | "Flags": [ 466 | "--from=builder2" 467 | ], 468 | "Value": [ 469 | "/builder2Bar.txt", 470 | "/builder2Bar.txt" 471 | ] 472 | } 473 | ], 474 | "BaseImage": "docker.io/library/python:3-bullseye" 475 | }, 476 | "AttributedEntity": { 477 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 478 | } 479 | }, 480 | { 481 | "LayerDescriptor": { 482 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 483 | "digest": "sha256:336f60ca2fdf8014edca08c0461e7491080d74554a3830e7d9167f0c2ccfb1f4", 484 | "size": 22473758 485 | }, 486 | "LayerCreationParameters": { 487 | "DockerfileLayerCreationType": "ADD-CommandLayer", 488 | "DockerfileCommands": [ 489 | { 490 | "Cmd": "ADD", 491 | "SubCmd": "", 492 | "Json": false, 493 | "Original": "ADD https://github.com/kubernetes/dashboard/archive/master.tar.gz /kubernetes/dashboard.tar.gz", 494 | "StartLine": 49, 495 | "EndLine": 49, 496 | "Flags": [], 497 | "Value": [ 498 | "https://github.com/kubernetes/dashboard/archive/master.tar.gz", 499 | "/kubernetes/dashboard.tar.gz" 500 | ] 501 | } 502 | ], 503 | "BaseImage": "" 504 | }, 505 | "AttributedEntity": { 506 | "responsible_entity_id": "ID of the responsible entity that introduced non-base image layers. i.e. Entity ID of the Dockerfile Author. This denotes responsible entity for the new layers added on top of base image layers." 507 | } 508 | } 509 | ] 510 | --------------------------------------------------------------------------------