diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f043094..567e3de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,3 +148,102 @@ jobs: with: source: https://github.com/docker/buildx.git#v0.8.2 targets: update-docs + + provenance: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + attrs: + - '' + - mode=max + - builder-id=foo + - false + - true + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} + driver-opts: | + network=host + image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} + - + name: Build + uses: ./ + with: + workdir: ./test/go + targets: binary + provenance: ${{ matrix.attrs }} + set: | + *.output=type=oci,dest=/tmp/build.tar + *.cache-from=type=gha,scope=provenance + *.cache-to=type=gha,scope=provenance,mode=max + + sbom: + runs-on: ubuntu-latest + env: + DESTDIR: /tmp/bake-build + strategy: + fail-fast: false + matrix: + include: + - target: image + output: type=image,name=localhost:5000/name/app:latest,push=true + - target: binary + output: /tmp/bake-build + services: + registry: + image: registry:2 + ports: + - 5000:5000 + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} + driver-opts: | + network=host + image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} + - + name: Build + uses: ./ + with: + workdir: ./test/go + targets: ${{ matrix.target }} + sbom: true + set: | + *.output=${{ matrix.output }} + *.cache-from=type=gha,scope=attests-${{ matrix.target }} + *.cache-to=type=gha,scope=attests-${{ matrix.target }},mode=max + - + name: Inspect image + if: matrix.target == 'image' + run: | + docker buildx imagetools inspect localhost:5000/name/app:latest --format '{{json .}}' + - + name: Check output folder + if: matrix.target == 'binary' + working-directory: ${{ env.DESTDIR }} + run: | + tree . + - + name: Print provenance + if: matrix.target == 'binary' + working-directory: ${{ env.DESTDIR }} + run: | + cat provenance.json | jq + - + name: Print SBOM + if: matrix.target == 'binary' + working-directory: ${{ env.DESTDIR }} + run: | + cat sbom.spdx.json | jq diff --git a/README.md b/README.md index e4c4f9f..45e0b90 100644 --- a/README.md +++ b/README.md @@ -80,18 +80,20 @@ Following inputs can be used as `step.with` keys > targets: default,release > ``` -| Name | Type | Description | -|------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------| -| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) | -| `files` | List/CSV | List of [bake definition files](https://docs.docker.com/build/customize/bake/file-definition/) | -| `workdir` | String | Working directory of execution | -| `targets` | List/CSV | List of bake targets (`default` target used if empty) | -| `no-cache` | Bool | Do not use cache when building the image (default `false`) | -| `pull` | Bool | Always attempt to pull a newer version of the image (default `false`) | -| `load` | Bool | Load is a shorthand for `--set=*.output=type=docker` (default `false`) | -| `push` | Bool | Push is a shorthand for `--set=*.output=type=registry` (default `false`) | -| `set` | List | List of [targets values to override](https://docs.docker.com/engine/reference/commandline/buildx_bake/#set) (eg: `targetpattern.key=value`) | -| `source` | String | [Remote bake definition](https://docs.docker.com/build/customize/bake/file-definition/#remote-definition) to build from | +| Name | Type | Description | +|--------------|-------------|---------------------------------------------------------------------------------------------------------------------------------------------| +| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) | +| `files` | List/CSV | List of [bake definition files](https://docs.docker.com/build/customize/bake/file-definition/) | +| `workdir` | String | Working directory of execution | +| `targets` | List/CSV | List of bake targets (`default` target used if empty) | +| `no-cache` | Bool | Do not use cache when building the image (default `false`) | +| `pull` | Bool | Always attempt to pull a newer version of the image (default `false`) | +| `load` | Bool | Load is a shorthand for `--set=*.output=type=docker` (default `false`) | +| `provenance` | Bool/String | [Provenance](https://docs.docker.com/build/attestations/provenance/) is a shorthand for `--set=*.attest=type=provenance` | +| `push` | Bool | Push is a shorthand for `--set=*.output=type=registry` (default `false`) | +| `sbom` | Bool/String | [SBOM](https://docs.docker.com/build/attestations/sbom/) is a shorthand for `--set=*.attest=type=sbom` | +| `set` | List | List of [targets values to override](https://docs.docker.com/engine/reference/commandline/buildx_bake/#set) (eg: `targetpattern.key=value`) | +| `source` | String | [Remote bake definition](https://docs.docker.com/build/customize/bake/file-definition/#remote-definition) to build from | ### outputs diff --git a/__mocks__/@actions/github.ts b/__mocks__/@actions/github.ts new file mode 100644 index 0000000..254a5df --- /dev/null +++ b/__mocks__/@actions/github.ts @@ -0,0 +1,207 @@ +import {jest} from '@jest/globals'; + +export const context = { + repo: { + owner: 'docker', + repo: 'build-push-action' + }, + ref: 'refs/heads/master', + runId: 123456789, + payload: { + after: '860c1904a1ce19322e91ac35af1ab07466440c37', + base_ref: null, + before: '5f3331d7f7044c18ca9f12c77d961c4d7cf3276a', + commits: [ + { + author: { + email: 'crazy-max@users.noreply.github.com', + name: 'CrazyMax', + username: 'crazy-max' + }, + committer: { + email: 'crazy-max@users.noreply.github.com', + name: 'CrazyMax', + username: 'crazy-max' + }, + distinct: true, + id: '860c1904a1ce19322e91ac35af1ab07466440c37', + message: 'hello dev', + timestamp: '2022-04-19T11:27:24+02:00', + tree_id: 'd2c60af597e863787d2d27f569e30495b0b92820', + url: 'https://github.com/docker/test-docker-action/commit/860c1904a1ce19322e91ac35af1ab07466440c37' + } + ], + compare: 'https://github.com/docker/test-docker-action/compare/5f3331d7f704...860c1904a1ce', + created: false, + deleted: false, + forced: false, + head_commit: { + author: { + email: 'crazy-max@users.noreply.github.com', + name: 'CrazyMax', + username: 'crazy-max' + }, + committer: { + email: 'crazy-max@users.noreply.github.com', + name: 'CrazyMax', + username: 'crazy-max' + }, + distinct: true, + id: '860c1904a1ce19322e91ac35af1ab07466440c37', + message: 'hello dev', + timestamp: '2022-04-19T11:27:24+02:00', + tree_id: 'd2c60af597e863787d2d27f569e30495b0b92820', + url: 'https://github.com/docker/test-docker-action/commit/860c1904a1ce19322e91ac35af1ab07466440c37' + }, + organization: { + avatar_url: 'https://avatars.githubusercontent.com/u/5429470?v=4', + description: 'Docker helps developers bring their ideas to life by conquering the complexity of app development.', + events_url: 'https://api.github.com/orgs/docker/events', + hooks_url: 'https://api.github.com/orgs/docker/hooks', + id: 5429470, + issues_url: 'https://api.github.com/orgs/docker/issues', + login: 'docker', + members_url: 'https://api.github.com/orgs/docker/members{/member}', + node_id: 'MDEyOk9yZ2FuaXphdGlvbjU0Mjk0NzA=', + public_members_url: 'https://api.github.com/orgs/docker/public_members{/member}', + repos_url: 'https://api.github.com/orgs/docker/repos', + url: 'https://api.github.com/orgs/docker' + }, + pusher: { + email: 'github@crazymax.dev', + name: 'crazy-max' + }, + ref: 'refs/heads/dev', + repository: { + allow_forking: true, + archive_url: 'https://api.github.com/repos/docker/test-docker-action/{archive_format}{/ref}', + archived: false, + assignees_url: 'https://api.github.com/repos/docker/test-docker-action/assignees{/user}', + blobs_url: 'https://api.github.com/repos/docker/test-docker-action/git/blobs{/sha}', + branches_url: 'https://api.github.com/repos/docker/test-docker-action/branches{/branch}', + clone_url: 'https://github.com/docker/test-docker-action.git', + collaborators_url: 'https://api.github.com/repos/docker/test-docker-action/collaborators{/collaborator}', + comments_url: 'https://api.github.com/repos/docker/test-docker-action/comments{/number}', + commits_url: 'https://api.github.com/repos/docker/test-docker-action/commits{/sha}', + compare_url: 'https://api.github.com/repos/docker/test-docker-action/compare/{base}...{head}', + contents_url: 'https://api.github.com/repos/docker/test-docker-action/contents/{+path}', + contributors_url: 'https://api.github.com/repos/docker/test-docker-action/contributors', + created_at: 1596792180, + default_branch: 'master', + deployments_url: 'https://api.github.com/repos/docker/test-docker-action/deployments', + description: 'Test "Docker" Actions', + disabled: false, + downloads_url: 'https://api.github.com/repos/docker/test-docker-action/downloads', + events_url: 'https://api.github.com/repos/docker/test-docker-action/events', + fork: false, + forks: 1, + forks_count: 1, + forks_url: 'https://api.github.com/repos/docker/test-docker-action/forks', + full_name: 'docker/test-docker-action', + git_commits_url: 'https://api.github.com/repos/docker/test-docker-action/git/commits{/sha}', + git_refs_url: 'https://api.github.com/repos/docker/test-docker-action/git/refs{/sha}', + git_tags_url: 'https://api.github.com/repos/docker/test-docker-action/git/tags{/sha}', + git_url: 'git://github.com/docker/test-docker-action.git', + has_downloads: true, + has_issues: true, + has_pages: false, + has_projects: true, + has_wiki: true, + homepage: '', + hooks_url: 'https://api.github.com/repos/docker/test-docker-action/hooks', + html_url: 'https://github.com/docker/test-docker-action', + id: 285789493, + is_template: false, + issue_comment_url: 'https://api.github.com/repos/docker/test-docker-action/issues/comments{/number}', + issue_events_url: 'https://api.github.com/repos/docker/test-docker-action/issues/events{/number}', + issues_url: 'https://api.github.com/repos/docker/test-docker-action/issues{/number}', + keys_url: 'https://api.github.com/repos/docker/test-docker-action/keys{/key_id}', + labels_url: 'https://api.github.com/repos/docker/test-docker-action/labels{/name}', + language: 'JavaScript', + languages_url: 'https://api.github.com/repos/docker/test-docker-action/languages', + license: { + key: 'mit', + name: 'MIT License', + node_id: 'MDc6TGljZW5zZTEz', + spdx_id: 'MIT', + url: 'https://api.github.com/licenses/mit' + }, + master_branch: 'master', + merges_url: 'https://api.github.com/repos/docker/test-docker-action/merges', + milestones_url: 'https://api.github.com/repos/docker/test-docker-action/milestones{/number}', + mirror_url: null, + name: 'test-docker-action', + node_id: 'MDEwOlJlcG9zaXRvcnkyODU3ODk0OTM=', + notifications_url: 'https://api.github.com/repos/docker/test-docker-action/notifications{?since,all,participating}', + open_issues: 6, + open_issues_count: 6, + organization: 'docker', + owner: { + avatar_url: 'https://avatars.githubusercontent.com/u/5429470?v=4', + email: 'info@docker.com', + events_url: 'https://api.github.com/users/docker/events{/privacy}', + followers_url: 'https://api.github.com/users/docker/followers', + following_url: 'https://api.github.com/users/docker/following{/other_user}', + gists_url: 'https://api.github.com/users/docker/gists{/gist_id}', + gravatar_id: '', + html_url: 'https://github.com/docker', + id: 5429470, + login: 'docker', + name: 'docker', + node_id: 'MDEyOk9yZ2FuaXphdGlvbjU0Mjk0NzA=', + organizations_url: 'https://api.github.com/users/docker/orgs', + received_events_url: 'https://api.github.com/users/docker/received_events', + repos_url: 'https://api.github.com/users/docker/repos', + site_admin: false, + starred_url: 'https://api.github.com/users/docker/starred{/owner}{/repo}', + subscriptions_url: 'https://api.github.com/users/docker/subscriptions', + type: 'Organization', + url: 'https://api.github.com/users/docker' + }, + private: true, + pulls_url: 'https://api.github.com/repos/docker/test-docker-action/pulls{/number}', + pushed_at: 1650360446, + releases_url: 'https://api.github.com/repos/docker/test-docker-action/releases{/id}', + size: 796, + ssh_url: 'git@github.com:docker/test-docker-action.git', + stargazers: 0, + stargazers_count: 0, + stargazers_url: 'https://api.github.com/repos/docker/test-docker-action/stargazers', + statuses_url: 'https://api.github.com/repos/docker/test-docker-action/statuses/{sha}', + subscribers_url: 'https://api.github.com/repos/docker/test-docker-action/subscribers', + subscription_url: 'https://api.github.com/repos/docker/test-docker-action/subscription', + svn_url: 'https://github.com/docker/test-docker-action', + tags_url: 'https://api.github.com/repos/docker/test-docker-action/tags', + teams_url: 'https://api.github.com/repos/docker/test-docker-action/teams', + topics: [], + trees_url: 'https://api.github.com/repos/docker/test-docker-action/git/trees{/sha}', + updated_at: '2022-04-19T09:05:09Z', + url: 'https://github.com/docker/test-docker-action', + visibility: 'private', + watchers: 0, + watchers_count: 0 + }, + sender: { + avatar_url: 'https://avatars.githubusercontent.com/u/1951866?v=4', + events_url: 'https://api.github.com/users/crazy-max/events{/privacy}', + followers_url: 'https://api.github.com/users/crazy-max/followers', + following_url: 'https://api.github.com/users/crazy-max/following{/other_user}', + gists_url: 'https://api.github.com/users/crazy-max/gists{/gist_id}', + gravatar_id: '', + html_url: 'https://github.com/crazy-max', + id: 1951866, + login: 'crazy-max', + node_id: 'MDQ6VXNlcjE5NTE4NjY=', + organizations_url: 'https://api.github.com/users/crazy-max/orgs', + received_events_url: 'https://api.github.com/users/crazy-max/received_events', + repos_url: 'https://api.github.com/users/crazy-max/repos', + site_admin: false, + starred_url: 'https://api.github.com/users/crazy-max/starred{/owner}{/repo}', + subscriptions_url: 'https://api.github.com/users/crazy-max/subscriptions', + type: 'User', + url: 'https://api.github.com/users/crazy-max' + } + } +}; + +export const getOctokit = jest.fn(); diff --git a/__tests__/context.test.ts b/__tests__/context.test.ts index b204379..cfee5eb 100644 --- a/__tests__/context.test.ts +++ b/__tests__/context.test.ts @@ -1,16 +1,27 @@ import {beforeEach, describe, expect, jest, test} from '@jest/globals'; import * as fs from 'fs'; import * as path from 'path'; +import {Bake} from '@docker/actions-toolkit/lib/buildx/bake'; +import {Builder} from '@docker/actions-toolkit/lib/buildx/builder'; import {Buildx} from '@docker/actions-toolkit/lib/buildx/buildx'; import {Context} from '@docker/actions-toolkit/lib/context'; import {Docker} from '@docker/actions-toolkit/lib/docker/docker'; +import {GitHub} from '@docker/actions-toolkit/lib/github'; import {Toolkit} from '@docker/actions-toolkit/lib/toolkit'; +import {BakeDefinition} from '@docker/actions-toolkit/lib/types/bake'; +import {BuilderInfo} from '@docker/actions-toolkit/lib/types/builder'; +import {GitHubRepo} from '@docker/actions-toolkit/lib/types/github'; import * as context from '../src/context'; const tmpDir = path.join('/tmp', '.docker-bake-action-jest'); const tmpName = path.join(tmpDir, '.tmpname-jest'); +import repoFixture from './fixtures/github-repo.json'; +jest.spyOn(GitHub.prototype, 'repoData').mockImplementation((): Promise => { + return >(repoFixture as unknown); +}); + jest.spyOn(Context, 'tmpDir').mockImplementation((): string => { if (!fs.existsSync(tmpDir)) { fs.mkdirSync(tmpDir, {recursive: true}); @@ -26,6 +37,83 @@ jest.spyOn(Docker, 'isAvailable').mockImplementation(async (): Promise return true; }); +jest.spyOn(Builder.prototype, 'inspect').mockImplementation(async (): Promise => { + return { + name: 'builder2', + driver: 'docker-container', + lastActivity: new Date('2023-01-16 09:45:23 +0000 UTC'), + nodes: [ + { + buildkit: 'v0.11.0', + 'buildkitd-flags': '--debug --allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host', + 'driver-opts': ['BUILDKIT_STEP_LOG_MAX_SIZE=10485760', 'BUILDKIT_STEP_LOG_MAX_SPEED=10485760', 'JAEGER_TRACE=localhost:6831', 'image=moby/buildkit:latest', 'network=host'], + endpoint: 'unix:///var/run/docker.sock', + name: 'builder20', + 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', + status: 'running' + } + ] + }; +}); + +jest.spyOn(Bake.prototype, 'parseDefinitions').mockImplementation(async (files: Array, targets: Array): Promise => { + return JSON.parse(`{ + "group": { + "default": { + "targets": [ + "validate" + ] + }, + "validate": { + "targets": [ + "lint", + "validate-vendor", + "validate-docs" + ] + } + }, + "target": { + "lint": { + "context": ".", + "dockerfile": "./hack/dockerfiles/lint.Dockerfile", + "args": { + "BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1", + "GO_VERSION": "1.20" + }, + "output": [ + "type=cacheonly" + ] + }, + "validate-docs": { + "context": ".", + "dockerfile": "./hack/dockerfiles/docs.Dockerfile", + "args": { + "BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1", + "BUILDX_EXPERIMENTAL": "1", + "FORMATS": "md", + "GO_VERSION": "1.20" + }, + "target": "validate", + "output": [ + "type=cacheonly" + ] + }, + "validate-vendor": { + "context": ".", + "dockerfile": "./hack/dockerfiles/vendor.Dockerfile", + "args": { + "BUILDKIT_CONTEXT_KEEP_GIT_DIR": "1", + "GO_VERSION": "1.20" + }, + "target": "validate", + "output": [ + "type=cacheonly" + ] + } + } + }`) as BakeDefinition; +}); + describe('getArgs', () => { beforeEach(() => { process.env = Object.keys(process.env).reduce((object, key) => { @@ -98,6 +186,85 @@ describe('getArgs', () => { '--metadata-file', path.join(tmpDir, 'metadata-file') ] ], + [ + 4, + '0.10.0', + new Map([ + ['load', 'false'], + ['no-cache', 'false'], + ['push', 'false'], + ['pull', 'false'], + ]), + [ + 'bake', + '--metadata-file', path.join(tmpDir, 'metadata-file'), + "--provenance", `mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`, + ] + ], + [ + 5, + '0.10.0', + new Map([ + ['load', 'false'], + ['no-cache', 'false'], + ['push', 'false'], + ['pull', 'false'], + ['provenance', 'true'], + ]), + [ + 'bake', + '--metadata-file', path.join(tmpDir, 'metadata-file'), + "--provenance", `builder-id=https://github.com/docker/build-push-action/actions/runs/123456789` + ] + ], + [ + 6, + '0.10.0', + new Map([ + ['load', 'false'], + ['no-cache', 'false'], + ['push', 'false'], + ['pull', 'false'], + ['provenance', 'mode=max'], + ]), + [ + 'bake', + '--metadata-file', path.join(tmpDir, 'metadata-file'), + "--provenance", `mode=max,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789` + ] + ], + [ + 7, + '0.10.0', + new Map([ + ['load', 'false'], + ['no-cache', 'false'], + ['push', 'false'], + ['pull', 'false'], + ['provenance', 'false'], + ]), + [ + 'bake', + '--metadata-file', path.join(tmpDir, 'metadata-file'), + "--provenance", 'false' + ] + ], + [ + 8, + '0.10.0', + new Map([ + ['load', 'false'], + ['no-cache', 'false'], + ['push', 'false'], + ['pull', 'false'], + ['provenance', 'builder-id=foo'], + ]), + [ + 'bake', + '--metadata-file', path.join(tmpDir, 'metadata-file'), + "--provenance", 'builder-id=foo' + ] + ], ])( '[%d] given %p with %p as inputs, returns %p', async (num: number, buildxVersion: string, inputs: Map, expected: Array) => { diff --git a/__tests__/fixtures/github-repo.json b/__tests__/fixtures/github-repo.json new file mode 100644 index 0000000..faf700c --- /dev/null +++ b/__tests__/fixtures/github-repo.json @@ -0,0 +1,362 @@ +{ + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "http://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "is_template": true, + "topics": [ + "octocat", + "atom", + "electron", + "api" + ], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "pull": true, + "triage": true, + "push": false, + "maintain": false, + "admin": false + }, + "allow_rebase_merge": true, + "template_repository": null, + "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", + "allow_squash_merge": true, + "delete_branch_on_merge": true, + "allow_merge_commit": true, + "subscribers_count": 42, + "network_count": 0, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZW1pdA==" + }, + "organization": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "Organization", + "site_admin": false + }, + "parent": { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "http://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "is_template": true, + "topics": [ + "octocat", + "atom", + "electron", + "api" + ], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "allow_rebase_merge": true, + "template_repository": null, + "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", + "allow_squash_merge": true, + "delete_branch_on_merge": true, + "allow_merge_commit": true, + "subscribers_count": 42, + "network_count": 0 + }, + "source": { + "id": 1296269, + "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "owner": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/octocat/Hello-World", + "description": "This your first repo!", + "fork": false, + "url": "https://api.github.com/repos/octocat/Hello-World", + "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "http://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", + "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", + "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "is_template": true, + "topics": [ + "octocat", + "atom", + "electron", + "api" + ], + "has_issues": true, + "has_projects": true, + "has_wiki": true, + "has_pages": false, + "has_downloads": true, + "archived": false, + "disabled": false, + "visibility": "public", + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "allow_rebase_merge": true, + "template_repository": null, + "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", + "allow_squash_merge": true, + "delete_branch_on_merge": true, + "allow_merge_commit": true, + "subscribers_count": 42, + "network_count": 0 + } +} diff --git a/action.yml b/action.yml index c49c5c4..361c59c 100644 --- a/action.yml +++ b/action.yml @@ -32,10 +32,16 @@ inputs: description: "Load is a shorthand for --set=*.output=type=docker" required: false default: 'false' + provenance: + description: "Provenance is a shorthand for --set=*.attest=type=provenance" + required: false push: description: "Push is a shorthand for --set=*.output=type=registry" required: false default: 'false' + sbom: + description: "SBOM is a shorthand for --set=*.attest=type=sbom" + required: false set: description: "List of targets values to override (eg. targetpattern.key=value)" required: false diff --git a/src/context.ts b/src/context.ts index 9660288..239b985 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,5 +1,7 @@ import * as core from '@actions/core'; +import {Bake} from '@docker/actions-toolkit/lib/buildx/bake'; import {Inputs as BuildxInputs} from '@docker/actions-toolkit/lib/buildx/inputs'; +import {GitHub} from '@docker/actions-toolkit/lib/github'; import {Toolkit} from '@docker/actions-toolkit/lib/toolkit'; import {Util} from '@docker/actions-toolkit/lib/util'; @@ -11,7 +13,9 @@ export interface Inputs { noCache: boolean; pull: boolean; load: boolean; + provenance: string; push: boolean; + sbom: string; set: string[]; source: string; } @@ -25,7 +29,9 @@ export async function getInputs(): Promise { noCache: core.getBooleanInput('no-cache'), pull: core.getBooleanInput('pull'), load: core.getBooleanInput('load'), + provenance: BuildxInputs.getProvenanceInput('provenance'), push: core.getBooleanInput('push'), + sbom: core.getInput('sbom'), set: Util.getInputList('set', {ignoreComma: true}), source: core.getInput('source') }; @@ -54,6 +60,28 @@ async function getBakeArgs(inputs: Inputs, toolkit: Toolkit): Promise=0.6.0')) { args.push('--metadata-file', BuildxInputs.getBuildMetadataFilePath()); } + if (await toolkit.buildx.versionSatisfies('>=0.10.0')) { + const bake = new Bake({buildx: toolkit.buildx}); + const bakedef = await bake.parseDefinitions(inputs.files, inputs.targets); + if (inputs.provenance) { + args.push('--provenance', inputs.provenance); + } else if ((await toolkit.buildkit.versionSatisfies(inputs.builder, '>=0.11.0')) && !Bake.hasDockerExporter(bakedef, inputs.load)) { + // if provenance not specified and BuildKit version compatible for + // attestation, set default provenance. Also needs to make sure user + // doesn't want to explicitly load the image to docker. + if (GitHub.context.payload.repository?.private ?? false) { + // if this is a private repository, we set the default provenance + // attributes being set in buildx: https://github.com/docker/buildx/blob/fb27e3f919dcbf614d7126b10c2bc2d0b1927eb6/build/build.go#L603 + args.push('--provenance', BuildxInputs.resolveProvenanceAttrs(`mode=min,inline-only=true`)); + } else { + // for a public repository, we set max provenance mode. + args.push('--provenance', BuildxInputs.resolveProvenanceAttrs(`mode=max`)); + } + } + if (inputs.sbom) { + args.push('--sbom', inputs.sbom); + } + } return args; }