├── __tests__ ├── .fixtures │ ├── secret.txt │ ├── sigstore │ │ ├── single │ │ │ └── hello.txt │ │ └── multi │ │ │ ├── linux_amd64 │ │ │ └── hello.txt │ │ │ └── linux_arm64 │ │ │ └── hello.txt │ ├── buildkitd.toml │ ├── buildx-refs │ │ ├── default │ │ │ └── default │ │ │ │ ├── a5s9rlg9cnqq98oa1a1h5sz6t │ │ │ │ ├── 49p5r8und2konke5pmlyzqp3n │ │ │ │ ├── o1ctbgdb1mwekkxocc6filxde │ │ │ │ ├── qxu22kx1mrydcjkbl0b0l6es8 │ │ │ │ ├── w38vcd5fo5cfvfyig77qjec0v │ │ │ │ ├── 36dix0eiv9evr61vrwzn32w7q │ │ │ │ ├── aav2ix4nw5eky66fw045dkylr │ │ │ │ ├── dfsz8r57a98zf789pmlyzqp3n │ │ │ │ ├── a8zqzhhv5yiazm396jobsgdw2 │ │ │ │ ├── ij71n3ubmhck85d03zdvye5nr │ │ │ │ ├── qvb2qy61mspqdyzf8whvjy0x1 │ │ │ │ ├── 84p2qpgacnqq98oa1a1h5sz6t │ │ │ │ ├── 7pnnqpgacnqq98oa1a1h5sz6t │ │ │ │ └── vzxn0jxr44khtq7hc8drtzwjv │ │ ├── foo │ │ │ └── foo0 │ │ │ │ ├── 21hqcxmgxyhugz2m24tmi7xco │ │ │ │ ├── 5nm14argzndbc4hw1jx6v9d5k │ │ │ │ └── 7dblgs0dsjm22ti6p53sih6b7 │ │ └── __group__ │ │ │ └── 1fugf958r4peyg86h6scim5t5 │ ├── oci-archive │ │ ├── hello-oci-multiplatform-gzip.tar │ │ ├── moby~buildkit~LWDOW6.dockerbuild │ │ ├── crazy-max~docker-alpine-s6~II9A63.dockerbuild │ │ ├── docker~test-docker-action~COIO50.dockerbuild │ │ ├── docker~test-docker-action~SNHBPN+3.dockerbuild │ │ └── docker~test-docker-action~TYO4JJ+15.dockerbuild │ ├── docker-config-auths.json │ ├── docker-config-proxies.json │ ├── imagetools-03.json │ ├── inspect4.txt │ ├── bake-test-docker-action-remote-private.json │ ├── bake-02-build.json │ ├── inspect6.txt │ ├── inspect1.txt │ ├── inspect9.txt │ ├── inspect2.txt │ ├── inspect3.txt │ ├── inspect5.txt │ ├── bake-01-overrides.json │ ├── hello-err.Dockerfile │ ├── inspect7.txt │ ├── hello.Dockerfile │ ├── lint-other.Dockerfile │ ├── bake-buildx-0.10.4-binaries-cross.json │ ├── lint.hcl │ ├── bake-02.hcl │ ├── dockerhub-repoinfo.json │ ├── lint.Dockerfile │ ├── bake-03.hcl │ ├── hello-bake.hcl │ ├── bake-01-validate.json │ ├── bake-03-default.json │ ├── inspect8.txt │ ├── runtimeToken.txt │ ├── inspect11.txt │ ├── inspect12.txt │ ├── imagetools-01.json │ ├── inspect10.txt │ └── imagetools-05.json ├── testResultsProcessor.js ├── undock │ ├── install.test.itg.ts │ ├── undock.test.itg.ts │ └── undock.test.ts ├── regclient │ └── install.test.itg.ts ├── exec.test.ts ├── buildx │ ├── install.test.itg.ts │ └── bake.test.itg.ts ├── compose │ ├── install.test.itg.ts │ └── compose.test.ts ├── oci │ └── oci.test.ts ├── cache.test.itg.ts ├── cosign │ ├── install.test.itg.ts │ └── cosign.test.ts ├── buildkit │ ├── buildkit.test.ts │ └── config.test.ts ├── docker │ └── docker.test.itg.ts ├── context.test.ts └── sigstore │ └── sigstore.test.itg.ts ├── codecov.yml ├── .gitattributes ├── .prettierignore ├── .dockerignore ├── .prettierrc.json ├── .editorconfig ├── .github ├── workflows │ ├── pr-assign-author.yml │ ├── build.yml │ ├── validate.yml │ ├── codeql.yml │ ├── publish.yml │ ├── virtual-env.yml │ ├── buildx-releases-json.yml │ ├── cosign-releases-json.yml │ ├── undock-releases-json.yml │ ├── compose-releases-json.yml │ ├── regclient-releases-json.yml │ ├── buildx-lab-releases-json.yml │ ├── docker-releases-json.yml │ └── compose-lab-releases-json.yml ├── dependabot.yml ├── SUPPORT.md └── CONTRIBUTING.md ├── .yarnrc.yml ├── tsconfig.json ├── src ├── types │ ├── oci │ │ ├── digest.ts │ │ ├── versioned.ts │ │ ├── layout.ts │ │ ├── index.ts │ │ ├── manifest.ts │ │ ├── mediatype.ts │ │ ├── oci.ts │ │ ├── descriptor.ts │ │ └── config.ts │ ├── git.ts │ ├── buildx │ │ ├── build.ts │ │ ├── imagetools.ts │ │ ├── buildx.ts │ │ ├── builder.ts │ │ ├── bake.ts │ │ └── history.ts │ ├── buildkit │ │ ├── buildkit.ts │ │ ├── git.ts │ │ ├── rpc.ts │ │ ├── client.ts │ │ ├── ops.ts │ │ └── control.ts │ ├── cosign │ │ └── cosign.ts │ ├── undock │ │ └── undock.ts │ ├── regclient │ │ └── regclient.ts │ ├── compose │ │ └── compose.ts │ ├── docker │ │ ├── mediatype.ts │ │ └── docker.ts │ ├── intoto │ │ ├── intoto.ts │ │ └── slsa_provenance │ │ │ └── v0.2 │ │ │ └── provenance.ts │ ├── github.ts │ ├── sigstore │ │ └── sigstore.ts │ └── dockerhub.ts ├── exec.ts ├── buildkit │ ├── config.ts │ └── buildkit.ts ├── index.ts ├── context.ts ├── cosign │ └── dockerfile.ts ├── toolkit.ts ├── compose │ └── compose.ts └── buildx │ └── imagetools.ts ├── .gitignore ├── jest.config.itg.js ├── jest.config.js ├── hack └── dockerfiles │ └── license.Dockerfile ├── eslint.config.js ├── README.md ├── docker-bake.hcl ├── package.json └── dev.Dockerfile /__tests__/.fixtures/secret.txt: -------------------------------------------------------------------------------- 1 | bar -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | github_checks: 3 | annotations: false 4 | -------------------------------------------------------------------------------- /__tests__/.fixtures/sigstore/single/hello.txt: -------------------------------------------------------------------------------- 1 | Hello, World! This is linux/amd64 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/sigstore/multi/linux_amd64/hello.txt: -------------------------------------------------------------------------------- 1 | Hello, World! This is linux/amd64 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/sigstore/multi/linux_arm64/hello.txt: -------------------------------------------------------------------------------- 1 | Hello, World! This is linux/arm64 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildkitd.toml: -------------------------------------------------------------------------------- 1 | debug = true 2 | [registry."docker.io"] 3 | mirrors = ["mirror.gcr.io"] 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /.yarn/releases/** binary 2 | /.yarn/plugins/** binary 3 | /__tests__/fixtures/oci-archive/** binary 4 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/a5s9rlg9cnqq98oa1a1h5sz6t: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazy/foo/bar/-","DockerfilePath":""} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/49p5r8und2konke5pmlyzqp3n: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":""} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/o1ctbgdb1mwekkxocc6filxde: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":""} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/qxu22kx1mrydcjkbl0b0l6es8: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":""} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/w38vcd5fo5cfvfyig77qjec0v: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazy/hello","DockerfilePath":"/home/crazy/hello/-"} 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Dependency directories 2 | /node_modules/** 3 | /jspm_packages/** 4 | 5 | # yarn v2 6 | /.yarn/** 7 | 8 | # build 9 | /lib/** 10 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/36dix0eiv9evr61vrwzn32w7q: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazymax/github/docker/docker-alpine-s6","DockerfilePath":""} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/aav2ix4nw5eky66fw045dkylr: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazy/foo/bar/https:/github.com/docker/buildx.git","DockerfilePath":""} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/oci-archive/hello-oci-multiplatform-gzip.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker/actions-toolkit/main/__tests__/.fixtures/oci-archive/hello-oci-multiplatform-gzip.tar -------------------------------------------------------------------------------- /__tests__/.fixtures/oci-archive/moby~buildkit~LWDOW6.dockerbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker/actions-toolkit/main/__tests__/.fixtures/oci-archive/moby~buildkit~LWDOW6.dockerbuild -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/dfsz8r57a98zf789pmlyzqp3n: -------------------------------------------------------------------------------- 1 | {"LocalPath":"https://github.com/docker/actions-toolkit.git#:__tests__/fixtures","DockerfilePath":"hello.Dockerfile"} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/docker-config-auths.json: -------------------------------------------------------------------------------- 1 | { 2 | "auths": { 3 | "https://index.docker.io/v1/": { 4 | "auth": "am9lam9lOmhlbGxv", 5 | "email": "user@example.com" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/a8zqzhhv5yiazm396jobsgdw2: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":"/home/crazymax/github/docker_org/buildx/Dockerfile"} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/ij71n3ubmhck85d03zdvye5nr: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":"/home/crazymax/github/docker_org/buildx/Dockerfile"} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/qvb2qy61mspqdyzf8whvjy0x1: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazymax/github/docker_org/buildx","DockerfilePath":"/home/crazymax/github/docker_org/buildx/Dockerfile"} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/docker-config-proxies.json: -------------------------------------------------------------------------------- 1 | { 2 | "proxies": { 3 | "default": { 4 | "httpProxy": "http://127.0.0.1:3128", 5 | "httpsProxy": "http://127.0.0.1:3128" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/.fixtures/oci-archive/crazy-max~docker-alpine-s6~II9A63.dockerbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker/actions-toolkit/main/__tests__/.fixtures/oci-archive/crazy-max~docker-alpine-s6~II9A63.dockerbuild -------------------------------------------------------------------------------- /__tests__/.fixtures/oci-archive/docker~test-docker-action~COIO50.dockerbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker/actions-toolkit/main/__tests__/.fixtures/oci-archive/docker~test-docker-action~COIO50.dockerbuild -------------------------------------------------------------------------------- /__tests__/.fixtures/oci-archive/docker~test-docker-action~SNHBPN+3.dockerbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker/actions-toolkit/main/__tests__/.fixtures/oci-archive/docker~test-docker-action~SNHBPN+3.dockerbuild -------------------------------------------------------------------------------- /__tests__/.fixtures/oci-archive/docker~test-docker-action~TYO4JJ+15.dockerbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker/actions-toolkit/main/__tests__/.fixtures/oci-archive/docker~test-docker-action~TYO4JJ+15.dockerbuild -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/84p2qpgacnqq98oa1a1h5sz6t: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazy/foo/bar/https:/github.com/docker/actions-toolkit.git#:__tests__/fixtures","DockerfilePath":"/home/crazy/foo/bar/-"} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/imagetools-03.json: -------------------------------------------------------------------------------- 1 | { 2 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 3 | "digest": "sha256:dccc69dd895968c4f21aa9e43e715f25f0cedfce4b17f1014c88c307928e22fc", 4 | "size": 1599 5 | } 6 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | 3 | # Dependency directories 4 | node_modules/ 5 | jspm_packages/ 6 | 7 | # yarn v2 8 | .yarn/cache 9 | .yarn/unplugged 10 | .yarn/build-state.yml 11 | .yarn/install-state.gz 12 | .pnp.* 13 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/7pnnqpgacnqq98oa1a1h5sz6t: -------------------------------------------------------------------------------- 1 | {"LocalPath":"/home/crazy/foo/bar/https:/github.com/docker/actions-toolkit.git#:__tests__/fixtures","DockerfilePath":"/home/crazy/foo/bar/hello.Dockerfile"} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/foo/foo0/21hqcxmgxyhugz2m24tmi7xco: -------------------------------------------------------------------------------- 1 | {"Target":"default","LocalPath":"/home/crazymax/github/docker_org/compose/.dev/47231","DockerfilePath":"/home/crazymax/github/docker_org/compose/.dev/47231/bad/Dockerfile"} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/foo/foo0/5nm14argzndbc4hw1jx6v9d5k: -------------------------------------------------------------------------------- 1 | {"Target":"default","LocalPath":"/home/crazymax/github/docker_org/compose/.dev/47231","DockerfilePath":"/home/crazymax/github/docker_org/compose/.dev/47231/bad/Dockerfile"} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/foo/foo0/7dblgs0dsjm22ti6p53sih6b7: -------------------------------------------------------------------------------- 1 | {"Target":"default","LocalPath":"/home/crazymax/github/docker_org/compose/.dev/47231","DockerfilePath":"/home/crazymax/github/docker_org/compose/.dev/47231/bad/Dockerfile"} 2 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/default/default/vzxn0jxr44khtq7hc8drtzwjv: -------------------------------------------------------------------------------- 1 | {"Target":"dev","LocalPath":"/home/crazymax/github/docker_org/docker","DockerfilePath":"/home/crazymax/github/docker_org/docker/Dockerfile","GroupRef":"1fugf958r4peyg86h6scim5t5"} 2 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 240, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "none", 8 | "bracketSpacing": false, 9 | "arrowParens": "avoid", 10 | "parser": "typescript" 11 | } 12 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect4.txt: -------------------------------------------------------------------------------- 1 | Name: default 2 | Driver: docker 3 | 4 | Nodes: 5 | Name: default 6 | Endpoint: default 7 | Status: running 8 | Buildkit: 20.10.17 9 | Platforms: linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6 10 | -------------------------------------------------------------------------------- /__tests__/.fixtures/bake-test-docker-action-remote-private.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": { 3 | "default": { 4 | "context": "https://github.com/docker/test-docker-action.git#remote-private", 5 | "dockerfile": "Dockerfile", 6 | "tags": [ 7 | "foo" 8 | ] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs. 2 | # More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.github/workflows/pr-assign-author.yml: -------------------------------------------------------------------------------- 1 | name: pr-assign-author 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | pull_request_target: 8 | types: 9 | - opened 10 | - reopened 11 | 12 | jobs: 13 | run: 14 | uses: crazy-max/.github/.github/workflows/pr-assign-author.yml@1b673f36fad86812f538c1df9794904038a23cbf 15 | permissions: 16 | contents: read 17 | pull-requests: write 18 | -------------------------------------------------------------------------------- /__tests__/.fixtures/bake-02-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": { 3 | "default": { 4 | "targets": [ 5 | "build" 6 | ] 7 | } 8 | }, 9 | "target": { 10 | "build": { 11 | "context": ".", 12 | "dockerfile": "Dockerfile", 13 | "args": { 14 | "BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1", 15 | "GO_VERSION": "1.20" 16 | }, 17 | "target": "build" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect6.txt: -------------------------------------------------------------------------------- 1 | Name: builder-17cfff01-48d9-4c3d-9332-9992e308a510 2 | Driver: docker-container 3 | 4 | Nodes: 5 | Name: builder-17cfff01-48d9-4c3d-9332-9992e308a5100 6 | Endpoint: unix:///var/run/docker.sock 7 | Status: running 8 | Flags: --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host 9 | Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386 10 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | # https://yarnpkg.com/configuration/yarnrc 2 | 3 | compressionLevel: mixed 4 | enableGlobalCache: false 5 | enableHardenedMode: true 6 | 7 | logFilters: 8 | - code: YN0013 9 | level: discard 10 | - code: YN0019 11 | level: discard 12 | - code: YN0076 13 | level: discard 14 | - code: YN0086 15 | level: discard 16 | 17 | nodeLinker: node-modules 18 | 19 | npmAuthToken: "${NODE_AUTH_TOKEN:-fallback}" 20 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect1.txt: -------------------------------------------------------------------------------- 1 | Name: builder-5cb467f7-0940-47e1-b94b-d51f54054d62 2 | Driver: docker-container 3 | 4 | Nodes: 5 | Name: builder-5cb467f7-0940-47e1-b94b-d51f54054d620 6 | Endpoint: unix:///var/run/docker.sock 7 | Status: running 8 | Flags: --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host 9 | Buildkit: v0.10.4 10 | Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/arm64, linux/riscv64, linux/386, linux/arm/v7, linux/arm/v6 11 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect9.txt: -------------------------------------------------------------------------------- 1 | Name: default 2 | Driver: docker 3 | Last Activity: 2023-06-13 18:13:43 +0000 UTC 4 | 5 | Nodes: 6 | Name: default 7 | Endpoint: default 8 | Status: running 9 | Buildkit: v0.11.7-0.20230525183624-798ad6b0ce9f 10 | Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6 11 | GC Policy rule#0: 12 | All: true 13 | Filters: 14 | Keep Bytes: 100GiB 15 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect2.txt: -------------------------------------------------------------------------------- 1 | Name: builder-5f449644-ff29-48af-8344-abb0292d0673 2 | Driver: docker-container 3 | 4 | Nodes: 5 | Name: builder-5f449644-ff29-48af-8344-abb0292d06730 6 | Endpoint: unix:///var/run/docker.sock 7 | Driver Options: image="moby/buildkit:latest" 8 | Status: running 9 | Flags: --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host 10 | Buildkit: v0.10.4 11 | Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/386 12 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect3.txt: -------------------------------------------------------------------------------- 1 | Name: builder-9929e463-7954-4dc3-89cd-514cca29ff80 2 | Driver: docker-container 3 | 4 | Nodes: 5 | Name: builder-9929e463-7954-4dc3-89cd-514cca29ff800 6 | Endpoint: unix:///var/run/docker.sock 7 | Driver Options: image="moby/buildkit:master" network="host" 8 | Status: running 9 | Flags: --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host 10 | Buildkit: 3fab389 11 | Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/386 12 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect5.txt: -------------------------------------------------------------------------------- 1 | Name: remote-builder 2 | Driver: remote 3 | 4 | Nodes: 5 | Name: aws_graviton2 6 | Endpoint: tcp://1.23.45.67:1234 7 | Driver Options: cert="/home/user/.certs/aws_graviton2/cert.pem" key="/home/user/.certs/aws_graviton2/key.pem" cacert="/home/user/.certs/aws_graviton2/ca.pem" 8 | Status: running 9 | Platforms: darwin/arm64*, linux/arm64*, linux/arm/v5*, linux/arm/v6*, linux/arm/v7*, windows/arm64*, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/mips64le, linux/mips64 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "target": "es6", 5 | "module": "commonjs", 6 | "strict": true, 7 | "declaration": true, 8 | "sourceMap": true, 9 | "newLine": "lf", 10 | "outDir": "./lib", 11 | "rootDir": "./src", 12 | "forceConsistentCasingInFileNames": true, 13 | "noImplicitAny": false, 14 | "resolveJsonModule": true, 15 | "useUnknownInCatchVariables": false, 16 | }, 17 | "exclude": [ 18 | "./__mocks__/**/*", 19 | "./__tests__/**/*", 20 | "./lib/**/*", 21 | "node_modules" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /__tests__/.fixtures/buildx-refs/__group__/1fugf958r4peyg86h6scim5t5: -------------------------------------------------------------------------------- 1 | {"Definition":"eyJncm91cCI6eyJkZWZhdWx0Ijp7InRhcmdldHMiOlsiZGV2Il19fSwidGFyZ2V0Ijp7ImRldiI6eyJjb250ZXh0IjoiLiIsImRvY2tlcmZpbGUiOiJEb2NrZXJmaWxlIiwiYXJncyI6eyJCVUlMREtJVF9DT05URVhUX0tFRVBfR0lUX0RJUiI6IjEiLCJERUZBVUxUX1BST0RVQ1RfTElDRU5TRSI6IiIsIkRPQ0tFUl9CVUlMRFRBR1MiOiIiLCJET0NLRVJfREVCVUciOiIiLCJET0NLRVJfTERGTEFHUyI6IiIsIkRPQ0tFUl9TVEFUSUMiOiIxIiwiUEFDS0FHRVJfTkFNRSI6IiIsIlBMQVRGT1JNIjoiIiwiUFJPRFVDVCI6IiIsIlNZU1RFTUQiOiJmYWxzZSIsIlZFUlNJT04iOiIifSwidGFncyI6WyJkb2NrZXItZGV2Il0sInRhcmdldCI6ImRldiIsIm91dHB1dCI6WyJ0eXBlPWRvY2tlciJdfX19","Targets":["dev"],"Refs":["vzxn0jxr44khtq7hc8drtzwjv"]} -------------------------------------------------------------------------------- /__tests__/.fixtures/bake-01-overrides.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": { 3 | "default": { 4 | "targets": [ 5 | "image" 6 | ] 7 | } 8 | }, 9 | "target": { 10 | "image": { 11 | "context": ".", 12 | "dockerfile": "Dockerfile", 13 | "args": { 14 | "BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1", 15 | "GO_VERSION": "1.20" 16 | }, 17 | "tags": [ 18 | "docker/buildx-bin:local" 19 | ], 20 | "target": "binaries", 21 | "platforms": [ 22 | "linux/amd64" 23 | ], 24 | "output": [ 25 | { 26 | "type": "docker" 27 | } 28 | ] 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | branches: 10 | - 'main' 11 | pull_request: 12 | paths-ignore: 13 | - '.github/*-releases.json' 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | node_version: 22 | - 24 23 | - 20 24 | - 18 25 | steps: 26 | - 27 | name: Build 28 | uses: docker/bake-action@v6 29 | with: 30 | targets: build 31 | env: 32 | NODE_VERSION: ${{ matrix.node_version }} 33 | -------------------------------------------------------------------------------- /src/types/oci/digest.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export type Digest = string; 18 | -------------------------------------------------------------------------------- /src/types/oci/versioned.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export interface Versioned { 18 | schemaVersion: number; 19 | } 20 | -------------------------------------------------------------------------------- /__tests__/.fixtures/hello-err.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | # Copyright 2024 actions-toolkit authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | FROM busybox:latest 18 | ARGGG NAME=foo 19 | RUN echo "hello $NAME" 20 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect7.txt: -------------------------------------------------------------------------------- 1 | Name: builder2 2 | Driver: docker-container 3 | Last Activity: 2023-01-16 09:45:23 +0000 UTC 4 | 5 | Nodes: 6 | Name: builder20 7 | Endpoint: unix:///var/run/docker.sock 8 | Driver Options: env.BUILDKIT_STEP_LOG_MAX_SIZE="10485760" env.BUILDKIT_STEP_LOG_MAX_SPEED="10485760" env.JAEGER_TRACE="localhost:6831" image="moby/buildkit:latest" network="host" qemu.install="true" 9 | Status: running 10 | Flags: --debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host 11 | Buildkit: v0.11.0 12 | Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6 13 | -------------------------------------------------------------------------------- /src/types/git.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Context as GitHubContext} from '@actions/github/lib/context'; 18 | 19 | export type Context = GitHubContext; 20 | -------------------------------------------------------------------------------- /src/types/buildx/build.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export type BuildMetadata = { 18 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 19 | [key: string]: any; 20 | }; 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | open-pull-requests-limit: 20 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | labels: 9 | - "dependencies" 10 | - "bot" 11 | - package-ecosystem: "npm" 12 | open-pull-requests-limit: 20 13 | directory: "/" 14 | schedule: 15 | interval: "daily" 16 | versioning-strategy: "increase" 17 | allow: 18 | - dependency-type: "production" 19 | ignore: 20 | - # we want to match the same version as the one used by @actions/artifact 21 | # https://github.com/actions/toolkit/blob/ae38557bb0dba824cdda26ce787bd6b66cf07a83/packages/artifact/package.json#L46 22 | dependency-name: "@azure/storage-blob" 23 | labels: 24 | - "dependencies" 25 | - "bot" 26 | -------------------------------------------------------------------------------- /src/types/buildkit/buildkit.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/llbsolver/history.go#L672 18 | export const MEDIATYPE_STATUS_V0 = 'application/vnd.buildkit.status.v0'; 19 | -------------------------------------------------------------------------------- /src/types/cosign/cosign.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GitHubContentOpts} from '../github'; 18 | 19 | export interface DownloadVersion { 20 | version: string; 21 | downloadURL: string; 22 | contentOpts: GitHubContentOpts; 23 | } 24 | -------------------------------------------------------------------------------- /src/types/undock/undock.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GitHubContentOpts} from '../github'; 18 | 19 | export interface DownloadVersion { 20 | version: string; 21 | downloadURL: string; 22 | contentOpts: GitHubContentOpts; 23 | } 24 | -------------------------------------------------------------------------------- /__tests__/.fixtures/hello.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | # Copyright 2024 actions-toolkit authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | FROM busybox AS build 18 | ARG NAME=foo 19 | ARG TARGETPLATFORM 20 | RUN echo "Hello $NAME from $TARGETPLATFORM" > foo 21 | 22 | FROM scratch 23 | COPY --from=build /foo / 24 | -------------------------------------------------------------------------------- /src/types/regclient/regclient.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GitHubContentOpts} from '../github'; 18 | 19 | export interface DownloadVersion { 20 | version: string; 21 | downloadURL: string; 22 | contentOpts: GitHubContentOpts; 23 | } 24 | -------------------------------------------------------------------------------- /src/types/compose/compose.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GitHubContentOpts} from '../github'; 18 | 19 | export interface DownloadVersion { 20 | key: string; 21 | version: string; 22 | downloadURL: string; 23 | contentOpts: GitHubContentOpts; 24 | } 25 | -------------------------------------------------------------------------------- /__tests__/.fixtures/lint-other.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile-upstream:master 2 | 3 | # Copyright 2024 actions-toolkit authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | frOM busybox as base 18 | cOpy lint-other.Dockerfile . 19 | 20 | froM busybox aS notused 21 | COPY lint-other.Dockerfile . 22 | 23 | from scratch 24 | COPy --from=base \ 25 | /lint-other.Dockerfile \ 26 | / 27 | -------------------------------------------------------------------------------- /src/types/oci/layout.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export const IMAGE_LAYOUT_FILE_V1 = 'oci-layout'; 18 | 19 | export const IMAGE_LAYOUT_VERSION_V1 = '1.0.0'; 20 | 21 | export const IMAGE_INDEX_FILE_V1 = 'index.json'; 22 | 23 | export const IMAGE_BLOBS_DIR_V1 = 'blobs'; 24 | 25 | export interface ImageLayout { 26 | version: string; 27 | } 28 | -------------------------------------------------------------------------------- /__tests__/.fixtures/bake-buildx-0.10.4-binaries-cross.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": { 3 | "default": { 4 | "targets": [ 5 | "binaries-cross" 6 | ] 7 | } 8 | }, 9 | "target": { 10 | "binaries-cross": { 11 | "context": "https://github.com/docker/buildx.git#v0.10.4", 12 | "dockerfile": "Dockerfile", 13 | "args": { 14 | "BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1", 15 | "GO_VERSION": "1.19" 16 | }, 17 | "target": "binaries", 18 | "platforms": [ 19 | "darwin/amd64", 20 | "darwin/arm64", 21 | "linux/amd64", 22 | "linux/arm/v6", 23 | "linux/arm/v7", 24 | "linux/arm64", 25 | "linux/ppc64le", 26 | "linux/riscv64", 27 | "linux/s390x", 28 | "windows/amd64", 29 | "windows/arm64" 30 | ], 31 | "output": [ 32 | { 33 | "dest": "./bin/build", 34 | "type": "local" 35 | } 36 | ] 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/types/oci/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Versioned} from './versioned'; 18 | import {Descriptor} from './descriptor'; 19 | 20 | export interface Index extends Versioned { 21 | mediaType?: string; 22 | artifactType?: string; 23 | manifests: Descriptor[]; 24 | subject?: Descriptor; 25 | annotations?: Record; 26 | } 27 | -------------------------------------------------------------------------------- /__tests__/.fixtures/lint.hcl: -------------------------------------------------------------------------------- 1 | // Copyright 2024 actions-toolkit authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | group "default" { 16 | targets = ["lint", "lint-other", "lint-inline"] 17 | } 18 | target "lint" { 19 | dockerfile = "lint.Dockerfile" 20 | } 21 | target "lint-other" { 22 | dockerfile = "lint-other.Dockerfile" 23 | } 24 | target "lint-inline" { 25 | dockerfile-inline = "FRoM alpine\nENTRYPOINT [\"echo\", \"hello\"]" 26 | } 27 | -------------------------------------------------------------------------------- /src/types/docker/mediatype.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export const MEDIATYPE_IMAGE_MANIFEST_LIST_V2 = 'application/vnd.docker.distribution.manifest.list.v2+json'; 18 | 19 | export const MEDIATYPE_IMAGE_MANIFEST_V2 = 'application/vnd.docker.distribution.manifest.v2+json'; 20 | 21 | export const MEDIATYPE_IMAGE_CONFIG_V1 = 'application/vnd.docker.container.image.v1+json'; 22 | -------------------------------------------------------------------------------- /__tests__/.fixtures/bake-02.hcl: -------------------------------------------------------------------------------- 1 | // Copyright 2023 actions-toolkit authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | variable "GO_VERSION" { 16 | default = "1.20" 17 | } 18 | 19 | target "_common" { 20 | args = { 21 | GO_VERSION = GO_VERSION 22 | BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1 23 | } 24 | } 25 | 26 | group "default" { 27 | targets = ["build"] 28 | } 29 | 30 | target "build" { 31 | inherits = ["_common"] 32 | target = "build" 33 | } 34 | -------------------------------------------------------------------------------- /src/types/oci/manifest.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Descriptor} from './descriptor'; 18 | import {Versioned} from './versioned'; 19 | 20 | export interface Manifest extends Versioned { 21 | mediaType?: string; 22 | artifactType?: string; 23 | config: Descriptor; 24 | layers: Descriptor[]; 25 | subject?: Descriptor; 26 | annotations?: Record; 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | .pnpm-debug.log* 11 | 12 | # Diagnostic reports (https://nodejs.org/api/report.html) 13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # Dependency directories 26 | node_modules/ 27 | jspm_packages/ 28 | 29 | # TypeScript cache 30 | *.tsbuildinfo 31 | 32 | # Optional npm cache directory 33 | .npm 34 | 35 | # Optional eslint cache 36 | .eslintcache 37 | 38 | # Yarn Integrity file 39 | .yarn-integrity 40 | 41 | # dotenv environment variable files 42 | .env 43 | .env.development.local 44 | .env.test.local 45 | .env.production.local 46 | .env.local 47 | 48 | # yarn v2 49 | .yarn/cache 50 | .yarn/unplugged 51 | .yarn/build-state.yml 52 | .yarn/install-state.gz 53 | .pnp.* 54 | 55 | # Lib 56 | /lib 57 | -------------------------------------------------------------------------------- /__tests__/.fixtures/dockerhub-repoinfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": "foo", 3 | "name": "bar", 4 | "namespace": "foo", 5 | "repository_type": "image", 6 | "status": 1, 7 | "status_description": "active", 8 | "description": "Bar", 9 | "is_private": false, 10 | "is_automated": false, 11 | "can_edit": true, 12 | "star_count": 68, 13 | "pull_count": 178255909, 14 | "last_updated": "2023-02-02T14:22:31.184404Z", 15 | "date_registered": "2019-06-04T20:08:57.306333Z", 16 | "collaborator_count": 0, 17 | "affiliation": "owner", 18 | "hub_user": "foo", 19 | "has_starred": false, 20 | "full_description": "This is the full description of the repo.", 21 | "permissions": { 22 | "read": true, 23 | "write": true, 24 | "admin": true 25 | }, 26 | "media_types": [ 27 | "application/vnd.docker.container.image.v1+json", 28 | "application/vnd.docker.distribution.manifest.list.v2+json", 29 | "application/vnd.oci.image.index.v1+json" 30 | ], 31 | "content_types": [ 32 | "image" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.github/workflows/validate.yml: -------------------------------------------------------------------------------- 1 | name: validate 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | push: 10 | branches: 11 | - 'main' 12 | pull_request: 13 | paths-ignore: 14 | - '.github/*-releases.json' 15 | 16 | jobs: 17 | prepare: 18 | runs-on: ubuntu-latest 19 | outputs: 20 | targets: ${{ steps.generate.outputs.targets }} 21 | steps: 22 | - 23 | name: Checkout 24 | uses: actions/checkout@v6 25 | - 26 | name: List targets 27 | id: generate 28 | uses: docker/bake-action/subaction/list-targets@v6 29 | with: 30 | target: validate 31 | 32 | validate: 33 | runs-on: ubuntu-latest 34 | needs: 35 | - prepare 36 | strategy: 37 | fail-fast: false 38 | matrix: 39 | target: ${{ fromJson(needs.prepare.outputs.targets) }} 40 | steps: 41 | - 42 | name: Validate 43 | uses: docker/bake-action@v6 44 | with: 45 | targets: ${{ matrix.target }} 46 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: codeql 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'main' 7 | pull_request: 8 | 9 | permissions: 10 | actions: read 11 | contents: read 12 | security-events: write 13 | 14 | env: 15 | NODE_VERSION: 20 16 | 17 | jobs: 18 | analyze: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - 22 | name: Checkout 23 | uses: actions/checkout@v6 24 | - 25 | name: Enable corepack 26 | run: | 27 | corepack enable 28 | yarn --version 29 | - 30 | name: Set up Node 31 | uses: actions/setup-node@v6 32 | with: 33 | node-version: ${{ env.NODE_VERSION }} 34 | - 35 | name: Initialize CodeQL 36 | uses: github/codeql-action/init@v4 37 | with: 38 | languages: javascript-typescript 39 | - 40 | name: Autobuild 41 | uses: github/codeql-action/autobuild@v4 42 | - 43 | name: Perform CodeQL Analysis 44 | uses: github/codeql-action/analyze@v4 45 | with: 46 | category: "/language:javascript-typescript" 47 | -------------------------------------------------------------------------------- /__tests__/testResultsProcessor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable @typescript-eslint/no-require-imports */ 18 | const fs = require('fs'); 19 | 20 | module.exports = results => { 21 | const allSkipped = results.testResults.every(result => result.skipped); 22 | if (allSkipped) { 23 | console.log('All tests were skipped!'); 24 | fs.mkdirSync('./coverage', {recursive: true}); 25 | fs.closeSync(fs.openSync('./coverage/allSkipped.txt', 'w')); 26 | } 27 | return results; 28 | }; 29 | -------------------------------------------------------------------------------- /__tests__/.fixtures/lint.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile-upstream:master 2 | 3 | # Copyright 2024 actions-toolkit authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | frOM busybox as base 18 | cOpy lint.Dockerfile . 19 | 20 | # some special chars: distroless/python3-debian12のPythonは3.11 21 | # https://github.com/docker/build-push-action/issues/1204#issuecomment-2274056016 22 | 23 | from scratch 24 | MAINTAINER moby@example.com 25 | COPy --from=base \ 26 | /lint.Dockerfile \ 27 | / 28 | 29 | CMD [ "echo", "Hello, Norway!" ] 30 | CMD [ "echo", "Hello, Sweden!" ] 31 | ENTRYPOINT my-program start 32 | -------------------------------------------------------------------------------- /src/types/buildx/imagetools.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Versioned} from '../oci/versioned'; 18 | import {Descriptor} from '../oci/descriptor'; 19 | import {Digest} from '../oci/digest'; 20 | 21 | // https://github.com/docker/buildx/blob/62857022a08552bee5cad0c3044a9a3b185f0b32/util/imagetools/printers.go#L109-L123 22 | export interface Manifest extends Versioned { 23 | mediaType?: string; 24 | digest: Digest; 25 | size: number; 26 | manifests?: Descriptor[]; 27 | annotations?: Record; 28 | } 29 | -------------------------------------------------------------------------------- /jest.config.itg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | module.exports = { 18 | testEnvironment: 'node', 19 | moduleFileExtensions: ['js', 'ts'], 20 | setupFiles: ['dotenv/config'], 21 | testMatch: ['**/*.test.itg.ts'], 22 | testTimeout: 1800000, // 30 minutes 23 | transform: { 24 | '^.+\\.ts$': 'ts-jest' 25 | }, 26 | moduleNameMapper: { 27 | '^csv-parse/sync': '/node_modules/csv-parse/dist/cjs/sync.cjs' 28 | }, 29 | testResultsProcessor: '/__tests__/testResultsProcessor.js', 30 | verbose: false 31 | }; 32 | -------------------------------------------------------------------------------- /src/types/intoto/intoto.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // https://github.com/in-toto/in-toto-golang/blob/dd6278764ab1dae7301609c7510129888e2fd569/in_toto/envelope.go#L17 18 | export const MEDIATYPE_PAYLOAD = 'application/vnd.in-toto+json'; 19 | 20 | export const MEDIATYPE_PREDICATE = 'in-toto.io/predicate-type'; 21 | 22 | // https://github.com/in-toto/in-toto-golang/blob/0a34c087cedcc36de065b4fccb7cf7c9bc16e29f/in_toto/attestations.go#L30-L42 23 | export interface Subject { 24 | name: string; 25 | digest: Record; 26 | } 27 | -------------------------------------------------------------------------------- /__tests__/.fixtures/bake-03.hcl: -------------------------------------------------------------------------------- 1 | // Copyright 2024 actions-toolkit authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | target "default" { 16 | attest = [ 17 | "type=provenance,mode=max", 18 | "type=sbom,disabled=true", 19 | ] 20 | cache-from = [ 21 | "type=gha,scope=build", 22 | "user/repo:cache", 23 | ] 24 | cache-to = [ 25 | "type=gha,scope=build,mode=max", 26 | "type=inline" 27 | ] 28 | output = [ 29 | "./release-out", 30 | "type=registry,ref=user/app" 31 | ] 32 | secret = [ 33 | "id=GITHUB_TOKEN,env=GITHUB_TOKEN", 34 | "id=aws,src=__tests__/.fixtures/secret.txt", 35 | "id=GITHUB_REPOSITORY" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /src/types/oci/mediatype.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export const MEDIATYPE_DESCRIPTOR_V1 = 'application/vnd.oci.descriptor.v1+json'; 18 | 19 | export const MEDIATYPE_IMAGE_MANIFEST_V1 = 'application/vnd.oci.image.manifest.v1+json'; 20 | 21 | export const MEDIATYPE_IMAGE_INDEX_V1 = 'application/vnd.oci.image.index.v1+json'; 22 | 23 | export const MEDIATYPE_IMAGE_LAYER_V1 = 'application/vnd.oci.image.layer.v1.tar'; 24 | 25 | export const MEDIATYPE_EMPTY_JSON_V1 = 'application/vnd.oci.empty.v1+json'; 26 | 27 | export const MEDIATYPE_IMAGE_CONFIG_V1 = 'application/vnd.oci.image.config.v1+json'; 28 | -------------------------------------------------------------------------------- /__tests__/.fixtures/hello-bake.hcl: -------------------------------------------------------------------------------- 1 | // Copyright 2024 actions-toolkit authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | target "hello" { 16 | dockerfile = "hello.Dockerfile" 17 | } 18 | 19 | target "hello-bar" { 20 | dockerfile = "hello.Dockerfile" 21 | args = { 22 | NAME = "bar" 23 | } 24 | } 25 | 26 | group "hello-all" { 27 | targets = ["hello", "hello-bar"] 28 | } 29 | 30 | target "hello-matrix" { 31 | name = "matrix-${name}" 32 | matrix = { 33 | name = ["bar", "baz", "boo", "far", "faz", "foo", "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj"] 34 | } 35 | dockerfile = "hello.Dockerfile" 36 | args = { 37 | NAME = name 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/types/oci/oci.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Index} from './index'; 18 | import {ImageLayout} from './layout'; 19 | import {Manifest} from './manifest'; 20 | import {Image} from './config'; 21 | 22 | export interface LoadArchiveOpts { 23 | file: string; 24 | } 25 | 26 | export interface Archive { 27 | root: { 28 | index: Index; 29 | layout: ImageLayout; 30 | }; 31 | indexes: Record; 32 | manifests: Record; 33 | images: Record; 34 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 35 | blobs: Record; 36 | } 37 | -------------------------------------------------------------------------------- /src/types/buildkit/git.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export interface GitURL { 18 | scheme: string; 19 | host: string; 20 | path: string; 21 | user?: URLUserInfo; 22 | fragment?: GitURLFragment; 23 | remote: string; 24 | } 25 | 26 | export interface GitURLFragment { 27 | ref: string; 28 | subdir: string; 29 | } 30 | 31 | export interface GitRef { 32 | remote?: string; 33 | shortName?: string; 34 | commit?: string; 35 | subDir?: string; 36 | indistinguishableFromLocal?: boolean; 37 | unencryptedTCP?: boolean; 38 | } 39 | 40 | export interface URLUserInfo { 41 | username: string; 42 | password: string; 43 | passwordSet: boolean; 44 | } 45 | -------------------------------------------------------------------------------- /src/types/buildkit/rpc.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // https://github.com/moby/buildkit/blob/v0.14.0/vendor/github.com/gogo/googleapis/google/rpc/status.pb.go#L36-L49 18 | export interface RpcStatus { 19 | code: number; 20 | message: string; 21 | details: Array; 22 | } 23 | 24 | // https://github.com/moby/buildkit/blob/v0.14.0/vendor/github.com/gogo/protobuf/types/any.pb.go#L108-L143 25 | // Define properties based on google.protobuf.Any. For simplicity, assuming it 26 | // has at least a type_url and a value. 27 | export interface RpcAny { 28 | type_url: string; 29 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 30 | value: any; 31 | } 32 | -------------------------------------------------------------------------------- /src/exec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as core from '@actions/core'; 18 | import * as exec from '@actions/exec'; 19 | import {ExecOptions, ExecOutput} from '@actions/exec'; 20 | 21 | export class Exec { 22 | public static async exec(commandLine: string, args?: string[], options?: ExecOptions): Promise { 23 | core.debug(`Exec.exec: ${commandLine} ${args?.join(' ')}`); 24 | return exec.exec(commandLine, args, options); 25 | } 26 | 27 | public static async getExecOutput(commandLine: string, args?: string[], options?: ExecOptions): Promise { 28 | core.debug(`Exec.getExecOutput: ${commandLine} ${args?.join(' ')}`); 29 | return exec.getExecOutput(commandLine, args, options); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/types/buildx/buildx.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GitHubContentOpts} from '../github'; 18 | 19 | export interface Cert { 20 | cacert?: string; 21 | cert?: string; 22 | key?: string; 23 | } 24 | 25 | export interface DownloadVersion { 26 | key: string; 27 | version: string; 28 | downloadURL: string; 29 | contentOpts: GitHubContentOpts; 30 | } 31 | 32 | export interface LocalRefsOpts { 33 | dir: string; 34 | builderName?: string; 35 | nodeName?: string; 36 | since?: Date; 37 | } 38 | 39 | export interface LocalRefsResponse { 40 | [ref: string]: LocalState; 41 | } 42 | 43 | export interface LocalState { 44 | Target: string; 45 | LocalPath: string; 46 | DockerfilePath: string; 47 | GroupRef?: string; 48 | } 49 | -------------------------------------------------------------------------------- /src/buildkit/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import fs from 'fs'; 18 | 19 | import {Context} from '../context'; 20 | 21 | export class Config { 22 | public resolveFromString(s: string): string { 23 | return this.resolve(s, false); 24 | } 25 | 26 | public resolveFromFile(s: string): string { 27 | return this.resolve(s, true); 28 | } 29 | 30 | private resolve(s: string, file: boolean): string { 31 | if (file) { 32 | if (!fs.existsSync(s)) { 33 | throw new Error(`config file ${s} not found`); 34 | } 35 | s = fs.readFileSync(s, {encoding: 'utf-8'}); 36 | } 37 | const configFile = Context.tmpName({tmpdir: Context.tmpDir()}); 38 | fs.writeFileSync(configFile, s); 39 | return configFile; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/types/oci/descriptor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Digest} from './digest'; 18 | 19 | import {MEDIATYPE_EMPTY_JSON_V1} from './mediatype'; 20 | 21 | export interface Descriptor { 22 | mediaType: string; 23 | digest: Digest; 24 | size: number; 25 | urls?: string[]; 26 | annotations?: Record; 27 | data?: string; 28 | platform?: Platform; 29 | artifactType?: string; 30 | } 31 | 32 | export interface Platform { 33 | architecture: string; 34 | os: string; 35 | 'os.version'?: string; 36 | 'os.features'?: string[]; 37 | variant?: string; 38 | } 39 | 40 | export const DescriptorEmptyJSON: Descriptor = { 41 | mediaType: MEDIATYPE_EMPTY_JSON_V1, 42 | digest: 'sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a', 43 | size: 2, 44 | data: '{}' 45 | }; 46 | -------------------------------------------------------------------------------- /__tests__/undock/install.test.itg.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, test} from '@jest/globals'; 18 | import * as fs from 'fs'; 19 | 20 | import {Install} from '../../src/undock/install'; 21 | 22 | describe('download', () => { 23 | // prettier-ignore 24 | test.each(['latest'])( 25 | 'install undock %s', async (version) => { 26 | await expect((async () => { 27 | const install = new Install(); 28 | const toolPath = await install.download(version); 29 | if (!fs.existsSync(toolPath)) { 30 | throw new Error('toolPath does not exist'); 31 | } 32 | const binPath = await install.install(toolPath); 33 | if (!fs.existsSync(binPath)) { 34 | throw new Error('binPath does not exist'); 35 | } 36 | })()).resolves.not.toThrow(); 37 | }, 60000); 38 | }); 39 | -------------------------------------------------------------------------------- /__tests__/.fixtures/bake-01-validate.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": { 3 | "default": { 4 | "targets": [ 5 | "validate" 6 | ] 7 | }, 8 | "validate": { 9 | "targets": [ 10 | "lint", 11 | "validate-vendor", 12 | "validate-docs" 13 | ] 14 | } 15 | }, 16 | "target": { 17 | "lint": { 18 | "context": ".", 19 | "dockerfile": "./hack/dockerfiles/lint.Dockerfile", 20 | "args": { 21 | "BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1", 22 | "GO_VERSION": "1.20" 23 | }, 24 | "output": [ 25 | { 26 | "type": "cacheonly" 27 | } 28 | ] 29 | }, 30 | "validate-docs": { 31 | "context": ".", 32 | "dockerfile": "./hack/dockerfiles/docs.Dockerfile", 33 | "args": { 34 | "BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1", 35 | "BUILDX_EXPERIMENTAL": "1", 36 | "FORMATS": "md", 37 | "GO_VERSION": "1.20" 38 | }, 39 | "target": "validate", 40 | "output": [ 41 | { 42 | "type": "cacheonly" 43 | } 44 | ] 45 | }, 46 | "validate-vendor": { 47 | "context": ".", 48 | "dockerfile": "./hack/dockerfiles/vendor.Dockerfile", 49 | "args": { 50 | "BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1", 51 | "GO_VERSION": "1.20" 52 | }, 53 | "target": "validate", 54 | "output": [ 55 | { 56 | "type": "cacheonly" 57 | } 58 | ] 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /__tests__/regclient/install.test.itg.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, test} from '@jest/globals'; 18 | import * as fs from 'fs'; 19 | 20 | import {Install} from '../../src/regclient/install'; 21 | 22 | describe('download', () => { 23 | // prettier-ignore 24 | test.each(['latest'])( 25 | 'install regclient %s', async (version) => { 26 | await expect((async () => { 27 | const install = new Install(); 28 | const toolPath = await install.download(version); 29 | if (!fs.existsSync(toolPath)) { 30 | throw new Error('toolPath does not exist'); 31 | } 32 | const binPath = await install.install(toolPath); 33 | if (!fs.existsSync(binPath)) { 34 | throw new Error('binPath does not exist'); 35 | } 36 | })()).resolves.not.toThrow(); 37 | }, 60000); 38 | }); 39 | -------------------------------------------------------------------------------- /__tests__/.fixtures/bake-03-default.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": { 3 | "default": { 4 | "targets": [ 5 | "default" 6 | ] 7 | } 8 | }, 9 | "target": { 10 | "default": { 11 | "context": ".", 12 | "dockerfile": "Dockerfile", 13 | "attest": [ 14 | { 15 | "mode": "max", 16 | "type": "provenance" 17 | }, 18 | { 19 | "disabled": true, 20 | "type": "sbom" 21 | } 22 | ], 23 | "cache-from": [ 24 | { 25 | "scope": "build", 26 | "type": "gha" 27 | }, 28 | { 29 | "ref": "user/repo:cache", 30 | "type": "registry" 31 | } 32 | ], 33 | "cache-to": [ 34 | { 35 | "mode": "max", 36 | "scope": "build", 37 | "type": "gha" 38 | }, 39 | { 40 | "type": "inline" 41 | } 42 | ], 43 | "output": [ 44 | { 45 | "dest": "./release-out", 46 | "type": "local" 47 | }, 48 | { 49 | "ref": "user/app", 50 | "type": "registry" 51 | } 52 | ], 53 | "secret": [ 54 | { 55 | "env": "GITHUB_TOKEN", 56 | "id": "GITHUB_TOKEN" 57 | }, 58 | { 59 | "id": "aws", 60 | "src": "__tests__/.fixtures/secret.txt" 61 | }, 62 | { 63 | "id": "GITHUB_REPOSITORY" 64 | } 65 | ] 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect8.txt: -------------------------------------------------------------------------------- 1 | Name: builder-52aa0611-faf0-42ac-a940-461e4e287d68 2 | Driver: docker-container 3 | Last Activity: 2023-06-13 13:52:31 +0000 UTC 4 | 5 | Nodes: 6 | Name: builder-52aa0611-faf0-42ac-a940-461e4e287d680 7 | Endpoint: unix:///var/run/docker.sock 8 | Driver Options: image="moby/buildkit:buildx-stable-1" network="host" 9 | Status: running 10 | Flags: --debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host 11 | Buildkit: v0.11.6 12 | Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6 13 | Labels: 14 | org.mobyproject.buildkit.worker.executor: oci 15 | org.mobyproject.buildkit.worker.hostname: fv-az572-38 16 | org.mobyproject.buildkit.worker.network: host 17 | org.mobyproject.buildkit.worker.oci.process-mode: sandbox 18 | org.mobyproject.buildkit.worker.selinux.enabled: false 19 | org.mobyproject.buildkit.worker.snapshotter: overlayfs 20 | GC Policy rule#0: 21 | All: false 22 | Filters: type==source.local,type==exec.cachemount,type==source.git.checkout 23 | Keep Duration: 48h0m0s 24 | Keep Bytes: 488.3MiB 25 | GC Policy rule#1: 26 | All: false 27 | Keep Duration: 1440h0m0s 28 | Keep Bytes: 8.382GiB 29 | GC Policy rule#2: 30 | All: false 31 | Keep Bytes: 8.382GiB 32 | GC Policy rule#3: 33 | All: true 34 | Keep Bytes: 8.382GiB 35 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as core from '@actions/core'; 18 | 19 | import {Cache} from './cache'; 20 | 21 | const isPost = !!process.env['STATE_isPost']; 22 | if (!isPost) { 23 | core.saveState('isPost', 'true'); 24 | } 25 | 26 | /** 27 | * Runs a GitHub Action. 28 | * Output will be streamed to the live console. 29 | * 30 | * @param main runs the defined function. 31 | * @param post runs the defined function at the end of the job if set. 32 | * @returns Promise 33 | */ 34 | export async function run(main: () => Promise, post?: () => Promise): Promise { 35 | if (!isPost) { 36 | try { 37 | await main(); 38 | } catch (e) { 39 | core.setFailed(e.message); 40 | } 41 | } else { 42 | if (post) { 43 | await post(); 44 | } 45 | await core.group(`Post cache`, async () => { 46 | await Cache.post(); 47 | }); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /__tests__/exec.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, it, jest} from '@jest/globals'; 18 | 19 | import {Exec} from '../src/exec'; 20 | 21 | describe('exec', () => { 22 | it('returns docker version', async () => { 23 | const execSpy = jest.spyOn(Exec, 'exec'); 24 | await Exec.exec('docker', ['version'], { 25 | ignoreReturnCode: true, 26 | silent: true 27 | }); 28 | expect(execSpy).toHaveBeenCalledWith(`docker`, ['version'], { 29 | ignoreReturnCode: true, 30 | silent: true 31 | }); 32 | }); 33 | }); 34 | 35 | describe('getExecOutput', () => { 36 | it('returns docker version', async () => { 37 | const execSpy = jest.spyOn(Exec, 'getExecOutput'); 38 | await Exec.getExecOutput('docker', ['version'], { 39 | ignoreReturnCode: true, 40 | silent: true 41 | }); 42 | expect(execSpy).toHaveBeenCalledWith(`docker`, ['version'], { 43 | ignoreReturnCode: true, 44 | silent: true 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/types/oci/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Digest} from './digest'; 18 | import {Platform} from './descriptor'; 19 | 20 | export interface ImageConfig { 21 | User?: string; 22 | ExposedPorts?: Record; 23 | Env?: string[]; 24 | Entrypoint?: string[]; 25 | Cmd?: string[]; 26 | Volumes?: Record; 27 | WorkingDir?: string; 28 | Labels?: Record; 29 | StopSignal?: string; 30 | ArgsEscaped?: boolean; 31 | } 32 | 33 | export interface RootFS { 34 | type: string; 35 | diff_ids: Digest[]; 36 | } 37 | 38 | export interface History { 39 | created?: string; // assuming RFC 3339 formatted string 40 | created_by?: string; 41 | author?: string; 42 | comment?: string; 43 | empty_layer?: boolean; 44 | } 45 | 46 | export interface Image extends Platform { 47 | created?: string; // assuming RFC 3339 formatted string 48 | author?: string; 49 | config?: ImageConfig; 50 | rootfs: RootFS; 51 | history?: History[]; 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | 3 | permissions: 4 | id-token: write # required for OIDC 5 | contents: read 6 | 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | 11 | on: 12 | push: 13 | tags: 14 | - 'v*' 15 | 16 | env: 17 | NODE_VERSION: "24" # at least Node 24 is required for Trusted Publishing with OIDC 18 | 19 | jobs: 20 | publish: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - 24 | name: Checkout 25 | uses: actions/checkout@v6 26 | - 27 | name: Enable corepack 28 | run: | 29 | corepack enable 30 | yarn --version 31 | - 32 | name: Setup Node 33 | uses: actions/setup-node@v6 34 | with: 35 | node-version: ${{ env.NODE_VERSION }} 36 | cache: 'yarn' 37 | package-manager-cache: false 38 | - 39 | name: Print versions 40 | run: | 41 | node --version 42 | npm --version 43 | yarn --version 44 | - 45 | name: Build 46 | run: | 47 | yarn install 48 | yarn run build 49 | - 50 | name: Publish 51 | run: | 52 | npm version --no-git-tag-version ${GITHUB_REF#refs/tags/v} 53 | npm publish --provenance --access public 54 | - 55 | name: Create Release 56 | uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 57 | with: 58 | draft: true 59 | generate_release_notes: true 60 | env: 61 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 62 | -------------------------------------------------------------------------------- /__tests__/.fixtures/runtimeToken.txt: -------------------------------------------------------------------------------- 1 | eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImVCWl9jbjNzWFlBZDBjaDRUSEJLSElnT3dPRSJ9.eyJuYW1laWQiOiJkZGRkZGRkZC1kZGRkLWRkZGQtZGRkZC1kZGRkZGRkZGRkZGQiLCJzY3AiOiJBY3Rpb25zLkdlbmVyaWNSZWFkOjAwMDAwMDAwLTAwMDAtMDAwMC0wMDAwLTAwMDAwMDAwMDAwMCBBY3Rpb25zLlVwbG9hZEFydGlmYWN0czowMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAvMTpCdWlsZC9CdWlsZC85MDIgTG9jYXRpb25TZXJ2aWNlLkNvbm5lY3QgUmVhZEFuZFVwZGF0ZUJ1aWxkQnlVcmk6MDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwLzE6QnVpbGQvQnVpbGQvOTAyIiwiSWRlbnRpdHlUeXBlQ2xhaW0iOiJTeXN0ZW06U2VydmljZUlkZW50aXR5IiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvc2lkIjoiREREREREREQtRERERC1ERERELUREREQtREREREREREREREREIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9wcmltYXJ5c2lkIjoiZGRkZGRkZGQtZGRkZC1kZGRkLWRkZGQtZGRkZGRkZGRkZGRkIiwiYXVpIjoiN2U0MGNlZWQtNWQxMi00OTRkLWI2M2QtOGVhMGQ2ZGRhMzRkIiwic2lkIjoiMmFlM2JkOTgtN2Q4NC00MGQxLWE1YjEtMWM5NTY1MmY5OTRjIiwiYWMiOiJbe1wiU2NvcGVcIjpcInJlZnMvaGVhZHMvbWFzdGVyXCIsXCJQZXJtaXNzaW9uXCI6M31dIiwiYWNzbCI6IjEwIiwib3JjaGlkIjoiNmViYTgwMjktZDliNy00ZGJkLWJkNzItM2I3ODFhZjYxNzkwLmJ1aWxkLl9fZGVmYXVsdCIsImlzcyI6InZzdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20iLCJhdWQiOiJ2c3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tfHZzbzo1YWQwMGYyMy05ZmEwLTRiZGEtYjQyNi1mMWIyNzg5MWM5MTkiLCJuYmYiOjE2NzUwNDE1NjcsImV4cCI6MTY3NTA2NDM2N30.lWJuHGC7wQ9pgHXs4dMMSsflUUi6zasOzH8rz4EFvZfIlzyMcP1sZQeySNGAZ9z91JkpREzRPHFOCTp0hM9MbN6jcA05zvhSXiEE5cZikm_z32g0c5um3F3LneHwOWZeM_Lw29FBMnswuCaljvCi9p50M4wRbtqJpoYfIwvm5-nLcBbSrQZcMfPEfVXHSBCUqdoiVAunXsUrnCsKURL5T_UJIBUYBGLUrZqf2m8YnO7Wg_Q11wSz33W0gDR4_PdnOiJY1hL0vAOiRbNG0RLPA0A2QCmvlwdJOWJKOS4GgWoRr-3_PQYNy5We70CpZTpVvHtx5PQ9l65qTASNmVeg4Q -------------------------------------------------------------------------------- /__tests__/undock/undock.test.itg.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, it} from '@jest/globals'; 18 | import fs from 'fs'; 19 | import os from 'os'; 20 | 21 | import {Undock} from '../../src/undock/undock'; 22 | import {Install as UndockInstall} from '../../src/undock/install'; 23 | 24 | describe('run', () => { 25 | it('extracts moby/moby-bin:26.1.5', async () => { 26 | const install = new UndockInstall(); 27 | const toolPath = await install.download('latest'); 28 | if (!fs.existsSync(toolPath)) { 29 | throw new Error('toolPath does not exist'); 30 | } 31 | const binPath = await install.install(toolPath); 32 | if (!fs.existsSync(binPath)) { 33 | throw new Error('binPath does not exist'); 34 | } 35 | 36 | const undock = new Undock(); 37 | await expect( 38 | (async () => { 39 | // prettier-ignore 40 | await undock.run({ 41 | source: 'docker/buildx-bin:0.23.0', 42 | dist: os.tmpdir() 43 | }); 44 | })() 45 | ).resolves.not.toThrow(); 46 | }, 500000); 47 | }); 48 | -------------------------------------------------------------------------------- /__tests__/buildx/install.test.itg.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, test} from '@jest/globals'; 18 | import * as fs from 'fs'; 19 | 20 | import {Install} from '../../src/buildx/install'; 21 | 22 | const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip; 23 | 24 | maybe('download', () => { 25 | // prettier-ignore 26 | test.each(['latest'])( 27 | 'install buildx %s', async (version) => { 28 | await expect((async () => { 29 | const install = new Install({ 30 | standalone: true 31 | }); 32 | const toolPath = await install.download(version); 33 | if (!fs.existsSync(toolPath)) { 34 | throw new Error('toolPath does not exist'); 35 | } 36 | const binPath = await install.installStandalone(toolPath); 37 | if (!fs.existsSync(binPath)) { 38 | throw new Error('binPath does not exist'); 39 | } 40 | })()).resolves.not.toThrow(); 41 | }, 60000); 42 | }); 43 | -------------------------------------------------------------------------------- /__tests__/compose/install.test.itg.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, test} from '@jest/globals'; 18 | import * as fs from 'fs'; 19 | 20 | import {Install} from '../../src/compose/install'; 21 | 22 | const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip; 23 | 24 | maybe('download', () => { 25 | // prettier-ignore 26 | test.each(['latest'])( 27 | 'install compose %s', async (version) => { 28 | await expect((async () => { 29 | const install = new Install({ 30 | standalone: true 31 | }); 32 | const toolPath = await install.download(version); 33 | if (!fs.existsSync(toolPath)) { 34 | throw new Error('toolPath does not exist'); 35 | } 36 | const binPath = await install.installStandalone(toolPath); 37 | if (!fs.existsSync(binPath)) { 38 | throw new Error('binPath does not exist'); 39 | } 40 | })()).resolves.not.toThrow(); 41 | }, 60000); 42 | }); 43 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support [![](https://isitmaintained.com/badge/resolution/docker/actions-toolkit.svg)](https://isitmaintained.com/project/docker/actions-toolkit) 2 | 3 | First, [be a good guy](https://github.com/kossnocorp/etiquette/blob/master/README.md). 4 | 5 | ## Reporting an issue 6 | 7 | Please do a search in [open issues](https://github.com/docker/actions-toolkit/issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed. 8 | 9 | If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment. 10 | 11 | :+1: - upvote 12 | 13 | :-1: - downvote 14 | 15 | If you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below. 16 | 17 | ## Writing good bug reports and feature requests 18 | 19 | File a single issue per problem and feature request. 20 | 21 | * Do not enumerate multiple bugs or feature requests in the same issue. 22 | * Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes. 23 | 24 | The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix. 25 | 26 | You are now ready to [create a new issue](https://github.com/docker/actions-toolkit/issues/new/choose)! 27 | 28 | ## Closure policy 29 | 30 | * Issues that don't have the information requested above (when applicable) will be closed immediately and the poster directed to the support guidelines. 31 | * Issues that go a week without a response from original poster are subject to closure at our discretion. 32 | -------------------------------------------------------------------------------- /src/types/buildx/builder.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export interface BuilderInfo { 18 | name?: string; 19 | driver?: string; 20 | lastActivity?: Date; 21 | nodes: NodeInfo[]; 22 | } 23 | 24 | export interface Node { 25 | name?: string; 26 | endpoint?: string; 27 | 'driver-opts'?: Array; 28 | 'buildkitd-flags'?: string; 29 | platforms?: string; 30 | } 31 | 32 | export interface NodeInfo extends Node { 33 | status?: string; 34 | buildkit?: string; 35 | features?: Record; 36 | labels?: Record; 37 | devices?: Array; 38 | gcPolicy?: Array; 39 | files?: Record; 40 | } 41 | 42 | export interface Device { 43 | name?: string; 44 | annotations?: Record; 45 | autoAllow?: boolean; 46 | onDemand?: boolean; 47 | } 48 | 49 | export interface GCPolicy { 50 | all?: boolean; 51 | filter?: string[]; 52 | keepDuration?: string; 53 | keepBytes?: string; // deprecated, use reservedSpace instead 54 | reservedSpace?: string; 55 | maxUsedSpace?: string; 56 | minFreeSpace?: string; 57 | } 58 | -------------------------------------------------------------------------------- /.github/workflows/virtual-env.yml: -------------------------------------------------------------------------------- 1 | name: virtual-env 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 10 * * *' 7 | push: 8 | branches: 9 | - 'main' 10 | paths: 11 | - '.github/workflows/virtual-env.yml' 12 | pull_request: 13 | paths: 14 | - '.github/workflows/virtual-env.yml' 15 | 16 | jobs: 17 | os: 18 | runs-on: ${{ matrix.os }} 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | os: 23 | - ubuntu-latest 24 | - ubuntu-24.04 25 | - ubuntu-22.04 26 | - ubuntu-24.04-arm 27 | - ubuntu-22.04-arm 28 | steps: 29 | - 30 | name: File system 31 | run: df -ah 32 | - 33 | name: Mounts 34 | run: mount 35 | - 36 | name: Node info 37 | run: node -p process 38 | - 39 | name: NPM version 40 | run: npm version 41 | - 42 | name: List install packages 43 | run: apt list --installed 44 | - 45 | name: Docker daemon conf 46 | run: | 47 | cat /etc/docker/daemon.json || true 48 | - 49 | name: Docker info 50 | run: docker info 51 | - 52 | name: Docker version 53 | run: docker version 54 | - 55 | name: Cgroups 56 | run: | 57 | sudo apt-get install -y cgroup-tools 58 | lscgroup 59 | - 60 | name: buildx version 61 | run: docker buildx version 62 | - 63 | name: containerd version 64 | run: containerd --version 65 | - 66 | name: Docker images 67 | run: docker image ls 68 | - 69 | name: Dump context 70 | if: always() 71 | uses: crazy-max/ghaction-dump-context@v2 72 | -------------------------------------------------------------------------------- /__tests__/oci/oci.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {afterEach, describe, expect, test} from '@jest/globals'; 18 | import fs from 'fs'; 19 | import os from 'os'; 20 | import path from 'path'; 21 | import * as rimraf from 'rimraf'; 22 | 23 | import {OCI} from '../../src/oci/oci'; 24 | 25 | const fixturesDir = path.join(__dirname, '..', '.fixtures'); 26 | const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'oci-oci-')); 27 | 28 | afterEach(function () { 29 | rimraf.sync(tmpDir); 30 | }); 31 | 32 | describe('loadArchive', () => { 33 | // prettier-ignore 34 | test.each(fs.readdirSync(path.join(fixturesDir, 'oci-archive')).filter(file => { 35 | return fs.statSync(path.join(path.join(fixturesDir, 'oci-archive'), file)).isFile(); 36 | }).map(filename => [filename]))('extracting %p', async (filename) => { 37 | const res = await OCI.loadArchive({ 38 | file: path.join(fixturesDir, 'oci-archive', filename) 39 | }); 40 | expect(res).toBeDefined(); 41 | expect(res?.root.index).toBeDefined(); 42 | expect(res?.root.layout).toBeDefined(); 43 | // console.log(JSON.stringify(res, null, 2)); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /.github/workflows/buildx-releases-json.yml: -------------------------------------------------------------------------------- 1 | name: buildx-releases-json 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | schedule: 10 | - cron: '0 */12 * * *' 11 | push: 12 | branches: 13 | - 'main' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/buildx-releases-json.yml' 17 | 18 | jobs: 19 | generate: 20 | uses: crazy-max/.github/.github/workflows/releases-json.yml@2842b806167c9dbacf5f972e0fcf47204a99d987 21 | with: 22 | repository: docker/buildx 23 | artifact_name: buildx-releases-json 24 | filename: buildx-releases.json 25 | secrets: inherit 26 | 27 | open-pr: 28 | runs-on: ubuntu-24.04 29 | if: github.event_name != 'pull_request' 30 | needs: 31 | - generate 32 | steps: 33 | - 34 | name: Checkout 35 | uses: actions/checkout@v6 36 | - 37 | name: Download 38 | uses: actions/download-artifact@v7 39 | with: 40 | name: buildx-releases-json 41 | path: .github 42 | - 43 | name: Commit changes 44 | run: | 45 | git add -A . 46 | - 47 | name: Create PR 48 | uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 49 | with: 50 | base: main 51 | branch: bot/buildx-releases-json 52 | commit-message: "github: update .github/buildx-releases.json" 53 | signoff: true 54 | delete-branch: true 55 | title: "Update `.github/buildx-releases.json`" 56 | body: | 57 | Update `.github/buildx-releases.json` to keep in sync with [https://github.com/docker/buildx](https://github.com/docker/buildx). 58 | draft: false 59 | -------------------------------------------------------------------------------- /.github/workflows/cosign-releases-json.yml: -------------------------------------------------------------------------------- 1 | name: cosign-releases-json 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | schedule: 10 | - cron: '0 */12 * * *' 11 | push: 12 | branches: 13 | - 'main' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/cosign-releases-json.yml' 17 | 18 | jobs: 19 | generate: 20 | uses: crazy-max/.github/.github/workflows/releases-json.yml@2842b806167c9dbacf5f972e0fcf47204a99d987 21 | with: 22 | repository: sigstore/cosign 23 | artifact_name: cosign-releases-json 24 | filename: cosign-releases.json 25 | secrets: inherit 26 | 27 | open-pr: 28 | runs-on: ubuntu-24.04 29 | if: github.event_name != 'pull_request' 30 | needs: 31 | - generate 32 | steps: 33 | - 34 | name: Checkout 35 | uses: actions/checkout@v6 36 | - 37 | name: Download 38 | uses: actions/download-artifact@v7 39 | with: 40 | name: cosign-releases-json 41 | path: .github 42 | - 43 | name: Commit changes 44 | run: | 45 | git add -A . 46 | - 47 | name: Create PR 48 | uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 49 | with: 50 | base: main 51 | branch: bot/cosign-releases-json 52 | commit-message: "github: update .github/cosign-releases.json" 53 | signoff: true 54 | delete-branch: true 55 | title: "Update `.github/cosign-releases.json`" 56 | body: | 57 | Update `.github/cosign-releases.json` to keep in sync with [https://github.com/sigstore/cosign](https://github.com/sigstore/cosign). 58 | draft: false 59 | -------------------------------------------------------------------------------- /.github/workflows/undock-releases-json.yml: -------------------------------------------------------------------------------- 1 | name: undock-releases-json 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | schedule: 10 | - cron: '0 */12 * * *' 11 | push: 12 | branches: 13 | - 'main' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/undock-releases-json.yml' 17 | 18 | jobs: 19 | generate: 20 | uses: crazy-max/.github/.github/workflows/releases-json.yml@2842b806167c9dbacf5f972e0fcf47204a99d987 21 | with: 22 | repository: crazy-max/undock 23 | artifact_name: undock-releases-json 24 | filename: undock-releases.json 25 | secrets: inherit 26 | 27 | open-pr: 28 | runs-on: ubuntu-24.04 29 | if: github.event_name != 'pull_request' 30 | needs: 31 | - generate 32 | steps: 33 | - 34 | name: Checkout 35 | uses: actions/checkout@v6 36 | - 37 | name: Download 38 | uses: actions/download-artifact@v7 39 | with: 40 | name: undock-releases-json 41 | path: .github 42 | - 43 | name: Commit changes 44 | run: | 45 | git add -A . 46 | - 47 | name: Create PR 48 | uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 49 | with: 50 | base: main 51 | branch: bot/undock-releases-json 52 | commit-message: "github: update .github/undock-releases.json" 53 | signoff: true 54 | delete-branch: true 55 | title: "Update `.github/undock-releases.json`" 56 | body: | 57 | Update `.github/undock-releases.json` to keep in sync with [https://github.com/crazy-max/undock](https://github.com/crazy-max/undock). 58 | draft: false 59 | -------------------------------------------------------------------------------- /.github/workflows/compose-releases-json.yml: -------------------------------------------------------------------------------- 1 | name: compose-releases-json 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | schedule: 10 | - cron: '0 */12 * * *' 11 | push: 12 | branches: 13 | - 'main' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/compose-releases-json.yml' 17 | 18 | jobs: 19 | generate: 20 | uses: crazy-max/.github/.github/workflows/releases-json.yml@2842b806167c9dbacf5f972e0fcf47204a99d987 21 | with: 22 | repository: docker/compose 23 | artifact_name: compose-releases-json 24 | filename: compose-releases.json 25 | secrets: inherit 26 | 27 | open-pr: 28 | runs-on: ubuntu-24.04 29 | if: github.event_name != 'pull_request' 30 | needs: 31 | - generate 32 | steps: 33 | - 34 | name: Checkout 35 | uses: actions/checkout@v6 36 | - 37 | name: Download 38 | uses: actions/download-artifact@v7 39 | with: 40 | name: compose-releases-json 41 | path: .github 42 | - 43 | name: Commit changes 44 | run: | 45 | git add -A . 46 | - 47 | name: Create PR 48 | uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 49 | with: 50 | base: main 51 | branch: bot/compose-releases-json 52 | commit-message: "github: update .github/compose-releases.json" 53 | signoff: true 54 | delete-branch: true 55 | title: "Update `.github/compose-releases.json`" 56 | body: | 57 | Update `.github/compose-releases.json` to keep in sync with [https://github.com/docker/compose](https://github.com/docker/compose). 58 | draft: false 59 | -------------------------------------------------------------------------------- /.github/workflows/regclient-releases-json.yml: -------------------------------------------------------------------------------- 1 | name: regclient-releases-json 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | schedule: 10 | - cron: '0 */12 * * *' 11 | push: 12 | branches: 13 | - 'main' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/regclient-releases-json.yml' 17 | 18 | jobs: 19 | generate: 20 | uses: crazy-max/.github/.github/workflows/releases-json.yml@2842b806167c9dbacf5f972e0fcf47204a99d987 21 | with: 22 | repository: regclient/regclient 23 | artifact_name: regclient-releases-json 24 | filename: regclient-releases.json 25 | secrets: inherit 26 | 27 | open-pr: 28 | runs-on: ubuntu-latest 29 | if: github.event_name != 'pull_request' 30 | needs: 31 | - generate 32 | steps: 33 | - 34 | name: Checkout 35 | uses: actions/checkout@v6 36 | - 37 | name: Download 38 | uses: actions/download-artifact@v7 39 | with: 40 | name: regclient-releases-json 41 | path: .github 42 | - 43 | name: Commit changes 44 | run: | 45 | git add -A . 46 | - 47 | name: Create PR 48 | uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 49 | with: 50 | base: main 51 | branch: bot/regclient-releases-json 52 | commit-message: "github: update .github/regclient-releases.json" 53 | signoff: true 54 | delete-branch: true 55 | title: "Update `.github/regclient-releases.json`" 56 | body: | 57 | Update `.github/regclient-releases.json` to keep in sync with [https://github.com/regclient/regclient](https://github.com/regclient/regclient). 58 | draft: false 59 | -------------------------------------------------------------------------------- /.github/workflows/buildx-lab-releases-json.yml: -------------------------------------------------------------------------------- 1 | name: buildx-lab-releases-json 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | schedule: 10 | - cron: '0 */12 * * *' 11 | push: 12 | branches: 13 | - 'main' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/buildx-lab-releases-json.yml' 17 | 18 | jobs: 19 | generate: 20 | uses: crazy-max/.github/.github/workflows/releases-json.yml@2842b806167c9dbacf5f972e0fcf47204a99d987 21 | with: 22 | repository: docker/buildx-desktop 23 | artifact_name: buildx-lab-releases-json 24 | filename: buildx-lab-releases.json 25 | secrets: inherit 26 | 27 | open-pr: 28 | runs-on: ubuntu-24.04 29 | if: github.event_name != 'pull_request' 30 | needs: 31 | - generate 32 | steps: 33 | - 34 | name: Checkout 35 | uses: actions/checkout@v6 36 | - 37 | name: Download 38 | uses: actions/download-artifact@v7 39 | with: 40 | name: buildx-lab-releases-json 41 | path: .github 42 | - 43 | name: Commit changes 44 | run: | 45 | git add -A . 46 | - 47 | name: Create PR 48 | uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 49 | with: 50 | base: main 51 | branch: bot/buildx-lab-releases-json 52 | commit-message: "github: update .github/buildx-lab-releases.json" 53 | signoff: true 54 | delete-branch: true 55 | title: "Update `.github/buildx-lab-releases.json`" 56 | body: | 57 | Update `.github/buildx-lab-releases.json` to keep in sync with [https://github.com/docker/buildx-desktop](https://github.com/docker/buildx-desktop). 58 | draft: false 59 | -------------------------------------------------------------------------------- /.github/workflows/docker-releases-json.yml: -------------------------------------------------------------------------------- 1 | name: docker-releases-json 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | schedule: 10 | - cron: '0 */12 * * *' 11 | push: 12 | branches: 13 | - 'main' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/docker-releases-json.yml' 17 | 18 | jobs: 19 | generate: 20 | uses: crazy-max/.github/.github/workflows/releases-json.yml@2842b806167c9dbacf5f972e0fcf47204a99d987 21 | with: 22 | repository: moby/moby 23 | artifact_name: docker-releases-json 24 | filename: docker-releases.json 25 | tag_patterns: | 26 | ^docker-(.*)$ 27 | ^(v.*)$ 28 | secrets: inherit 29 | 30 | open-pr: 31 | runs-on: ubuntu-24.04 32 | if: github.event_name != 'pull_request' 33 | needs: 34 | - generate 35 | steps: 36 | - 37 | name: Checkout 38 | uses: actions/checkout@v6 39 | - 40 | name: Download 41 | uses: actions/download-artifact@v7 42 | with: 43 | name: docker-releases-json 44 | path: .github 45 | - 46 | name: Commit changes 47 | run: | 48 | git add -A . 49 | - 50 | name: Create PR 51 | uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 52 | with: 53 | base: main 54 | branch: bot/docker-releases-json 55 | commit-message: "github: update .github/docker-releases.json" 56 | signoff: true 57 | delete-branch: true 58 | title: "Update `.github/docker-releases.json`" 59 | body: | 60 | Update `.github/docker-releases.json` to keep in sync with [https://github.com/moby/moby](https://github.com/moby/moby). 61 | draft: false 62 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable @typescript-eslint/no-require-imports */ 18 | const fs = require('fs'); 19 | const os = require('os'); 20 | const path = require('path'); 21 | 22 | const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-actions-toolkit-')); 23 | 24 | process.env = Object.assign({}, process.env, { 25 | TEMP: tmpDir, 26 | GITHUB_REPOSITORY: 'docker/actions-toolkit', 27 | GITHUB_RUN_ATTEMPT: 2, 28 | GITHUB_RUN_ID: 2188748038, 29 | GITHUB_RUN_NUMBER: 15, 30 | RUNNER_TEMP: path.join(tmpDir, 'runner-temp'), 31 | RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache') 32 | }); 33 | 34 | module.exports = { 35 | clearMocks: true, 36 | testEnvironment: 'node', 37 | moduleFileExtensions: ['js', 'ts'], 38 | setupFiles: ['dotenv/config'], 39 | testMatch: ['**/*.test.ts'], 40 | transform: { 41 | '^.+\\.ts$': 'ts-jest' 42 | }, 43 | moduleNameMapper: { 44 | '^csv-parse/sync': '/node_modules/csv-parse/dist/cjs/sync.cjs' 45 | }, 46 | collectCoverageFrom: ['src/**/{!(index.ts),}.ts'], 47 | coveragePathIgnorePatterns: ['lib/', 'node_modules/', '__mocks__/', '__tests__/'], 48 | testResultsProcessor: '/__tests__/testResultsProcessor.js', 49 | verbose: true 50 | }; 51 | -------------------------------------------------------------------------------- /.github/workflows/compose-lab-releases-json.yml: -------------------------------------------------------------------------------- 1 | name: compose-lab-releases-json 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | schedule: 10 | - cron: '0 */12 * * *' 11 | push: 12 | branches: 13 | - 'main' 14 | pull_request: 15 | paths: 16 | - '.github/workflows/compose-lab-releases-json.yml' 17 | 18 | jobs: 19 | generate: 20 | uses: crazy-max/.github/.github/workflows/releases-json.yml@2842b806167c9dbacf5f972e0fcf47204a99d987 21 | with: 22 | repository: docker/compose-desktop 23 | artifact_name: compose-lab-releases-json 24 | filename: compose-lab-releases.json 25 | secrets: inherit 26 | 27 | open-pr: 28 | runs-on: ubuntu-24.04 29 | if: github.event_name != 'pull_request' 30 | needs: 31 | - generate 32 | steps: 33 | - 34 | name: Checkout 35 | uses: actions/checkout@v6 36 | - 37 | name: Download 38 | uses: actions/download-artifact@v7 39 | with: 40 | name: compose-lab-releases-json 41 | path: .github 42 | - 43 | name: Commit changes 44 | run: | 45 | git add -A . 46 | - 47 | name: Create PR 48 | uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 49 | with: 50 | base: main 51 | branch: bot/compose-lab-releases-json 52 | commit-message: "github: update .github/compose-lab-releases.json" 53 | signoff: true 54 | delete-branch: true 55 | title: "Update `.github/compose-lab-releases.json`" 56 | body: | 57 | Update `.github/compose-lab-releases.json` to keep in sync with [https://github.com/docker/compose-desktop](https://github.com/docker/compose-desktop). 58 | draft: false 59 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. 4 | 5 | Contributions to this project are [released](https://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license) 6 | to the public under the [project's open source license](LICENSE). 7 | 8 | ## Submitting a pull request 9 | 10 | 1. [Fork](https://github.com/docker/actions-toolkit/fork) and clone the repository 11 | 2. Configure and install the dependencies: `yarn install` 12 | 3. Create a new branch: `git checkout -b my-branch-name` 13 | 4. Make your changes 14 | 5. Make sure the tests pass: `docker buildx bake test` 15 | 6. Format code and build javascript artifacts: `docker buildx bake pre-checkin` 16 | 7. Validate all code has correctly formatted and built: `docker buildx bake validate` 17 | 8. Push to your fork and [submit a pull request](https://github.com/docker/actions-toolkit/compare) 18 | 9. Pat your self on the back and wait for your pull request to be reviewed and merged. 19 | 20 | Here are a few things you can do that will increase the likelihood of your pull request being accepted: 21 | 22 | - Make sure the `README.md` and any other relevant **documentation are kept up-to-date**. 23 | - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. 24 | - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**. 25 | - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). 26 | 27 | ## Resources 28 | 29 | - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) 30 | - [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) 31 | - [GitHub Help](https://docs.github.com/en) 32 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect11.txt: -------------------------------------------------------------------------------- 1 | Name: builder 2 | Driver: docker-container 3 | Last Activity: 2024-03-01 14:25:03 +0000 UTC 4 | 5 | Nodes: 6 | Name: builder0 7 | Endpoint: unix:///var/run/docker.sock 8 | Driver Options: env.JAEGER_TRACE="localhost:6831" image="moby/buildkit:master" network="host" env.BUILDKIT_STEP_LOG_MAX_SIZE="10485760" env.BUILDKIT_STEP_LOG_MAX_SPEED="10485760" 9 | Status: running 10 | BuildKit daemon flags: --debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host --allow-insecure-entitlement=network.host 11 | BuildKit version: 37657a1 12 | Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6 13 | Features: 14 | Cache export: true 15 | Docker exporter: true 16 | Multi-platform build: true 17 | OCI exporter: true 18 | Labels: 19 | org.mobyproject.buildkit.worker.executor: oci 20 | org.mobyproject.buildkit.worker.hostname: docker-desktop 21 | org.mobyproject.buildkit.worker.network: host 22 | org.mobyproject.buildkit.worker.oci.process-mode: sandbox 23 | org.mobyproject.buildkit.worker.selinux.enabled: false 24 | org.mobyproject.buildkit.worker.snapshotter: overlayfs 25 | GC Policy rule#0: 26 | All: false 27 | Filters: type==source.local,type==exec.cachemount,type==source.git.checkout 28 | Keep Duration: 48h0m0s 29 | Keep Bytes: 488.3MiB 30 | GC Policy rule#1: 31 | All: false 32 | Keep Duration: 1440h0m0s 33 | Keep Bytes: 94.06GiB 34 | GC Policy rule#2: 35 | All: false 36 | Keep Bytes: 94.06GiB 37 | GC Policy rule#3: 38 | All: true 39 | Keep Bytes: 94.06GiB 40 | File#buildkitd.toml: 41 | > debug = true 42 | > insecure-entitlements = ["network.host", "security.insecure"] 43 | > trace = true 44 | > 45 | > [log] 46 | > format = "text" 47 | > 48 | File#foo.txt: 49 | > foo = bar 50 | > baz = qux 51 | > 52 | -------------------------------------------------------------------------------- /__tests__/.fixtures/inspect12.txt: -------------------------------------------------------------------------------- 1 | Name: nvidia 2 | Driver: docker-container 3 | Last Activity: 2025-02-14 15:57:45 +0000 UTC 4 | 5 | Nodes: 6 | Name: nvidia0 7 | Endpoint: unix:///var/run/docker.sock 8 | Driver Options: image="moby/buildkit:local" 9 | Status: running 10 | BuildKit daemon flags: --allow-insecure-entitlement=network.host 11 | BuildKit version: v0.20.0-rc2-4-gd30d8e22c.m 12 | Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6 13 | Features: 14 | Cache export: true 15 | Docker exporter: true 16 | Multi-platform build: true 17 | OCI exporter: true 18 | Labels: 19 | org.mobyproject.buildkit.worker.executor: oci 20 | org.mobyproject.buildkit.worker.hostname: 76ac9a510d96 21 | org.mobyproject.buildkit.worker.network: host 22 | org.mobyproject.buildkit.worker.oci.process-mode: sandbox 23 | org.mobyproject.buildkit.worker.selinux.enabled: false 24 | org.mobyproject.buildkit.worker.snapshotter: overlayfs 25 | Devices: 26 | Name: nvidia.com/gpu=all 27 | Automatically allowed: true 28 | Annotations: 29 | foo: bar 30 | org.mobyproject.buildkit.device.autoallow: true 31 | Name: docker.com/gpu=venus 32 | Automatically allowed: false 33 | Annotations: 34 | bar: baz 35 | GC Policy rule#0: 36 | All: false 37 | Filters: type==source.local,type==exec.cachemount,type==source.git.checkout 38 | Keep Duration: 48h0m0s 39 | Max Used Space: 488.3MiB 40 | GC Policy rule#1: 41 | All: false 42 | Keep Duration: 1440h0m0s 43 | Reserved Space: 9.313GiB 44 | Max Used Space: 93.13GiB 45 | Min Free Space: 188.1GiB 46 | GC Policy rule#2: 47 | All: false 48 | Reserved Space: 9.313GiB 49 | Max Used Space: 93.13GiB 50 | Min Free Space: 188.1GiB 51 | GC Policy rule#3: 52 | All: true 53 | Reserved Space: 9.313GiB 54 | Max Used Space: 93.13GiB 55 | Min Free Space: 188.1GiB 56 | -------------------------------------------------------------------------------- /src/types/intoto/slsa_provenance/v0.2/provenance.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // https://github.com/in-toto/in-toto-golang/blob/master/in_toto/slsa_provenance/v0.2/provenance.go 18 | 19 | export const PREDICATE_SLSA_PROVENANCE = 'https://slsa.dev/provenance/v0.2'; 20 | 21 | export interface ProvenancePredicate { 22 | builder: ProvenanceBuilder; 23 | buildType: string; 24 | invocation?: ProvenanceInvocation; 25 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 26 | buildConfig?: any; 27 | metadata: ProvenanceMetadata; 28 | materials?: Material[]; 29 | } 30 | 31 | export interface ProvenanceBuilder { 32 | id: string; 33 | } 34 | 35 | export interface ProvenanceInvocation { 36 | configSource?: ConfigSource; 37 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 38 | parameters?: any; 39 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 40 | environment?: any; 41 | } 42 | 43 | export interface DigestSet { 44 | [key: string]: string; 45 | } 46 | 47 | export interface ConfigSource { 48 | uri?: string; 49 | digest?: DigestSet; 50 | entryPoint?: string; 51 | } 52 | 53 | export interface Completeness { 54 | parameters?: boolean; 55 | environment?: boolean; 56 | materials?: boolean; 57 | } 58 | 59 | export interface ProvenanceMetadata { 60 | buildInvocationId?: string; 61 | buildStartedOn?: string; 62 | completeness?: Completeness; 63 | reproducible?: boolean; 64 | } 65 | 66 | export interface Material { 67 | uri: string; 68 | digest: DigestSet; 69 | } 70 | -------------------------------------------------------------------------------- /__tests__/cache.test.itg.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, it} from '@jest/globals'; 18 | import fs from 'fs'; 19 | import os from 'os'; 20 | import path from 'path'; 21 | 22 | import {Cache} from '../src/cache'; 23 | import {Util} from '../src/util'; 24 | 25 | const fixturesDir = path.join(__dirname, '.fixtures'); 26 | const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'cache-itg-')); 27 | 28 | describe('cache', () => { 29 | it('caches github-repo', async () => { 30 | const r = Util.generateRandomString(); 31 | const htcName = `cache-test-github-repo-${r}`; 32 | const c = new Cache({ 33 | htcName: htcName, 34 | htcVersion: `v1.0.0+${r}`, 35 | baseCacheDir: path.join(tmpDir, '.cache-test'), 36 | cacheFile: 'github-repo.json' 37 | }); 38 | expect(await c.save(path.join(fixturesDir, 'github-repo.json'), true)).not.toEqual(''); 39 | expect(await c.find()).not.toEqual(''); 40 | }); 41 | 42 | it('caches github-repo with post state', async () => { 43 | const r = Util.generateRandomString(); 44 | const htcName = `cache-test-github-repo-${r}`; 45 | const c = new Cache({ 46 | htcName: htcName, 47 | htcVersion: `v1.0.0+${r}`, 48 | baseCacheDir: path.join(tmpDir, '.cache-test'), 49 | cacheFile: 'github-repo.json' 50 | }); 51 | expect(await c.save(path.join(fixturesDir, 'github-repo.json'))).not.toEqual(''); 52 | expect(await Cache.post()).not.toBeNull(); 53 | expect(await c.find()).not.toEqual(''); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /__tests__/cosign/install.test.itg.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, it, test} from '@jest/globals'; 18 | import * as fs from 'fs'; 19 | 20 | import {Install} from '../../src/cosign/install'; 21 | 22 | const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip; 23 | 24 | describe('download', () => { 25 | // prettier-ignore 26 | test.each(['latest'])( 27 | 'install cosign %s', async (version) => { 28 | await expect((async () => { 29 | const install = new Install(); 30 | const toolPath = await install.download({ 31 | version: version, 32 | verifySignature: true 33 | }); 34 | if (!fs.existsSync(toolPath)) { 35 | throw new Error('toolPath does not exist'); 36 | } 37 | const binPath = await install.install(toolPath); 38 | if (!fs.existsSync(binPath)) { 39 | throw new Error('binPath does not exist'); 40 | } 41 | })()).resolves.not.toThrow(); 42 | }, 60000); 43 | }); 44 | 45 | maybe('build', () => { 46 | it.skip('builds refs/pull/4492/head', async () => { 47 | const install = new Install(); 48 | const toolPath = await install.build('https://github.com/sigstore/cosign.git#refs/pull/4492/head'); 49 | expect(fs.existsSync(toolPath)).toBe(true); 50 | const buildxBin = await install.install(toolPath); 51 | expect(fs.existsSync(buildxBin)).toBe(true); 52 | }, 500000); 53 | }); 54 | -------------------------------------------------------------------------------- /src/types/github.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {AnnotationProperties} from '@actions/core'; 18 | import {components as OctoOpenApiTypes} from '@octokit/openapi-types'; 19 | import {JwtPayload} from 'jwt-decode'; 20 | 21 | import {BakeDefinition} from './buildx/bake'; 22 | import {ExportResponse} from './buildx/history'; 23 | 24 | export interface GitHubRelease { 25 | id: number; 26 | tag_name: string; 27 | html_url: string; 28 | assets: Array; 29 | } 30 | 31 | export interface GitHubContentOpts { 32 | owner: string; 33 | repo: string; 34 | ref?: string; 35 | path: string; 36 | } 37 | 38 | export type GitHubRepo = OctoOpenApiTypes['schemas']['repository']; 39 | 40 | export interface GitHubActionsRuntimeToken extends JwtPayload { 41 | ac?: string; 42 | } 43 | 44 | export interface GitHubActionsRuntimeTokenAC { 45 | Scope: string; 46 | Permission: number; 47 | } 48 | 49 | export interface GitHubAnnotation extends AnnotationProperties { 50 | message: string; 51 | } 52 | 53 | export interface UploadArtifactOpts { 54 | filename: string; 55 | mimeType?: string; 56 | retentionDays?: number; 57 | } 58 | 59 | export interface UploadArtifactResponse { 60 | id: number; 61 | filename: string; 62 | size: number; 63 | url: string; 64 | } 65 | 66 | export interface BuildSummaryOpts { 67 | exportRes: ExportResponse; 68 | uploadRes?: UploadArtifactResponse; 69 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 70 | inputs?: any; 71 | bakeDefinition?: BakeDefinition; 72 | // builder options 73 | driver?: string; 74 | endpoint?: string; 75 | } 76 | -------------------------------------------------------------------------------- /src/context.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import fs from 'fs'; 18 | import os from 'os'; 19 | import path from 'path'; 20 | import * as tmp from 'tmp'; 21 | import * as github from '@actions/github'; 22 | 23 | import {GitHub} from './github'; 24 | 25 | export class Context { 26 | private static readonly _tmpDir = fs.mkdtempSync(path.join(Context.ensureDirExists(process.env.RUNNER_TEMP || os.tmpdir()), 'docker-actions-toolkit-')); 27 | 28 | private static ensureDirExists(dir: string): string { 29 | fs.mkdirSync(dir, {recursive: true}); 30 | return dir; 31 | } 32 | 33 | public static tmpDir(): string { 34 | return Context._tmpDir; 35 | } 36 | 37 | public static tmpName(options?: tmp.TmpNameOptions): string { 38 | return tmp.tmpNameSync(options); 39 | } 40 | 41 | public static gitRef(): string { 42 | return Context.parseGitRef(github.context.ref, github.context.sha); 43 | } 44 | 45 | public static parseGitRef(ref: string, sha: string): string { 46 | const setPullRequestHeadRef: boolean = !!(process.env.DOCKER_DEFAULT_GIT_CONTEXT_PR_HEAD_REF && process.env.DOCKER_DEFAULT_GIT_CONTEXT_PR_HEAD_REF === 'true'); 47 | if (sha && ref && !ref.startsWith('refs/')) { 48 | ref = `refs/heads/${ref}`; 49 | } 50 | if (sha && !ref.startsWith(`refs/pull/`)) { 51 | ref = sha; 52 | } else if (ref.startsWith(`refs/pull/`) && setPullRequestHeadRef) { 53 | ref = ref.replace(/\/merge$/g, '/head'); 54 | } 55 | return ref; 56 | } 57 | 58 | public static gitContext(): string { 59 | return `${GitHub.serverURL}/${github.context.repo.owner}/${github.context.repo.repo}.git#${Context.gitRef()}`; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/types/buildx/bake.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export interface BakeDefinition { 18 | group: Record; 19 | target: Record; 20 | } 21 | 22 | export interface Group { 23 | description?: string; 24 | targets: Array; 25 | } 26 | 27 | export interface Target { 28 | description?: string; 29 | args?: Record; 30 | attest?: Array | Array; 31 | 'cache-from'?: Array | Array; 32 | 'cache-to'?: Array | Array; 33 | call?: string; 34 | context: string; 35 | contexts?: Record; 36 | dockerfile: string; 37 | 'dockerfile-inline'?: string; 38 | entitlements?: Array; 39 | labels?: Record; 40 | 'no-cache'?: boolean; 41 | 'no-cache-filter'?: Array; 42 | output?: Array | Array; 43 | platforms?: Array; 44 | pull?: boolean; 45 | secret?: Array | Array; 46 | 'shm-size'?: string; 47 | ssh?: Array | Array; 48 | tags?: Array; 49 | target?: string; 50 | ulimits?: Array; 51 | } 52 | 53 | export interface AttestEntry { 54 | type: string; 55 | disabled?: string | boolean; 56 | [key: string]: string | boolean | undefined; 57 | } 58 | 59 | export interface CacheEntry { 60 | type: string; 61 | [key: string]: string; 62 | } 63 | 64 | export interface ExportEntry { 65 | type: string; 66 | [key: string]: string; 67 | } 68 | 69 | export interface SecretEntry { 70 | id?: string; 71 | src?: string; 72 | env?: string; 73 | } 74 | 75 | export interface SSHEntry { 76 | id?: string; 77 | paths?: Array; 78 | } 79 | -------------------------------------------------------------------------------- /src/types/sigstore/sigstore.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import type {SerializedBundle} from '@sigstore/bundle'; 18 | 19 | import {Subject} from '../intoto/intoto'; 20 | 21 | export const FULCIO_URL = 'https://fulcio.sigstore.dev'; 22 | export const REKOR_URL = 'https://rekor.sigstore.dev'; 23 | export const TSASERVER_URL = 'https://timestamp.sigstore.dev'; 24 | export const SEARCH_URL = 'https://search.sigstore.dev'; 25 | 26 | export interface Endpoints { 27 | fulcioURL: string; 28 | rekorURL?: string; 29 | tsaServerURL?: string; 30 | } 31 | 32 | export interface ParsedBundle { 33 | payload: SerializedBundle; 34 | certificate: string; 35 | tlogID?: string; 36 | } 37 | 38 | export interface SignAttestationManifestsOpts { 39 | imageNames: Array; 40 | imageDigest: string; 41 | noTransparencyLog?: boolean; 42 | } 43 | 44 | export interface SignAttestationManifestsResult extends ParsedBundle { 45 | imageName: string; 46 | } 47 | 48 | export interface VerifySignedManifestsOpts { 49 | certificateIdentityRegexp: string; 50 | retries?: number; 51 | } 52 | 53 | export interface VerifySignedManifestsResult { 54 | cosignArgs: Array; 55 | signatureManifestDigest: string; 56 | } 57 | 58 | export interface SignProvenanceBlobsOpts { 59 | localExportDir: string; 60 | name?: string; 61 | noTransparencyLog?: boolean; 62 | } 63 | 64 | export interface SignProvenanceBlobsResult extends ParsedBundle { 65 | bundlePath: string; 66 | subjects: Array; 67 | } 68 | 69 | export interface VerifySignedArtifactsOpts { 70 | certificateIdentityRegexp: string; 71 | } 72 | 73 | export interface VerifySignedArtifactsResult { 74 | bundlePath: string; 75 | cosignArgs: Array; 76 | } 77 | -------------------------------------------------------------------------------- /__tests__/buildx/bake.test.itg.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, test} from '@jest/globals'; 18 | import * as fs from 'fs'; 19 | import * as path from 'path'; 20 | 21 | import {Bake} from '../../src/buildx/bake'; 22 | import {BakeDefinition} from '../../src/types/buildx/bake'; 23 | 24 | const fixturesDir = path.join(__dirname, '..', '.fixtures'); 25 | 26 | const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip; 27 | 28 | maybe('getDefinition', () => { 29 | // prettier-ignore 30 | test.each([ 31 | [ 32 | 'https://github.com/docker/buildx.git#v0.10.4', 33 | ['binaries-cross'], 34 | path.join(fixturesDir, 'bake-buildx-0.10.4-binaries-cross.json'), 35 | false, 36 | ], 37 | // TODO: uncomment this test case when we have access to the private repo using an access token 38 | // [ 39 | // 'https://github.com/docker/test-docker-action.git#remote-private', 40 | // ['default'], 41 | // path.join(fixturesDir, 'bake-test-docker-action-remote-private.json'), 42 | // true, 43 | // ] 44 | ])('given %p', async (source: string, targets: string[], out: string, auth) => { 45 | const gitAuthToken = process.env.GITHUB_TOKEN || ''; 46 | if (auth && !gitAuthToken) { 47 | console.log(`Git auth token not available, skipping test`); 48 | return; 49 | } 50 | const bake = new Bake(); 51 | const expectedDef = JSON.parse(fs.readFileSync(out, {encoding: 'utf-8'}).trim()) 52 | expect(await bake.getDefinition({ 53 | source: source, 54 | targets: targets, 55 | githubToken: gitAuthToken, 56 | })).toEqual(expectedDef); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /src/types/buildkit/client.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Digest} from '../oci/digest'; 18 | import {ProgressGroup, Range, SourceInfo} from './ops'; 19 | 20 | // https://github.com/moby/buildkit/blob/v0.14.0/client/graph.go#L10-L19 21 | export interface Vertex { 22 | digest?: Digest; 23 | inputs?: Array; 24 | name?: string; 25 | started?: Date; 26 | completed?: Date; 27 | cached?: boolean; 28 | error?: string; 29 | progressGroup?: ProgressGroup; 30 | } 31 | 32 | // https://github.com/moby/buildkit/blob/v0.14.0/client/graph.go#L21-L30 33 | export interface VertexStatus { 34 | id: string; 35 | vertex?: Digest; 36 | name?: string; 37 | total?: number; 38 | current: number; 39 | timestamp?: Date; 40 | started?: Date; 41 | completed?: Date; 42 | } 43 | 44 | // https://github.com/moby/buildkit/blob/v0.14.0/client/graph.go#L32-L37 45 | export interface VertexLog { 46 | vertex?: Digest; 47 | stream?: number; 48 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 49 | data: any; 50 | timestamp: Date; 51 | } 52 | 53 | // https://github.com/moby/buildkit/blob/v0.14.0/client/graph.go#L39-L48 54 | export interface VertexWarning { 55 | vertex?: Digest; 56 | level?: number; 57 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 58 | short?: any; 59 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 60 | detail?: Array; 61 | url?: string; 62 | 63 | sourceInfo?: SourceInfo; 64 | range?: Array; 65 | } 66 | 67 | // https://github.com/moby/buildkit/blob/v0.14.0/client/graph.go#L50-L55 68 | export interface SolveStatus { 69 | vertexes?: Array; 70 | statuses?: Array; 71 | logs?: Array; 72 | warnings?: Array; 73 | } 74 | 75 | // https://github.com/moby/buildkit/blob/v0.14.0/client/graph.go#L57-L60 76 | export interface SolveResponse { 77 | exporterResponse: Record; 78 | } 79 | -------------------------------------------------------------------------------- /__tests__/buildkit/buildkit.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, it, jest, test} from '@jest/globals'; 18 | 19 | import {BuildKit} from '../../src/buildkit/buildkit'; 20 | import {Builder} from '../../src/buildx/builder'; 21 | 22 | import {BuilderInfo} from '../../src/types/buildx/builder'; 23 | 24 | jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise => { 25 | return { 26 | name: 'builder2', 27 | driver: 'docker-container', 28 | lastActivity: new Date('2023-01-16 09:45:23 +0000 UTC'), 29 | nodes: [ 30 | { 31 | buildkit: 'v0.11.0', 32 | 'buildkitd-flags': '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', 33 | 'driver-opts': ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'], 34 | endpoint: 'unix:///var/run/docker.sock', 35 | name: 'builder20', 36 | platforms: 'linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6', 37 | status: 'running' 38 | } 39 | ] 40 | }; 41 | }); 42 | 43 | describe('getVersion', () => { 44 | it('valid', async () => { 45 | const builder = new Builder(); 46 | const builderInfo = await builder.inspect('builder2'); 47 | const buildkit = new BuildKit(); 48 | const version = await buildkit.getVersion(builderInfo.nodes[0]); 49 | expect(version).toBe('v0.11.0'); 50 | }); 51 | }); 52 | 53 | describe('satisfies', () => { 54 | test.each([ 55 | ['builder2', '>=0.10.0', true], 56 | ['builder2', '>0.11.0', false] 57 | ])('given %p', async (builderName, range, expected) => { 58 | const buildkit = new BuildKit(); 59 | expect(await buildkit.versionSatisfies(builderName, range)).toBe(expected); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /__tests__/docker/docker.test.itg.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, it, test} from '@jest/globals'; 18 | 19 | import {Docker} from '../../src/docker/docker'; 20 | 21 | const maybe = !process.env.GITHUB_ACTIONS || (process.env.GITHUB_ACTIONS === 'true' && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu')) ? describe : describe.skip; 22 | 23 | maybe('isDaemonRunning', () => { 24 | it('checks if daemon is running', async () => { 25 | expect(await Docker.isDaemonRunning()).toBe(true); 26 | }); 27 | }); 28 | 29 | maybe('pull', () => { 30 | // prettier-ignore 31 | test.each([ 32 | [ 33 | 'busybox', 34 | undefined, 35 | ], 36 | [ 37 | 'busybox:1.36', 38 | undefined, 39 | ], 40 | [ 41 | 'busybox@sha256:7ae8447f3a7f5bccaa765926f25fc038e425cf1b2be6748727bbea9a13102094', 42 | undefined, 43 | ], 44 | [ 45 | 'doesnotexist:foo', 46 | `pull access denied for doesnotexist`, 47 | ], 48 | ])('pulling %p', async (image: string, err: string | undefined) => { 49 | try { 50 | await Docker.pull(image, true); 51 | if (err !== undefined) { 52 | throw new Error('Expected an error to be thrown'); 53 | } 54 | } catch (e) { 55 | if (err === undefined) { 56 | throw new Error(`Expected no error, but got: ${e.message}`); 57 | } 58 | // eslint-disable-next-line jest/no-conditional-expect 59 | expect(e.message).toContain(err); 60 | } 61 | }, 600000); 62 | }); 63 | 64 | maybe('contextInspect', () => { 65 | it('inspect default context', async () => { 66 | const contextInfo = await Docker.contextInspect(); 67 | expect(contextInfo).toBeDefined(); 68 | console.log('contextInfo', contextInfo); 69 | expect(contextInfo?.Name).toBeDefined(); 70 | expect(contextInfo?.Endpoints).toBeDefined(); 71 | expect(Object.keys(contextInfo?.Endpoints).length).toBeGreaterThan(0); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /__tests__/buildkit/config.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, jest, test, afterEach} from '@jest/globals'; 18 | import fs from 'fs'; 19 | import os from 'os'; 20 | import path from 'path'; 21 | import * as rimraf from 'rimraf'; 22 | 23 | import {BuildKit} from '../../src/buildkit/buildkit'; 24 | import {Context} from '../../src/context'; 25 | 26 | const fixturesDir = path.join(__dirname, '..', '.fixtures'); 27 | const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'buildkit-config-')); 28 | const tmpName = path.join(tmpDir, '.tmpname-jest'); 29 | 30 | jest.spyOn(Context, 'tmpDir').mockImplementation((): string => { 31 | fs.mkdirSync(tmpDir, {recursive: true}); 32 | return tmpDir; 33 | }); 34 | 35 | jest.spyOn(Context, 'tmpName').mockImplementation((): string => { 36 | return tmpName; 37 | }); 38 | 39 | afterEach(() => { 40 | rimraf.sync(tmpDir); 41 | }); 42 | 43 | describe('resolve', () => { 44 | test.each([ 45 | ['debug = true', false, 'debug = true', null], 46 | [`notfound.toml`, true, '', new Error('config file notfound.toml not found')], 47 | [ 48 | `${path.join(fixturesDir, 'buildkitd.toml')}`, 49 | true, 50 | `debug = true 51 | [registry."docker.io"] 52 | mirrors = ["mirror.gcr.io"] 53 | `, 54 | null 55 | ] 56 | ])('given %p config', async (val: string, file: boolean, exValue: string, error: Error | null) => { 57 | try { 58 | const buildkit = new BuildKit(); 59 | let config: string; 60 | if (file) { 61 | config = buildkit.config.resolveFromFile(val); 62 | } else { 63 | config = buildkit.config.resolveFromString(val); 64 | } 65 | expect(config).toEqual(tmpName); 66 | const configValue = fs.readFileSync(tmpName, 'utf-8'); 67 | expect(configValue).toEqual(exValue); 68 | } catch (e) { 69 | // eslint-disable-next-line jest/no-conditional-expect 70 | expect(e.message).toEqual(error?.message); 71 | } 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /hack/dockerfiles/license.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | # Copyright 2023 actions-toolkit authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | ARG ADDLICENSE_VERSION="v1.1.1" 18 | ARG ALPINE_VERSION="3.21" 19 | ARG GO_VERSION="1.23" 20 | ARG XX_VERSION="1.6.1" 21 | 22 | ARG LICENSE_HOLDER="actions-toolkit authors" 23 | ARG LICENSE_TYPE="apache" 24 | ARG LICENSE_FILES=".*\(Dockerfile\|Makefile\|\.js\|\.ts\|\.hcl\|\.sh|\.ps1\)" 25 | 26 | FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx 27 | 28 | FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base 29 | RUN apk add --no-cache cpio findutils git 30 | ENV CGO_ENABLED=0 31 | WORKDIR /src 32 | COPY --link --from=xx / / 33 | 34 | FROM base AS addlicense 35 | ARG ADDLICENSE_VERSION 36 | ARG TARGETPLATFORM 37 | RUN --mount=target=/root/.cache,type=cache \ 38 | --mount=type=cache,target=/go/pkg/mod </dev/null || { 39 | echo >&2 "Failed to get git revision, make sure --build-arg BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 is set when building from Git directly" 40 | exit 1 41 | } 42 | set -ex 43 | export PKG=sigs.k8s.io BUILDDATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") TREESTATE=$(if ! git diff --no-ext-diff --quiet --exit-code; then echo dirty; else echo clean; fi) VERSION=$(git describe --match 'v[0-9]*' --dirty='.m' --always --tags) COMMIT=$(git rev-parse HEAD)$(if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi); 44 | echo "-X \${PKG}/release-utils/version.gitVersion=\${VERSION} -X \${PKG}/release-utils/version.gitCommit=\${COMMIT} -X \${PKG}/release-utils/version.gitTreeState=\${TREESTATE} -X \${PKG}/release-utils/version.buildDate=\${BUILDDATE}" > /tmp/.ldflags; 45 | echo -n "\${VERSION}" > /tmp/.version; 46 | EOT 47 | 48 | FROM builder-base AS builder 49 | ARG TARGETPLATFORM 50 | RUN --mount=type=bind,target=. \\ 51 | --mount=type=cache,target=/root/.cache,id=cosign-$TARGETPLATFORM \\ 52 | --mount=source=/tmp/.ldflags,target=/tmp/.ldflags,from=version \\ 53 | --mount=type=cache,target=/go/pkg/mod < { 29 | it('extracts moby/moby-bin:26.1.5', async () => { 30 | const undock = new Undock(); 31 | await expect( 32 | (async () => { 33 | // prettier-ignore 34 | await undock.run({ 35 | source: 'moby/moby-bin:26.1.5', 36 | dist: tmpDir, 37 | all: true 38 | }); 39 | })() 40 | ).resolves.not.toThrow(); 41 | }, 500000); 42 | }); 43 | 44 | describe('isAvailable', () => { 45 | it('checks undock is available', async () => { 46 | const execSpy = jest.spyOn(Exec, 'getExecOutput'); 47 | const undock = new Undock(); 48 | await undock.isAvailable(); 49 | expect(execSpy).toHaveBeenCalledWith(`undock`, [], { 50 | silent: true, 51 | ignoreReturnCode: true 52 | }); 53 | }); 54 | }); 55 | 56 | describe('printVersion', () => { 57 | it('prints undock version', async () => { 58 | const execSpy = jest.spyOn(Exec, 'exec'); 59 | const undock = new Undock(); 60 | await undock.printVersion(); 61 | expect(execSpy).toHaveBeenCalledWith(`undock`, ['--version'], { 62 | failOnStdErr: false 63 | }); 64 | }); 65 | }); 66 | 67 | describe('version', () => { 68 | it('valid', async () => { 69 | const undock = new Undock(); 70 | expect(semver.valid(await undock.version())).not.toBeUndefined(); 71 | }); 72 | }); 73 | 74 | describe('versionSatisfies', () => { 75 | test.each([ 76 | ['v0.4.1', '>=0.3.2', true], 77 | ['v0.8.0', '>0.6.0', true], 78 | ['v0.8.0', '<0.3.0', false] 79 | ])('given %p', async (version, range, expected) => { 80 | const undock = new Undock(); 81 | expect(await undock.versionSatisfies(range, version)).toBe(expected); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /src/types/buildkit/ops.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/pb/ops.pb.go#L1901-L1909 18 | export interface Definition { 19 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 20 | def?: Array; 21 | metadata: Record; 22 | Source?: Source; 23 | } 24 | 25 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/pb/ops.pb.go#L1313-L1323 26 | export interface OpMetadata { 27 | ignore_cache?: boolean; 28 | description?: Record; 29 | export_cache?: ExportCache; 30 | caps: Record; 31 | progress_group?: ProgressGroup; 32 | } 33 | 34 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/pb/ops.pb.go#L1390-L1393 35 | export interface Source { 36 | locations?: Record; 37 | infos?: Array; 38 | } 39 | 40 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/pb/ops.pb.go#L1439-L1441 41 | export interface Locations { 42 | locations?: Array; 43 | } 44 | 45 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/pb/ops.pb.go#L1545-L1548 46 | export interface Location { 47 | sourceIndex?: number; 48 | ranges?: Array; 49 | } 50 | 51 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/pb/ops.pb.go#L1594-L1597 52 | export interface Range { 53 | start: Position; 54 | end: Position; 55 | } 56 | 57 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/pb/ops.pb.go#L1643-L1646 58 | export interface Position { 59 | line: number; 60 | character: number; 61 | } 62 | 63 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/pb/ops.pb.go#L1480-L1485 64 | export interface SourceInfo { 65 | filename?: string; 66 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 67 | data?: any; 68 | definition?: Definition; 69 | language?: string; 70 | } 71 | 72 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/pb/ops.pb.go#L1691-L1693 73 | export interface ExportCache { 74 | Value?: boolean; 75 | } 76 | 77 | // https://github.com/moby/buildkit/blob/v0.14.0/solver/pb/ops.pb.go#L1731-L1735 78 | export interface ProgressGroup { 79 | id?: string; 80 | name?: string; 81 | weak?: boolean; 82 | } 83 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* eslint-disable @typescript-eslint/no-require-imports */ 18 | const {defineConfig, globalIgnores} = require('eslint/config'); 19 | const {fixupConfigRules, fixupPluginRules} = require('@eslint/compat'); 20 | const typescriptEslint = require('@typescript-eslint/eslint-plugin'); 21 | const jestPlugin = require('eslint-plugin-jest'); 22 | const prettier = require('eslint-plugin-prettier'); 23 | const globals = require('globals'); 24 | const tsParser = require('@typescript-eslint/parser'); 25 | const js = require('@eslint/js'); 26 | const {FlatCompat} = require('@eslint/eslintrc'); 27 | 28 | // __dirname and __filename exist natively in CommonJS 29 | const compat = new FlatCompat({ 30 | baseDirectory: __dirname, 31 | recommendedConfig: js.configs.recommended, 32 | allConfig: js.configs.all 33 | }); 34 | 35 | module.exports = defineConfig([ 36 | globalIgnores(['.yarn/**/*', 'lib/**/*', 'coverage/**/*', 'node_modules/**/*']), 37 | { 38 | extends: fixupConfigRules( 39 | compat.extends( 40 | 'eslint:recommended', 41 | 'plugin:@typescript-eslint/eslint-recommended', 42 | 'plugin:@typescript-eslint/recommended', 43 | 'plugin:import/errors', 44 | 'plugin:import/typescript', 45 | 'plugin:import/warnings', 46 | 'plugin:jest/recommended', 47 | 'plugin:prettier/recommended' 48 | ) 49 | ), 50 | 51 | plugins: { 52 | '@typescript-eslint': fixupPluginRules(typescriptEslint), 53 | jest: fixupPluginRules(jestPlugin), 54 | prettier: fixupPluginRules(prettier) 55 | }, 56 | 57 | languageOptions: { 58 | globals: { 59 | ...globals.node, 60 | ...globals.mocha, 61 | ...globals.jest 62 | }, 63 | parser: tsParser, 64 | ecmaVersion: 2023, 65 | sourceType: 'commonjs' 66 | }, 67 | 68 | rules: { 69 | '@typescript-eslint/no-require-imports': [ 70 | 'error', 71 | { 72 | allowAsImport: true 73 | } 74 | ], 75 | 'import/no-unresolved': [ 76 | 'error', 77 | { 78 | ignore: ['csv-parse/sync', '@octokit/openapi-types'] 79 | } 80 | ], 81 | 'jest/no-disabled-tests': 0 82 | } 83 | } 84 | ]); 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Version](https://img.shields.io/npm/v/@docker/actions-toolkit?label=version&logo=npm&style=flat-square)](https://www.npmjs.com/package/@docker/actions-toolkit) 2 | [![Downloads](https://img.shields.io/npm/dw/@docker/actions-toolkit?logo=npm&style=flat-square)](https://www.npmjs.com/package/@docker/actions-toolkit) 3 | [![Build workflow](https://img.shields.io/github/actions/workflow/status/docker/actions-toolkit/build.yml?label=build&logo=github&style=flat-square)](https://github.com/docker/actions-toolkit/actions?workflow=build) 4 | [![Test workflow](https://img.shields.io/github/actions/workflow/status/docker/actions-toolkit/test.yml?label=test&logo=github&style=flat-square)](https://github.com/docker/actions-toolkit/actions?workflow=test) 5 | [![Validate workflow](https://img.shields.io/github/actions/workflow/status/docker/actions-toolkit/validate.yml?label=validate&logo=github&style=flat-square)](https://github.com/docker/actions-toolkit/actions?workflow=validate) 6 | [![Codecov](https://img.shields.io/codecov/c/github/docker/actions-toolkit?logo=codecov&style=flat-square)](https://codecov.io/gh/docker/actions-toolkit) 7 | 8 | # Actions Toolkit 9 | 10 | Toolkit for Docker (GitHub) Actions. 11 | 12 | ## :test_tube: Experimental 13 | 14 | This repository is considered **EXPERIMENTAL** and under active development 15 | until further notice. It is subject to non-backward compatible changes or 16 | removal in any future version. 17 | 18 | ## About 19 | 20 | This repository contains the source code for the toolkit that is consumed as 21 | a library by most of our GitHub Actions: 22 | 23 | * [docker/bake-action](https://github.com/docker/bake-action) 24 | * [docker/build-push-action](https://github.com/docker/build-push-action) 25 | * [docker/login-action](https://github.com/docker/login-action) 26 | * [docker/metadata-action](https://github.com/docker/metadata-action) 27 | * [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) 28 | * [docker/setup-compose-action](https://github.com/docker/setup-compose-action) 29 | * [docker/setup-docker-action](https://github.com/docker/setup-docker-action) 30 | * [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) 31 | 32 | This toolkit provides some utilities and common logic when developing GitHub 33 | Actions and also acts as a minimal wrapper around our build tooling such as 34 | [Buildx](https://github.com/docker/buildx) and [BuildKit](https://github.com/moby/buildkit) 35 | and provides an easier API for interacting with them. 36 | 37 | ## Installation 38 | 39 | ```console 40 | $ npm install @docker/actions-toolkit 41 | ``` 42 | 43 | ## Usage 44 | 45 | ```js 46 | const { Toolkit } = require('@docker/actions-toolkit/lib/toolkit') 47 | const toolkit = new Toolkit() 48 | ``` 49 | 50 | ## Contributing 51 | 52 | Want to contribute to the Actions Toolkit? Awesome! You can find information 53 | about contributing to this project in the [CONTRIBUTING.md](/.github/CONTRIBUTING.md) 54 | -------------------------------------------------------------------------------- /src/types/docker/docker.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // https://github.com/docker/cli/blob/master/cli/config/configfile/file.go 18 | export interface ConfigFile { 19 | auths: Record; 20 | HttpHeaders?: Record; 21 | psFormat?: string; 22 | imagesFormat?: string; 23 | networksFormat?: string; 24 | pluginsFormat?: string; 25 | volumesFormat?: string; 26 | statsFormat?: string; 27 | detachKeys?: string; 28 | credsStore?: string; 29 | credHelpers?: Record; 30 | serviceInspectFormat?: string; 31 | servicesFormat?: string; 32 | tasksFormat?: string; 33 | secretFormat?: string; 34 | configFormat?: string; 35 | nodesFormat?: string; 36 | pruneFilters?: string[]; 37 | proxies?: Record; 38 | experimental?: string; 39 | stackOrchestrator?: string; 40 | kubernetes?: KubernetesConfig; 41 | currentContext?: string; 42 | cliPluginsExtraDirs?: string[]; 43 | plugins?: Record>; 44 | aliases?: Record; 45 | } 46 | 47 | export interface ProxyConfig { 48 | httpProxy?: string; 49 | httpsProxy?: string; 50 | noProxy?: string; 51 | ftpProxy?: string; 52 | } 53 | 54 | export interface KubernetesConfig { 55 | allNamespaces?: string; 56 | } 57 | 58 | export interface AuthConfig { 59 | username?: string; 60 | password?: string; 61 | auth?: string; 62 | email?: string; 63 | serveraddress?: string; 64 | identitytoken?: string; 65 | registrytoken?: string; 66 | } 67 | 68 | export interface ContextInfo { 69 | Name: string; 70 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 71 | Metadata: any; 72 | Endpoints: Record; 73 | TLSMaterial: Record>; 74 | Storage: StorageInfo; 75 | } 76 | 77 | export interface EndpointInfo { 78 | Host?: string; 79 | SkipVerify: boolean; 80 | TLSData?: TLSData; 81 | } 82 | 83 | export interface TLSData { 84 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 85 | CA: any; 86 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 87 | Key: any; 88 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 89 | Cert: any; 90 | } 91 | 92 | export interface StorageInfo { 93 | MetadataPath: string; 94 | TLSPath: string; 95 | } 96 | -------------------------------------------------------------------------------- /__tests__/.fixtures/imagetools-05.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "mediaType":"application/vnd.oci.image.manifest.v1+json", 4 | "digest":"sha256:2ba4ad6eae1efcafee73a971953093c7c32b6938f2f9fd4998c8bf4d0fbe76f2", 5 | "size":1113, 6 | "annotations":{ 7 | "vnd.docker.reference.digest":"sha256:dccc69dd895968c4f21aa9e43e715f25f0cedfce4b17f1014c88c307928e22fc", 8 | "vnd.docker.reference.type":"attestation-manifest" 9 | }, 10 | "platform":{ 11 | "architecture":"unknown", 12 | "os":"unknown" 13 | } 14 | }, 15 | { 16 | "mediaType":"application/vnd.oci.image.manifest.v1+json", 17 | "digest":"sha256:0709528fae1747ce17638ad2978ee7936b38a294136eaadaf692e415f64b1e03", 18 | "size":1113, 19 | "annotations":{ 20 | "vnd.docker.reference.digest":"sha256:1b6bce668653f08e2d0f9f7c9b646675b2cbce94ce8abdf4eb0eabaef4353045", 21 | "vnd.docker.reference.type":"attestation-manifest" 22 | }, 23 | "platform":{ 24 | "architecture":"unknown", 25 | "os":"unknown" 26 | } 27 | }, 28 | { 29 | "mediaType":"application/vnd.oci.image.manifest.v1+json", 30 | "digest":"sha256:241b7159129d53923c89708bcc052b3398086a826519896be2f025545916e43e", 31 | "size":1113, 32 | "annotations":{ 33 | "vnd.docker.reference.digest":"sha256:8f251fda6057e9dffc54f7874b249920f15f1813e9b1406a0cebeca5e4ab1ad9", 34 | "vnd.docker.reference.type":"attestation-manifest" 35 | }, 36 | "platform":{ 37 | "architecture":"unknown", 38 | "os":"unknown" 39 | } 40 | }, 41 | { 42 | "mediaType":"application/vnd.oci.image.manifest.v1+json", 43 | "digest":"sha256:97f4a222a7992dba6dc1a43991d0cca1fcffdc25593033c6a3a7ff14c8651cbf", 44 | "size":1113, 45 | "annotations":{ 46 | "vnd.docker.reference.digest":"sha256:d306cbc2d506547f136c8e0ea040b929743f298fb2813d9030efdb9d9eee4d51", 47 | "vnd.docker.reference.type":"attestation-manifest" 48 | }, 49 | "platform":{ 50 | "architecture":"unknown", 51 | "os":"unknown" 52 | } 53 | }, 54 | { 55 | "mediaType":"application/vnd.oci.image.manifest.v1+json", 56 | "digest":"sha256:aa933713d8094b2708120e889acb6f7153dee4e0f3298ccd3e37a584cd0c260d", 57 | "size":1113, 58 | "annotations":{ 59 | "vnd.docker.reference.digest":"sha256:9d195ff2dc9ef347bb52ebb1c2a6e6587d4bd87019d2ea11df3e7046a3d19708", 60 | "vnd.docker.reference.type":"attestation-manifest" 61 | }, 62 | "platform":{ 63 | "architecture":"unknown", 64 | "os":"unknown" 65 | } 66 | }, 67 | { 68 | "mediaType":"application/vnd.oci.image.manifest.v1+json", 69 | "digest":"sha256:d95ca72d4f2a6bc416d4b2f3003b2af9d5f4dea99acec6ad3ab0c2082000a98c", 70 | "size":1113, 71 | "annotations":{ 72 | "vnd.docker.reference.digest":"sha256:72410c2c4529fca9339ebbcc8db2a1d5cb4d72d72c669f50b6d45d8a0f79fc22", 73 | "vnd.docker.reference.type":"attestation-manifest" 74 | }, 75 | "platform":{ 76 | "architecture":"unknown", 77 | "os":"unknown" 78 | } 79 | } 80 | ] 81 | -------------------------------------------------------------------------------- /__tests__/context.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, jest, it, afterEach, beforeEach, test} from '@jest/globals'; 18 | import fs from 'fs'; 19 | import os from 'os'; 20 | import path from 'path'; 21 | import * as rimraf from 'rimraf'; 22 | 23 | import {Context} from '../src/context'; 24 | 25 | const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'context-')); 26 | const tmpName = path.join(tmpDir, '.tmpname-jest'); 27 | 28 | jest.spyOn(Context, 'tmpDir').mockImplementation((): string => { 29 | fs.mkdirSync(tmpDir, {recursive: true}); 30 | return tmpDir; 31 | }); 32 | 33 | jest.spyOn(Context, 'tmpName').mockImplementation((): string => { 34 | return tmpName; 35 | }); 36 | 37 | afterEach(() => { 38 | rimraf.sync(tmpDir); 39 | }); 40 | 41 | describe('gitRef', () => { 42 | it('returns refs/heads/master', async () => { 43 | expect(Context.gitRef()).toEqual('refs/heads/master'); 44 | }); 45 | }); 46 | 47 | describe('parseGitRef', () => { 48 | const originalEnv = process.env; 49 | beforeEach(() => { 50 | jest.resetModules(); 51 | process.env = { 52 | ...originalEnv, 53 | DOCKER_GIT_CONTEXT_PR_HEAD_REF: '' 54 | }; 55 | }); 56 | afterEach(() => { 57 | process.env = originalEnv; 58 | }); 59 | // prettier-ignore 60 | test.each([ 61 | ['refs/heads/master', '860c1904a1ce19322e91ac35af1ab07466440c37', false, '860c1904a1ce19322e91ac35af1ab07466440c37'], 62 | ['master', '860c1904a1ce19322e91ac35af1ab07466440c37', false, '860c1904a1ce19322e91ac35af1ab07466440c37'], 63 | ['refs/pull/15/merge', '860c1904a1ce19322e91ac35af1ab07466440c37', false, 'refs/pull/15/merge'], 64 | ['refs/heads/master', '', false, 'refs/heads/master'], 65 | ['master', '', false, 'master'], 66 | ['refs/tags/v1.0.0', '', false, 'refs/tags/v1.0.0'], 67 | ['refs/pull/15/merge', '', false, 'refs/pull/15/merge'], 68 | ['refs/pull/15/merge', '', true, 'refs/pull/15/head'], 69 | ])('given %p and %p, should return %p', async (ref: string, sha: string, prHeadRef: boolean, expected: string) => { 70 | process.env.DOCKER_DEFAULT_GIT_CONTEXT_PR_HEAD_REF = prHeadRef ? 'true' : ''; 71 | expect(Context.parseGitRef(ref, sha)).toEqual(expected); 72 | }); 73 | }); 74 | 75 | describe('gitContext', () => { 76 | it('returns refs/heads/master', async () => { 77 | expect(Context.gitContext()).toEqual('https://github.com/docker/actions-toolkit.git#refs/heads/master'); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /src/types/dockerhub.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export interface TokenRequest { 18 | username: string; 19 | password: string; 20 | } 21 | 22 | export interface TokenResponse { 23 | token: string; 24 | detail: string; 25 | } 26 | 27 | export interface RepositoryRequest { 28 | namespace: string; 29 | name: string; 30 | } 31 | 32 | export interface RepositoryResponse { 33 | user: string; 34 | name: string; 35 | namespace: string; 36 | repository_type: string; 37 | status: number; 38 | status_description: string; 39 | description: string; 40 | is_private: boolean; 41 | is_automated: boolean; 42 | can_edit: boolean; 43 | star_count: number; 44 | pull_count: number; 45 | last_updated: string; 46 | date_registered: string; 47 | collaborator_count: number; 48 | affiliation: string; 49 | hub_user: string; 50 | has_starred: boolean; 51 | full_description: string; 52 | permissions: { 53 | read: boolean; 54 | write: boolean; 55 | admin: boolean; 56 | }; 57 | media_types: Array; 58 | content_types: Array; 59 | } 60 | 61 | export interface RepositoryTagsRequest { 62 | namespace: string; 63 | name: string; 64 | page?: number; 65 | page_size?: number; 66 | } 67 | 68 | export interface RepositoryTagsResponse { 69 | count: number; 70 | next?: string; 71 | previous?: string; 72 | results: Array; 73 | } 74 | 75 | export interface RepositoryTagsResult { 76 | creator: number; 77 | id: number; 78 | images: Array; 79 | last_updated: Date; 80 | last_updater: number; 81 | last_updater_username: string; 82 | name: string; 83 | repository: number; 84 | full_size: number; 85 | v2: boolean; 86 | tag_status: string; 87 | tag_last_pulled: Date; 88 | tag_last_pushed: Date; 89 | media_type: string; 90 | content_type: string; 91 | digest: string; 92 | } 93 | 94 | export interface RepositoryTagsResultImage { 95 | architecture: string; 96 | features: string; 97 | variant?: string; 98 | digest: string; 99 | os: string; 100 | os_features: string; 101 | os_version?: string; 102 | size: number; 103 | status: string; 104 | last_pulled: Date; 105 | last_pushed: Date; 106 | } 107 | 108 | export interface UpdateRepoDescriptionRequest { 109 | name: string; 110 | namespace: string; 111 | description?: string; 112 | full_description: string; 113 | } 114 | -------------------------------------------------------------------------------- /docker-bake.hcl: -------------------------------------------------------------------------------- 1 | // Copyright 2023 actions-toolkit authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | variable "NODE_VERSION" { 16 | default = null 17 | } 18 | 19 | group "default" { 20 | targets = ["build"] 21 | } 22 | 23 | group "pre-checkin" { 24 | targets = ["vendor", "format", "build"] 25 | } 26 | 27 | group "validate" { 28 | targets = ["lint", "vendor-validate", "dockerfile-validate", "license-validate"] 29 | } 30 | 31 | target "_common" { 32 | args = { 33 | BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1 34 | NODE_VERSION = NODE_VERSION 35 | } 36 | } 37 | 38 | target "build" { 39 | inherits = ["_common"] 40 | dockerfile = "dev.Dockerfile" 41 | target = "build-update" 42 | output = ["."] 43 | } 44 | 45 | target "format" { 46 | inherits = ["_common"] 47 | dockerfile = "dev.Dockerfile" 48 | target = "format-update" 49 | output = ["."] 50 | } 51 | 52 | target "lint" { 53 | inherits = ["_common"] 54 | dockerfile = "dev.Dockerfile" 55 | target = "lint" 56 | output = ["type=cacheonly"] 57 | } 58 | 59 | target "vendor" { 60 | inherits = ["_common"] 61 | dockerfile = "dev.Dockerfile" 62 | target = "vendor-update" 63 | output = ["."] 64 | } 65 | 66 | target "vendor-validate" { 67 | inherits = ["_common"] 68 | dockerfile = "dev.Dockerfile" 69 | target = "vendor-validate" 70 | output = ["type=cacheonly"] 71 | } 72 | 73 | target "dockerfile-validate" { 74 | matrix = { 75 | dockerfile = [ 76 | "dev.Dockerfile", 77 | "./hack/dockerfiles/license.Dockerfile" 78 | ] 79 | } 80 | inherits = ["_common"] 81 | name = "dockerfile-validate-${md5(dockerfile)}" 82 | dockerfile = dockerfile 83 | call = "check" 84 | } 85 | 86 | target "test" { 87 | inherits = ["_common"] 88 | dockerfile = "dev.Dockerfile" 89 | target = "test" 90 | output = ["type=cacheonly"] 91 | secret = ["id=GITHUB_TOKEN,env=GITHUB_TOKEN"] 92 | } 93 | 94 | target "test-coverage" { 95 | inherits = ["_common"] 96 | dockerfile = "dev.Dockerfile" 97 | target = "test-coverage" 98 | output = ["./coverage"] 99 | secret = ["id=GITHUB_TOKEN,env=GITHUB_TOKEN"] 100 | } 101 | 102 | target "license-validate" { 103 | inherits = ["_common"] 104 | dockerfile = "./hack/dockerfiles/license.Dockerfile" 105 | target = "validate" 106 | output = ["type=cacheonly"] 107 | } 108 | 109 | target "license-update" { 110 | inherits = ["_common"] 111 | dockerfile = "./hack/dockerfiles/license.Dockerfile" 112 | target = "update" 113 | output = ["."] 114 | } 115 | -------------------------------------------------------------------------------- /src/toolkit.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {GitHub} from './github'; 18 | import {Buildx} from './buildx/buildx'; 19 | import {Build as BuildxBuild} from './buildx/build'; 20 | import {Bake as BuildxBake} from './buildx/bake'; 21 | import {Install as BuildxInstall} from './buildx/install'; 22 | import {Builder} from './buildx/builder'; 23 | import {BuildKit} from './buildkit/buildkit'; 24 | import {Compose} from './compose/compose'; 25 | import {Install as ComposeInstall} from './compose/install'; 26 | import {Cosign} from './cosign/cosign'; 27 | import {Install as CosignInstall} from './cosign/install'; 28 | import {Regctl} from './regclient/regctl'; 29 | import {Install as RegctlInstall} from './regclient/install'; 30 | import {Undock} from './undock/undock'; 31 | import {Install as UndockInstall} from './undock/install'; 32 | import {Sigstore} from './sigstore/sigstore'; 33 | 34 | export interface ToolkitOpts { 35 | /** 36 | * GitHub token to use for authentication. 37 | * Uses `process.env.GITHUB_TOKEN` by default. 38 | */ 39 | githubToken?: string; 40 | } 41 | 42 | export class Toolkit { 43 | public github: GitHub; 44 | public buildx: Buildx; 45 | public buildxBuild: BuildxBuild; 46 | public buildxBake: BuildxBake; 47 | public buildxInstall: BuildxInstall; 48 | public builder: Builder; 49 | public buildkit: BuildKit; 50 | public compose: Compose; 51 | public composeInstall: ComposeInstall; 52 | public cosign: Cosign; 53 | public cosignInstall: CosignInstall; 54 | public regctl: Regctl; 55 | public regctlInstall: RegctlInstall; 56 | public sigstore: Sigstore; 57 | public undock: Undock; 58 | public undockInstall: UndockInstall; 59 | 60 | constructor(opts: ToolkitOpts = {}) { 61 | this.github = new GitHub({token: opts.githubToken}); 62 | this.buildx = new Buildx(); 63 | this.buildxBuild = new BuildxBuild({buildx: this.buildx}); 64 | this.buildxBake = new BuildxBake({buildx: this.buildx}); 65 | this.buildxInstall = new BuildxInstall(); 66 | this.builder = new Builder({buildx: this.buildx}); 67 | this.buildkit = new BuildKit({buildx: this.buildx}); 68 | this.compose = new Compose(); 69 | this.composeInstall = new ComposeInstall(); 70 | this.cosign = new Cosign(); 71 | this.cosignInstall = new CosignInstall({buildx: this.buildx}); 72 | this.regctl = new Regctl(); 73 | this.regctlInstall = new RegctlInstall(); 74 | this.sigstore = new Sigstore(); 75 | this.undock = new Undock(); 76 | this.undockInstall = new UndockInstall(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /__tests__/cosign/cosign.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, it, jest, test} from '@jest/globals'; 18 | import fs from 'fs'; 19 | import path from 'path'; 20 | import * as semver from 'semver'; 21 | 22 | import {Exec} from '../../src/exec'; 23 | import {Cosign} from '../../src/cosign/cosign'; 24 | 25 | const fixturesDir = path.join(__dirname, '..', '.fixtures'); 26 | 27 | describe('isAvailable', () => { 28 | it('checks Cosign is available', async () => { 29 | const execSpy = jest.spyOn(Exec, 'getExecOutput'); 30 | const cosign = new Cosign(); 31 | await cosign.isAvailable(); 32 | expect(execSpy).toHaveBeenCalledWith(`cosign`, [], { 33 | silent: true, 34 | ignoreReturnCode: true 35 | }); 36 | }); 37 | }); 38 | 39 | describe('printVersion', () => { 40 | it('prints Cosign version', async () => { 41 | const execSpy = jest.spyOn(Exec, 'exec'); 42 | const cosign = new Cosign(); 43 | await cosign.printVersion(); 44 | expect(execSpy).toHaveBeenCalledWith(`cosign`, ['version', '--json'], { 45 | failOnStdErr: false 46 | }); 47 | }); 48 | }); 49 | 50 | describe('version', () => { 51 | it('valid', async () => { 52 | const cosign = new Cosign(); 53 | expect(semver.valid(await cosign.version())).not.toBeUndefined(); 54 | }); 55 | }); 56 | 57 | describe('versionSatisfies', () => { 58 | test.each([ 59 | ['v0.4.1', '>=0.3.2', true], 60 | ['v0.8.0', '>0.6.0', true], 61 | ['v0.8.0', '<0.3.0', false] 62 | ])('given %p', async (version, range, expected) => { 63 | const cosign = new Cosign(); 64 | expect(await cosign.versionSatisfies(range, version)).toBe(expected); 65 | }); 66 | }); 67 | 68 | describe('parseCommandOutput', () => { 69 | // prettier-ignore 70 | test.each([ 71 | [path.join(fixturesDir, 'cosign', 'sign-output1.txt')], 72 | [path.join(fixturesDir, 'cosign', 'sign-output2.txt')], 73 | [path.join(fixturesDir, 'cosign', 'sign-output3.txt')], 74 | ])('parsing %p', async (fixturePath: string) => { 75 | const signResult = Cosign.parseCommandOutput(fs.readFileSync(fixturePath, 'utf-8')); 76 | expect(signResult).toBeDefined(); 77 | expect(signResult.bundle).toBeDefined(); 78 | }); 79 | 80 | // prettier-ignore 81 | test.each([ 82 | [path.join(fixturesDir, 'cosign', 'verify-output-err1.txt')], 83 | ])('parsing %p', async (fixturePath: string) => { 84 | const signResult = Cosign.parseCommandOutput(fs.readFileSync(fixturePath, 'utf-8')); 85 | expect(signResult).toBeDefined(); 86 | expect(signResult.bundle).toBeUndefined(); 87 | expect(signResult.errors).toBeDefined(); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@docker/actions-toolkit", 3 | "version": "0.0.0+unknown", 4 | "description": "Toolkit for Docker (GitHub) Actions", 5 | "scripts": { 6 | "build": "tsc", 7 | "lint": "yarn run prettier && yarn run eslint", 8 | "format": "yarn run prettier:fix && yarn run eslint:fix", 9 | "eslint": "eslint --max-warnings=0 .", 10 | "eslint:fix": "eslint --fix .", 11 | "prettier": "prettier --check \"./**/*.ts\"", 12 | "prettier:fix": "prettier --write \"./**/*.ts\"", 13 | "test": "jest", 14 | "test:coverage": "jest --coverage", 15 | "test:itg": "jest -c jest.config.itg.js --runInBand", 16 | "test:itg-list": "jest -c jest.config.itg.js --listTests", 17 | "test:itg-coverage": "jest -c jest.config.itg.js --coverage --runInBand" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/docker/actions-toolkit.git" 22 | }, 23 | "keywords": [ 24 | "github", 25 | "actions", 26 | "docker", 27 | "build", 28 | "buildx", 29 | "buildkit" 30 | ], 31 | "author": "Docker Inc.", 32 | "license": "Apache-2.0", 33 | "packageManager": "yarn@4.9.2", 34 | "main": "lib/index.js", 35 | "types": "lib/index.d.ts", 36 | "directories": { 37 | "lib": "lib", 38 | "test": "__tests__" 39 | }, 40 | "files": [ 41 | "lib" 42 | ], 43 | "publishConfig": { 44 | "access": "public", 45 | "registry": "https://registry.npmjs.org/" 46 | }, 47 | "dependencies": { 48 | "@actions/artifact": "^5.0.1", 49 | "@actions/cache": "^5.0.1", 50 | "@actions/core": "^2.0.1", 51 | "@actions/exec": "^2.0.0", 52 | "@actions/github": "^6.0.1", 53 | "@actions/http-client": "^3.0.0", 54 | "@actions/io": "^2.0.0", 55 | "@actions/tool-cache": "^2.0.2", 56 | "@azure/storage-blob": "^12.29.1", 57 | "@octokit/core": "^5.2.2", 58 | "@octokit/plugin-rest-endpoint-methods": "^10.4.1", 59 | "@sigstore/bundle": "^4.0.0", 60 | "@sigstore/sign": "^4.0.1", 61 | "@sigstore/tuf": "^4.0.0", 62 | "@sigstore/verify": "^3.0.0", 63 | "async-retry": "^1.3.3", 64 | "csv-parse": "^6.1.0", 65 | "gunzip-maybe": "^1.4.2", 66 | "handlebars": "^4.7.8", 67 | "he": "^1.2.0", 68 | "js-yaml": "^4.1.1", 69 | "jwt-decode": "^4.0.0", 70 | "semver": "^7.7.3", 71 | "tar-stream": "^3.1.7", 72 | "tmp": "^0.2.5" 73 | }, 74 | "devDependencies": { 75 | "@eslint/compat": "^2.0.0", 76 | "@eslint/eslintrc": "^3.3.3", 77 | "@eslint/js": "^9.39.2", 78 | "@sigstore/rekor-types": "^3.0.0", 79 | "@types/gunzip-maybe": "^1.4.3", 80 | "@types/he": "^1.2.3", 81 | "@types/js-yaml": "^4.0.9", 82 | "@types/node": "^20.19.27", 83 | "@types/semver": "^7.7.1", 84 | "@types/tar-stream": "^3.1.4", 85 | "@types/tmp": "^0.2.6", 86 | "@typescript-eslint/eslint-plugin": "^8.50.0", 87 | "@typescript-eslint/parser": "^8.50.0", 88 | "dotenv": "^17.2.3", 89 | "eslint": "^9.39.2", 90 | "eslint-config-prettier": "^10.1.8", 91 | "eslint-plugin-import": "^2.32.0", 92 | "eslint-plugin-jest": "^29.5.0", 93 | "eslint-plugin-prettier": "^5.5.4", 94 | "jest": "^30.2.0", 95 | "prettier": "^3.7.4", 96 | "rimraf": "^6.1.2", 97 | "ts-jest": "^29.4.6", 98 | "ts-node": "^10.9.2", 99 | "typescript": "^5.9.3" 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/compose/compose.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as core from '@actions/core'; 18 | 19 | import {Docker} from '../docker/docker'; 20 | import {Exec} from '../exec'; 21 | 22 | export interface ComposeOpts { 23 | standalone?: boolean; 24 | } 25 | 26 | export class Compose { 27 | private _version: string; 28 | private _versionOnce: boolean; 29 | private readonly _standalone: boolean | undefined; 30 | 31 | constructor(opts?: ComposeOpts) { 32 | this._standalone = opts?.standalone; 33 | this._version = ''; 34 | this._versionOnce = false; 35 | } 36 | 37 | public async isStandalone(): Promise { 38 | const standalone = this._standalone ?? !(await Docker.isAvailable()); 39 | core.debug(`Compose.isStandalone: ${standalone}`); 40 | return standalone; 41 | } 42 | 43 | public async getCommand(args: Array) { 44 | const standalone = await this.isStandalone(); 45 | return { 46 | command: standalone ? 'compose' : 'docker', 47 | args: standalone ? args : ['compose', ...args] 48 | }; 49 | } 50 | 51 | public async isAvailable(): Promise { 52 | const cmd = await this.getCommand([]); 53 | 54 | const ok: boolean = await Exec.getExecOutput(cmd.command, cmd.args, { 55 | ignoreReturnCode: true, 56 | silent: true 57 | }) 58 | .then(res => { 59 | if (res.stderr.length > 0 && res.exitCode != 0) { 60 | core.debug(`Compose.isAvailable cmd err: ${res.stderr.trim()}`); 61 | return false; 62 | } 63 | return res.exitCode == 0; 64 | }) 65 | .catch(error => { 66 | core.debug(`Compose.isAvailable error: ${error}`); 67 | return false; 68 | }); 69 | 70 | core.debug(`Compose.isAvailable: ${ok}`); 71 | return ok; 72 | } 73 | 74 | public async version(): Promise { 75 | if (this._versionOnce) { 76 | return this._version; 77 | } 78 | this._versionOnce = true; 79 | const cmd = await this.getCommand(['version']); 80 | this._version = await Exec.getExecOutput(cmd.command, cmd.args, { 81 | ignoreReturnCode: true, 82 | silent: true 83 | }).then(res => { 84 | if (res.stderr.length > 0 && res.exitCode != 0) { 85 | throw new Error(res.stderr.trim()); 86 | } 87 | return Compose.parseVersion(res.stdout.trim()); 88 | }); 89 | return this._version; 90 | } 91 | 92 | public async printVersion() { 93 | const cmd = await this.getCommand(['version']); 94 | await Exec.exec(cmd.command, cmd.args, { 95 | failOnStdErr: false 96 | }); 97 | } 98 | 99 | public static parseVersion(stdout: string): string { 100 | const matches = /\sv?([0-9a-f]{7}|[0-9.]+)/.exec(stdout); 101 | if (!matches) { 102 | throw new Error(`Cannot parse compose version`); 103 | } 104 | return matches[1]; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /__tests__/compose/compose.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, it, jest, test, afterEach} from '@jest/globals'; 18 | import fs from 'fs'; 19 | import os from 'os'; 20 | import path from 'path'; 21 | import * as rimraf from 'rimraf'; 22 | import * as semver from 'semver'; 23 | 24 | import {Context} from '../../src/context'; 25 | import {Exec} from '../../src/exec'; 26 | 27 | import {Compose} from '../../src/compose/compose'; 28 | 29 | const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'compose-compose-')); 30 | const tmpName = path.join(tmpDir, '.tmpname-jest'); 31 | 32 | jest.spyOn(Context, 'tmpDir').mockImplementation((): string => { 33 | fs.mkdirSync(tmpDir, {recursive: true}); 34 | return tmpDir; 35 | }); 36 | 37 | jest.spyOn(Context, 'tmpName').mockImplementation((): string => { 38 | return tmpName; 39 | }); 40 | 41 | afterEach(() => { 42 | rimraf.sync(tmpDir); 43 | }); 44 | 45 | describe('isAvailable', () => { 46 | it('docker cli', async () => { 47 | const execSpy = jest.spyOn(Exec, 'getExecOutput'); 48 | const compose = new Compose({ 49 | standalone: false 50 | }); 51 | await compose.isAvailable(); 52 | expect(execSpy).toHaveBeenCalledWith(`docker`, ['compose'], { 53 | silent: true, 54 | ignoreReturnCode: true 55 | }); 56 | }); 57 | it('standalone', async () => { 58 | const execSpy = jest.spyOn(Exec, 'getExecOutput'); 59 | const compose = new Compose({ 60 | standalone: true 61 | }); 62 | await compose.isAvailable(); 63 | expect(execSpy).toHaveBeenCalledWith(`compose`, [], { 64 | silent: true, 65 | ignoreReturnCode: true 66 | }); 67 | }); 68 | }); 69 | 70 | describe('printVersion', () => { 71 | it('docker cli', async () => { 72 | const execSpy = jest.spyOn(Exec, 'exec'); 73 | const compose = new Compose({ 74 | standalone: false 75 | }); 76 | await compose.printVersion(); 77 | expect(execSpy).toHaveBeenCalledWith(`docker`, ['compose', 'version'], { 78 | failOnStdErr: false 79 | }); 80 | }); 81 | it('standalone', async () => { 82 | const execSpy = jest.spyOn(Exec, 'exec'); 83 | const compose = new Compose({ 84 | standalone: true 85 | }); 86 | await compose.printVersion(); 87 | expect(execSpy).toHaveBeenCalledWith(`compose`, ['version'], { 88 | failOnStdErr: false 89 | }); 90 | }); 91 | }); 92 | 93 | describe('version', () => { 94 | it('valid', async () => { 95 | const compose = new Compose(); 96 | expect(semver.valid(await compose.version())).not.toBeUndefined(); 97 | }); 98 | }); 99 | 100 | describe('parseVersion', () => { 101 | // prettier-ignore 102 | test.each([ 103 | ['Docker Compose version v2.31.0', '2.31.0'], 104 | ])('given %p', async (stdout, expected) => { 105 | expect(Compose.parseVersion(stdout)).toEqual(expected); 106 | }); 107 | }); 108 | -------------------------------------------------------------------------------- /src/types/buildx/history.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export interface InspectOpts { 18 | ref?: string; 19 | builder?: string; 20 | } 21 | 22 | export type BuildStatus = 'completed' | 'running' | 'failed' | 'canceled'; 23 | 24 | export interface InspectResponse { 25 | Name: string; 26 | Ref: string; 27 | 28 | Context?: string; 29 | Dockerfile?: string; 30 | VCSRepository?: string; 31 | VCSRevision?: string; 32 | Target?: string; 33 | Platform?: Array; 34 | KeepGitDir?: boolean; 35 | 36 | NamedContexts?: Array; 37 | 38 | StartedAt?: Date; 39 | CompletedAt?: Date; 40 | Duration: number; 41 | Status: BuildStatus; 42 | Error?: InspectErrorOutput; 43 | 44 | NumCompletedSteps: number; 45 | NumTotalSteps: number; 46 | NumCachedSteps: number; 47 | 48 | BuildArgs?: Array; 49 | Labels?: Array; 50 | 51 | Config?: InspectConfigOutput; 52 | 53 | Materials?: InspectMaterialOutput[]; 54 | Attachments?: InspectAttachmentOutput[]; 55 | 56 | Errors?: Array; 57 | } 58 | 59 | export interface InspectConfigOutput { 60 | Network?: string; 61 | ExtraHosts?: Array; 62 | Hostname?: string; 63 | CgroupParent?: string; 64 | ImageResolveMode?: string; 65 | MultiPlatform?: boolean; 66 | NoCache?: boolean; 67 | NoCacheFilter?: Array; 68 | 69 | ShmSize?: string; 70 | Ulimit?: string; 71 | CacheMountNS?: string; 72 | DockerfileCheckConfig?: string; 73 | SourceDateEpoch?: string; 74 | SandboxHostname?: string; 75 | 76 | RestRaw?: Array; 77 | } 78 | 79 | export interface InspectMaterialOutput { 80 | URI?: string; 81 | Digests?: Array; 82 | } 83 | 84 | export interface InspectAttachmentOutput { 85 | Digest?: string; 86 | Platform?: string; 87 | Type?: string; 88 | } 89 | 90 | export interface InspectErrorOutput { 91 | Code?: number; 92 | Message?: string; 93 | Name?: string; 94 | Logs?: Array; 95 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 96 | Sources?: any; 97 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 98 | Stack?: any; 99 | } 100 | 101 | export interface InspectKeyValueOutput { 102 | Name?: string; 103 | Value?: string; 104 | } 105 | 106 | export interface ExportOpts { 107 | refs: Array; 108 | noSummaries?: boolean; 109 | image?: string; 110 | useContainer?: boolean; 111 | } 112 | 113 | export interface ExportResponse { 114 | dockerbuildFilename: string; 115 | dockerbuildSize: number; 116 | builderName: string; 117 | nodeName: string; 118 | refs: Array; 119 | summaries?: Summaries; 120 | } 121 | 122 | export interface Summaries { 123 | [ref: string]: Summary; 124 | } 125 | 126 | export interface Summary { 127 | name: string; 128 | status: string; 129 | duration: string; 130 | numCachedSteps: number; 131 | numTotalSteps: number; 132 | numCompletedSteps: number; 133 | frontendAttrs?: Record; 134 | defaultPlatform?: string; 135 | error?: string; 136 | } 137 | -------------------------------------------------------------------------------- /src/types/buildkit/control.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Descriptor} from '../oci/descriptor'; 18 | import {Digest} from '../oci/digest'; 19 | import {ProgressGroup, Range, SourceInfo} from './ops'; 20 | import {RpcStatus} from './rpc'; 21 | 22 | // https://github.com/moby/buildkit/blob/v0.14.0/api/services/control/control.pb.go#L1504-L1525 23 | export interface BuildHistoryRecord { 24 | Ref: string; 25 | Frontend: string; 26 | FrontendAttrs: Record; 27 | Exporters: Array; 28 | error?: RpcStatus; 29 | CreatedAt?: Date; 30 | CompletedAt?: Date; 31 | logs?: Descriptor; 32 | ExporterResponse: Record; 33 | Result?: BuildResultInfo; 34 | Results: Record; 35 | Generation: number; 36 | trace?: Descriptor; 37 | pinned: boolean; 38 | numCachedSteps: number; 39 | numTotalSteps: number; 40 | numCompletedSteps: number; 41 | } 42 | 43 | // https://github.com/moby/buildkit/blob/v0.14.0/api/services/control/control.pb.go#L1909-L1917 44 | export interface Exporter { 45 | Type: string; 46 | Attrs: Record; 47 | } 48 | 49 | // https://github.com/moby/buildkit/blob/v0.14.0/api/services/control/control.pb.go#L1845-L1852 50 | export interface BuildResultInfo { 51 | ResultDeprecated?: Descriptor; 52 | Attestations?: Array; 53 | Results?: Record; 54 | } 55 | 56 | // https://github.com/moby/buildkit/blob/v0.14.0/api/services/control/control.pb.go#L751-L759 57 | export interface StatusResponse { 58 | vertexes?: Array; 59 | statuses?: Array; 60 | logs?: Array; 61 | warnings?: Array; 62 | } 63 | 64 | // https://github.com/moby/buildkit/blob/v0.14.0/api/services/control/control.pb.go#L822-L834 65 | export interface Vertex { 66 | digest: Digest; 67 | inputs: Array; 68 | name?: string; 69 | cached?: boolean; 70 | started?: Date; 71 | completed?: Date; 72 | error?: string; 73 | progressGroup?: ProgressGroup; 74 | } 75 | 76 | // https://github.com/moby/buildkit/blob/v0.14.0/api/services/control/control.pb.go#L911-L923 77 | export interface VertexStatus { 78 | ID?: string; 79 | vertex: Digest; 80 | name?: string; 81 | current?: number; 82 | total?: number; 83 | timestamp: Date; 84 | started?: Date; 85 | completed?: Date; 86 | } 87 | 88 | // https://github.com/moby/buildkit/blob/v0.14.0/api/services/control/control.pb.go#L1007-L1015 89 | export interface VertexLog { 90 | vertex: Digest; 91 | timestamp: Date; 92 | stream?: number; 93 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 94 | msg?: any; 95 | } 96 | 97 | // https://github.com/moby/buildkit/blob/v0.14.0/api/services/control/control.pb.go#L1071-L1082 98 | export interface VertexWarning { 99 | vertex: Digest; 100 | level?: number; 101 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 102 | short?: any; 103 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 104 | detail?: Array; 105 | url?: string; 106 | info?: SourceInfo; 107 | ranges?: Array; 108 | } 109 | -------------------------------------------------------------------------------- /src/buildx/imagetools.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Buildx} from './buildx'; 18 | import {Exec} from '../exec'; 19 | 20 | import {Manifest as ImageToolsManifest} from '../types/buildx/imagetools'; 21 | import {Image} from '../types/oci/config'; 22 | import {Descriptor} from '../types/oci/descriptor'; 23 | import {Digest} from '../types/oci/digest'; 24 | 25 | export interface ImageToolsOpts { 26 | buildx?: Buildx; 27 | } 28 | 29 | export class ImageTools { 30 | private readonly buildx: Buildx; 31 | 32 | constructor(opts?: ImageToolsOpts) { 33 | this.buildx = opts?.buildx || new Buildx(); 34 | } 35 | 36 | public async getCommand(args: Array) { 37 | return await this.buildx.getCommand(['imagetools', ...args]); 38 | } 39 | 40 | public async getInspectCommand(args: Array) { 41 | return await this.getCommand(['inspect', ...args]); 42 | } 43 | 44 | public async inspectImage(name: string): Promise | Image> { 45 | const cmd = await this.getInspectCommand([name, '--format', '{{json .Image}}']); 46 | return await Exec.getExecOutput(cmd.command, cmd.args, { 47 | ignoreReturnCode: true, 48 | silent: true 49 | }).then(res => { 50 | if (res.stderr.length > 0 && res.exitCode != 0) { 51 | throw new Error(res.stderr.trim()); 52 | } 53 | const parsedOutput = JSON.parse(res.stdout); 54 | if (typeof parsedOutput === 'object' && !Array.isArray(parsedOutput) && parsedOutput !== null) { 55 | if (Object.prototype.hasOwnProperty.call(parsedOutput, 'config')) { 56 | return parsedOutput; 57 | } else { 58 | return >parsedOutput; 59 | } 60 | } 61 | throw new Error('Unexpected output format'); 62 | }); 63 | } 64 | 65 | public async inspectManifest(name: string): Promise { 66 | const cmd = await this.getInspectCommand([name, '--format', '{{json .Manifest}}']); 67 | return await Exec.getExecOutput(cmd.command, cmd.args, { 68 | ignoreReturnCode: true, 69 | silent: true 70 | }).then(res => { 71 | if (res.stderr.length > 0 && res.exitCode != 0) { 72 | throw new Error(res.stderr.trim()); 73 | } 74 | const parsedOutput = JSON.parse(res.stdout); 75 | if (typeof parsedOutput === 'object' && !Array.isArray(parsedOutput) && parsedOutput !== null) { 76 | if (Object.prototype.hasOwnProperty.call(parsedOutput, 'manifests')) { 77 | return parsedOutput; 78 | } else { 79 | return parsedOutput; 80 | } 81 | } 82 | throw new Error('Unexpected output format'); 83 | }); 84 | } 85 | 86 | public async attestationDescriptors(name: string): Promise> { 87 | const manifest = await this.inspectManifest(name); 88 | if (typeof manifest === 'object' && manifest !== null && 'manifests' in manifest && Array.isArray(manifest.manifests)) { 89 | return manifest.manifests.filter(m => m.annotations && m.annotations['vnd.docker.reference.type'] === 'attestation-manifest'); 90 | } 91 | throw new Error(`No attestation descriptors found for ${name}`); 92 | } 93 | 94 | public async attestationDigests(name: string): Promise> { 95 | return (await this.attestationDescriptors(name)).map(attestation => attestation.digest); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /__tests__/sigstore/sigstore.test.itg.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {describe, expect, jest, it, beforeAll} from '@jest/globals'; 18 | import fs from 'fs'; 19 | import * as path from 'path'; 20 | 21 | import {Install as CosignInstall} from '../../src/cosign/install'; 22 | import {Sigstore} from '../../src/sigstore/sigstore'; 23 | 24 | const fixturesDir = path.join(__dirname, '..', '.fixtures'); 25 | 26 | const maybe = process.env.GITHUB_ACTIONS && process.env.GITHUB_ACTIONS === 'true' && process.env.ACTIONS_ID_TOKEN_REQUEST_URL && process.env.ImageOS && process.env.ImageOS.startsWith('ubuntu') ? describe : describe.skip; 27 | 28 | // needs current GitHub repo info 29 | jest.unmock('@actions/github'); 30 | 31 | beforeAll(async () => { 32 | const cosignInstall = new CosignInstall(); 33 | const cosignBinPath = await cosignInstall.download({ 34 | version: 'v3.0.2' 35 | }); 36 | await cosignInstall.install(cosignBinPath); 37 | }, 100000); 38 | 39 | maybe('signProvenanceBlobs', () => { 40 | it('single platform', async () => { 41 | const sigstore = new Sigstore(); 42 | const results = await sigstore.signProvenanceBlobs({ 43 | localExportDir: path.join(fixturesDir, 'sigstore', 'single') 44 | }); 45 | expect(Object.keys(results).length).toEqual(1); 46 | const provenancePath = Object.keys(results)[0]; 47 | expect(provenancePath).toEqual(path.join(fixturesDir, 'sigstore', 'single', 'provenance.json')); 48 | expect(fs.existsSync(results[provenancePath].bundlePath)).toBe(true); 49 | expect(results[provenancePath].payload).toBeDefined(); 50 | expect(results[provenancePath].certificate).toBeDefined(); 51 | expect(results[provenancePath].tlogID).toBeDefined(); 52 | console.log(provenancePath, JSON.stringify(results[provenancePath].payload, null, 2)); 53 | }); 54 | it('multi-platform', async () => { 55 | const sigstore = new Sigstore(); 56 | const results = await sigstore.signProvenanceBlobs({ 57 | localExportDir: path.join(fixturesDir, 'sigstore', 'multi') 58 | }); 59 | expect(Object.keys(results).length).toEqual(2); 60 | for (const [provenancePath, res] of Object.entries(results)) { 61 | expect(provenancePath).toMatch(/linux_(amd64|arm64)\/provenance.json/); 62 | expect(fs.existsSync(res.bundlePath)).toBe(true); 63 | expect(res.payload).toBeDefined(); 64 | expect(res.certificate).toBeDefined(); 65 | expect(res.tlogID).toBeDefined(); 66 | console.log(provenancePath, JSON.stringify(res.payload, null, 2)); 67 | } 68 | }); 69 | }); 70 | 71 | maybe('verifySignedArtifacts', () => { 72 | it('sign and verify', async () => { 73 | const sigstore = new Sigstore(); 74 | const signResults = await sigstore.signProvenanceBlobs({ 75 | localExportDir: path.join(fixturesDir, 'sigstore', 'multi') 76 | }); 77 | expect(Object.keys(signResults).length).toEqual(2); 78 | 79 | const verifyResults = await sigstore.verifySignedArtifacts( 80 | { 81 | certificateIdentityRegexp: `^https://github.com/docker/actions-toolkit/.github/workflows/test.yml.*$` 82 | }, 83 | signResults 84 | ); 85 | expect(Object.keys(verifyResults).length).toEqual(2); 86 | for (const [artifactPath, res] of Object.entries(verifyResults)) { 87 | expect(fs.existsSync(artifactPath)).toBe(true); 88 | expect(res.bundlePath).toBeDefined(); 89 | expect(res.cosignArgs).toBeDefined(); 90 | } 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /src/buildkit/buildkit.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 actions-toolkit authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import * as core from '@actions/core'; 18 | import * as semver from 'semver'; 19 | 20 | import {Buildx} from '../buildx/buildx'; 21 | import {Builder} from '../buildx/builder'; 22 | import {Docker} from '../docker/docker'; 23 | import {Config} from './config'; 24 | 25 | import {BuilderInfo, NodeInfo} from '../types/buildx/builder'; 26 | 27 | export interface BuildKitOpts { 28 | buildx?: Buildx; 29 | } 30 | 31 | export class BuildKit { 32 | private readonly buildx: Buildx; 33 | 34 | public readonly config: Config; 35 | 36 | constructor(opts?: BuildKitOpts) { 37 | this.config = new Config(); 38 | this.buildx = opts?.buildx || new Buildx(); 39 | } 40 | 41 | public async getVersion(node: NodeInfo): Promise { 42 | if (!node.buildkit && node.name) { 43 | try { 44 | return await this.getVersionWithinImage(node.name); 45 | } catch (e) { 46 | core.warning(e); 47 | } 48 | } 49 | return node.buildkit; 50 | } 51 | 52 | private async getVersionWithinImage(nodeName: string): Promise { 53 | core.debug(`BuildKit.getVersionWithinImage nodeName: ${nodeName}`); 54 | return Docker.getExecOutput(['inspect', '--format', '{{.Config.Image}}', `${Buildx.containerNamePrefix}${nodeName}`], { 55 | ignoreReturnCode: true, 56 | silent: true 57 | }).then(bkitimage => { 58 | if (bkitimage.exitCode == 0 && bkitimage.stdout.length > 0) { 59 | core.debug(`BuildKit.getVersionWithinImage image: ${bkitimage.stdout.trim()}`); 60 | return Docker.getExecOutput(['run', '--rm', bkitimage.stdout.trim(), '--version'], { 61 | ignoreReturnCode: true, 62 | silent: true 63 | }).then(bkitversion => { 64 | if (bkitversion.exitCode == 0 && bkitversion.stdout.length > 0) { 65 | return `${bkitimage.stdout.trim()} => ${bkitversion.stdout.trim()}`; 66 | } else if (bkitversion.stderr.length > 0) { 67 | throw new Error(bkitimage.stderr.trim()); 68 | } 69 | return bkitversion.stdout.trim(); 70 | }); 71 | } else if (bkitimage.stderr.length > 0) { 72 | throw new Error(bkitimage.stderr.trim()); 73 | } 74 | return bkitimage.stdout.trim(); 75 | }); 76 | } 77 | 78 | public async versionSatisfies(builderName: string, range: string, builderInfo?: BuilderInfo): Promise { 79 | if (!builderInfo) { 80 | builderInfo = await new Builder({buildx: this.buildx}).inspect(builderName); 81 | } 82 | for (const node of builderInfo.nodes) { 83 | let bkversion = node.buildkit; 84 | core.debug(`BuildKit.versionSatisfies ${bkversion}: ${range}`); 85 | if (!bkversion) { 86 | try { 87 | bkversion = await this.getVersionWithinImage(node.name || ''); 88 | } catch { 89 | core.debug(`BuildKit.versionSatisfies ${node.name}: can't get version`); 90 | return false; 91 | } 92 | } 93 | core.debug(`BuildKit.versionSatisfies ${node.name}: version ${bkversion}`); 94 | // BuildKit version reported by moby is in the format of `v0.11.0-moby` 95 | if (builderInfo.driver == 'docker' && !bkversion.endsWith('-moby')) { 96 | return false; 97 | } 98 | if (!semver.satisfies(bkversion.replace(/-moby$/, ''), range)) { 99 | return false; 100 | } 101 | } 102 | return true; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /dev.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | # Copyright 2023 actions-toolkit authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | ARG NODE_VERSION=20 18 | ARG DOCKER_VERSION=28.3 19 | ARG BUILDX_VERSION=0.30.1 20 | ARG COMPOSE_VERSION=2.39.1 21 | ARG UNDOCK_VERSION=0.10.0 22 | ARG REGCTL_VERSION=v0.8.2 23 | ARG COSIGN_VERSION=v3.0.3 24 | 25 | FROM node:${NODE_VERSION}-alpine AS base 26 | RUN apk add --no-cache cpio findutils git 27 | WORKDIR /src 28 | RUN --mount=type=bind,target=.,rw \ 29 | --mount=type=cache,target=/src/.yarn/cache <&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"' 51 | git status --porcelain -- yarn.lock 52 | exit 1 53 | fi 54 | EOT 55 | 56 | FROM deps AS build 57 | RUN --mount=type=bind,target=.,rw \ 58 | --mount=type=cache,target=/src/.yarn/cache \ 59 | --mount=type=cache,target=/src/node_modules \ 60 | yarn run build && mkdir /out && cp -Rf lib /out/ 61 | 62 | FROM scratch AS build-update 63 | COPY --from=build /out / 64 | 65 | FROM deps AS format 66 | RUN --mount=type=bind,target=.,rw \ 67 | --mount=type=cache,target=/src/.yarn/cache \ 68 | --mount=type=cache,target=/src/node_modules \ 69 | yarn run format \ 70 | && mkdir /out && find . -name '*.ts' -not -path './node_modules/*' -not -path './.yarn/*' | cpio -pdm /out 71 | 72 | FROM scratch AS format-update 73 | COPY --from=format /out / 74 | 75 | FROM deps AS lint 76 | RUN --mount=type=bind,target=.,rw \ 77 | --mount=type=cache,target=/src/node_modules \ 78 | yarn run lint 79 | 80 | FROM dockereng/cli-bin:${DOCKER_VERSION} AS docker 81 | FROM docker/buildx-bin:${BUILDX_VERSION} AS buildx 82 | FROM docker/compose-bin:v${COMPOSE_VERSION} AS compose 83 | FROM crazymax/undock:${UNDOCK_VERSION} AS undock 84 | FROM ghcr.io/regclient/regctl:${REGCTL_VERSION} AS regctl 85 | FROM ghcr.io/sigstore/cosign/cosign:${COSIGN_VERSION} AS cosign 86 | 87 | FROM deps AS test 88 | RUN --mount=type=bind,target=.,rw \ 89 | --mount=type=cache,target=/src/.yarn/cache \ 90 | --mount=type=cache,target=/src/node_modules \ 91 | --mount=type=bind,from=docker,source=/docker,target=/usr/bin/docker \ 92 | --mount=type=bind,from=buildx,source=/buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \ 93 | --mount=type=bind,from=buildx,source=/buildx,target=/usr/bin/buildx \ 94 | --mount=type=bind,from=compose,source=/docker-compose,target=/usr/libexec/docker/cli-plugins/docker-compose \ 95 | --mount=type=bind,from=compose,source=/docker-compose,target=/usr/bin/compose \ 96 | --mount=type=bind,from=undock,source=/usr/local/bin/undock,target=/usr/bin/undock \ 97 | --mount=type=bind,from=regctl,source=/regctl,target=/usr/bin/regctl \ 98 | --mount=type=bind,from=cosign,source=/ko-app/cosign,target=/usr/bin/cosign \ 99 | --mount=type=secret,id=GITHUB_TOKEN \ 100 | GITHUB_TOKEN=$(cat /run/secrets/GITHUB_TOKEN) yarn run test:coverage --coverageDirectory=/tmp/coverage 101 | 102 | FROM scratch AS test-coverage 103 | COPY --from=test /tmp/coverage / 104 | --------------------------------------------------------------------------------