-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(BUILD-1563): SBOM action and reusable workflow (#2)
* feat(BUILD-1563): SBOM action and reusable workflow renovate config Reviewed-by malena-ebert-sonarsource, drautureau-sonarsource
- Loading branch information
1 parent
dd86254
commit 725910c
Showing
8 changed files
with
374 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"$schema": "https://docs.renovatebot.com/renovate-schema.json", | ||
"extends": [ | ||
"github>SonarSource/renovate-config:re-team" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
name: Test action | ||
on: | ||
pull_request: | ||
push: | ||
branches: [ '**' ] | ||
release: | ||
types: | ||
- created | ||
workflow_dispatch: | ||
|
||
jobs: | ||
test-action: | ||
name: Test SonarSource/gh-action_sbom on alpine:latest | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
with: | ||
path: ./ | ||
- uses: ./ # SonarSource/gh-action_sbom | ||
with: | ||
image: alpine:latest | ||
filename: test-action-bom.json | ||
upload-artifact: true | ||
upload-release-assets: true | ||
env: | ||
GPG_PRIVATE_KEY_PASSPHRASE: ${{ secrets.GPG_PRIVATE_KEY_PASSPHRASE }} | ||
GPG_PRIVATE_KEY_BASE64: ${{ secrets.GPG_PRIVATE_KEY_BASE64 }} | ||
- run: | | ||
test -f test-action-bom.json.asc | ||
echo "test-action-bom.json:" | ||
head test-action-bom.json | ||
- uses: ./ # SonarSource/gh-action_sbom | ||
with: | ||
image: alpine:latest | ||
filename: test2-action-bom.json | ||
upload-artifact: false | ||
upload-release-assets: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
name: Test reusable workflow | ||
on: | ||
pull_request: | ||
push: | ||
branches: [ '**' ] | ||
release: | ||
types: | ||
- created | ||
workflow_dispatch: | ||
|
||
jobs: | ||
test-workflow: | ||
name: Test SonarSource/gh-action_sbom on alpine:latest | ||
uses: ./.github/workflows/workflow.yml | ||
with: | ||
image: alpine:latest | ||
filename: test-workflow-bom.json | ||
upload-artifact: true | ||
upload-release-assets: true | ||
secrets: | ||
GPG_PRIVATE_KEY_PASSPHRASE: ${{ secrets.GPG_PRIVATE_KEY_PASSPHRASE }} | ||
GPG_PRIVATE_KEY_BASE64: ${{ secrets.GPG_PRIVATE_KEY_BASE64 }} | ||
test2-workflow: | ||
name: Test SonarSource/gh-action_sbom on alpine:latest | ||
uses: ./.github/workflows/workflow.yml | ||
with: | ||
image: alpine:latest | ||
filename: test-workflow-bom.json | ||
upload-artifact: false | ||
upload-release-assets: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
name: "CycloneDX SBOM reusable workflow" | ||
|
||
on: | ||
workflow_call: | ||
inputs: | ||
image: | ||
required: true | ||
type: string | ||
description: "The Docker image to scan." | ||
# description: "Newline-delimited list of Docker images to scan" | ||
default: "example/image_name:tag" | ||
filename: | ||
required: true | ||
type: string | ||
description: "The generated SBOM file name" | ||
# description: "Newline-delimited list of generated SBOM file names" | ||
default: "bom.json" | ||
upload-artifact: | ||
required: false | ||
type: boolean | ||
description: "Attach the SBOM to the workflow" | ||
default: true | ||
upload-release-assets: | ||
required: false | ||
type: boolean | ||
description: "Attach the SBOM to the release" | ||
default: true | ||
syft-version: | ||
required: false | ||
type: string | ||
description: "Syft version" | ||
default: v0.45.1 | ||
secrets: | ||
GPG_PRIVATE_KEY_PASSPHRASE: | ||
required: false | ||
description: "Required when 'upload-artifact' is true" | ||
GPG_PRIVATE_KEY_BASE64: | ||
required: false | ||
description: "Required when 'upload-artifact' is true" | ||
|
||
jobs: | ||
sbom: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: anchore/[email protected] | ||
with: | ||
image: ${{ inputs.image }} | ||
artifact-name: ${{ inputs.filename }} | ||
output-file: ${{ inputs.filename }} | ||
format: cyclonedx-json | ||
syft-version: ${{ inputs.syft-version }} | ||
upload-artifact: ${{ inputs.upload-artifact }} | ||
upload-release-assets: ${{ inputs.upload-release-assets }} | ||
env: | ||
SYFT_QUIET: true | ||
- name: Sign CycloneDX SBOM | ||
if: inputs.upload-artifact | ||
shell: bash | ||
env: | ||
GPG_PRIVATE_KEY_PASSPHRASE: ${{ secrets.GPG_PRIVATE_KEY_PASSPHRASE }} | ||
GPG_PRIVATE_KEY_BASE64: ${{ secrets.GPG_PRIVATE_KEY_BASE64 }} | ||
run: | | ||
if [[ ! -v GPG_PRIVATE_KEY_PASSPHRASE || ! -v GPG_PRIVATE_KEY_BASE64 ]]; then exit 0; fi | ||
export GNUPGHOMEDIR=gnupg/ | ||
mkdir --parent "${GNUPGHOMEDIR}" | ||
echo "${GPG_PRIVATE_KEY_PASSPHRASE}" | gpg --batch --pinentry-mode loopback --passphrase-fd 0 --quiet --import <(echo "${GPG_PRIVATE_KEY_BASE64}") | ||
echo "${GPG_PRIVATE_KEY_PASSPHRASE}" | gpg --batch --pinentry-mode loopback --passphrase-fd 0 --quiet --detach-sign --armor "${{ inputs.filename }}" | ||
rm -rf "${GNUPGHOMEDIR}" | ||
- uses: actions/upload-artifact@v3 | ||
if: inputs.upload-artifact | ||
with: | ||
name: "${{ inputs.filename }}" | ||
path: | | ||
${{ inputs.filename }} | ||
${{ inputs.filename }}.asc | ||
- name: Upload binaries to release | ||
if: inputs.upload-release-assets && startsWith(github.ref, 'refs/tags/') | ||
uses: svenstaro/upload-release-action@v2 | ||
with: | ||
repo_token: ${{ github.token }} | ||
file_glob: true | ||
file: "${{ inputs.filename }}?(.asc)" | ||
tag: ${{ github.ref }} | ||
overwrite: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.vscode | ||
.idea/ | ||
*.iml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
repos: | ||
- repo: meta | ||
hooks: | ||
- id: check-hooks-apply | ||
- id: check-useless-excludes | ||
- repo: https://github.com/pre-commit/pre-commit-hooks | ||
rev: v4.1.0 | ||
hooks: | ||
- id: trailing-whitespace | ||
args: [ --markdown-linebreak-ext=md ] | ||
- id: end-of-file-fixer | ||
- id: check-added-large-files | ||
- id: check-yaml | ||
- id: check-json | ||
- id: pretty-format-json | ||
args: [--autofix, --indent, "4", --no-sort-keys] | ||
files: ^.github/renovate.json | ||
- repo: https://github.com/python-jsonschema/check-jsonschema | ||
rev: 0.14.0 | ||
hooks: | ||
- id: check-renovate |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,128 @@ | ||
# gh-action_sbom | ||
GitHub Action for SBOM generation | ||
|
||
Action and reusable workflow for Docker SBOM generation from GitHub workflows. | ||
|
||
The generation of Software Bill of Material (SBOM) is implemented with [Syft](https://github.com/anchore/syft) | ||
and [sbom-action](https://github.com/anchore/sbom-action). | ||
|
||
The SBOM files are signed and eventually attached to the workflow and to the release. | ||
|
||
## Usage | ||
|
||
The BOM file is signed if the `upload-artifact` parameter is true and the GPG secrets are provided. | ||
|
||
### GitHub Action | ||
|
||
```yaml | ||
jobs: | ||
job-calling-action: | ||
steps: | ||
- uses: SonarSource/gh-action_sbom@v1 | ||
with: | ||
image: example/image_name:tag | ||
filename: bom.json | ||
upload-artifact: true | ||
upload-release-assets: true | ||
env: | ||
GPG_PRIVATE_KEY_PASSPHRASE: ${{ secrets.GPG_PRIVATE_KEY_PASSPHRASE }} | ||
GPG_PRIVATE_KEY_BASE64: ${{ secrets.GPG_PRIVATE_KEY_BASE64 }} | ||
``` | ||
### GitHub Reusable Workflow | ||
:warning: The strategy property is not supported in any job that calls a reusable workflow. | ||
See https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations | ||
```yaml | ||
jobs: | ||
job-calling-workflow: | ||
uses: SonarSource/gh-action_sbom/.github/workflows/workflow.yml@v1 | ||
with: | ||
image: example/image_name:tag | ||
filename: bom.json | ||
upload-artifact: true | ||
upload-release-assets: true | ||
secrets: | ||
GPG_PRIVATE_KEY_PASSPHRASE: ${{ secrets.GPG_PRIVATE_KEY_PASSPHRASE }} | ||
GPG_PRIVATE_KEY_BASE64: ${{ secrets.GPG_PRIVATE_KEY_BASE64 }} | ||
``` | ||
## Versioning | ||
Using the versioned semantic [tags](#Tags) is recommended for security and reliability. | ||
See [GitHub: Using tags for release management](https://docs.github.com/en/actions/creating-actions/about-custom-actions#using-tags-for-release-management) | ||
and [GitHub: Keeping your actions up to date with Dependabot](https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/keeping-your-actions-up-to-date-with-dependabot) | ||
. | ||
For convenience, it is possible to use the [branches](#Branches) following the major releases. | ||
### Tags | ||
This repository is released following semantic versioning, | ||
ie: [`1.0.0`](https://github.com/SonarSource/gh-action_sbom/releases/tag/1.0.0). | ||
|
||
```yaml | ||
jobs: | ||
job-calling-workflow: | ||
uses: SonarSource/gh-action_sbom/.github/workflows/[email protected] | ||
job-calling-action: | ||
steps: | ||
- uses: SonarSource/[email protected] | ||
``` | ||
|
||
### Branches | ||
|
||
The `master` branch shall not be referenced by end-users. | ||
|
||
Branches prefixed with a `v` are pointers to the last major versions, ie: [`v1`](https://github.com/SonarSource/gh-action_sbom/tree/v1). | ||
|
||
```yaml | ||
jobs: | ||
job-calling-workflow: | ||
uses: SonarSource/gh-action_sbom/.github/workflows/workflow.yml@v1 | ||
job-calling-action: | ||
steps: | ||
- uses: SonarSource/gh-action_sbom@v1 | ||
``` | ||
|
||
Note: use only branches with precaution and confidence in the provider. | ||
|
||
## Development | ||
|
||
The development is done on `master` and the `branch-*` maintenance branches. | ||
|
||
### Release | ||
|
||
Create a release from a maintained branches, then update the `v*` shortcut: | ||
|
||
```shell | ||
git fetch --tags | ||
git update-ref -m "reset: update branch v1 to tag 1.0.0" refs/heads/v1 1.0.0 | ||
git push origin v1 | ||
``` | ||
|
||
## FAQ | ||
|
||
### Warning Unexpected input | ||
|
||
> ``` | ||
> Warning: Unexpected input(s) 'upload-artifact', 'upload-release-assets', | ||
> valid inputs are ['path', 'image', 'registry-username', 'registry-password', 'format', 'github-token', 'artifact-name', 'output-file', 'syft-version', 'dependency-snapshot'] | ||
> ``` | ||
|
||
The warning can be ignored, see anchore/sbom-action#269 | ||
|
||
## References | ||
|
||
[Xtranet/RE/Artifact Management#GitHub Actions](https://xtranet-sonarsource.atlassian.net/wiki/spaces/RE/pages/872153170/Artifact+Management#GitHub-Actions) | ||
|
||
[Semantic Versioning 2.0.0](https://semver.org/) | ||
|
||
[GitHub: About Custom Actions](https://docs.github.com/en/actions/creating-actions/about-custom-actions) | ||
|
||
[Syft](https://github.com/anchore/syft) | ||
|
||
[Syft GitHub Action for SBOM Generation](https://github.com/anchore/sbom-action) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
name: "CycloneDX SBOM action" | ||
description: "Generate CycloneDX SBOM with Syft" | ||
|
||
inputs: | ||
image: | ||
required: true | ||
description: "The Docker image to scan." | ||
# description: "Newline-delimited list of Docker images to scan" | ||
default: "example/image_name:tag" | ||
filename: | ||
required: true | ||
description: "The generated SBOM file name" | ||
# description: "Newline-delimited list of generated SBOM file names" | ||
default: "bom.json" | ||
upload-artifact: | ||
required: false | ||
description: "Attach the SBOM to the workflow" | ||
default: true | ||
upload-release-assets: | ||
required: false | ||
description: "Attach the SBOM to the release" | ||
default: true | ||
syft-version: | ||
required: false | ||
description: "Syft version" | ||
default: v0.45.1 | ||
|
||
runs: | ||
using: 'composite' | ||
steps: | ||
- uses: anchore/[email protected] | ||
with: | ||
image: ${{ inputs.image }} | ||
artifact-name: ${{ inputs.filename }} | ||
output-file: ${{ inputs.filename }} | ||
format: cyclonedx-json | ||
syft-version: ${{ inputs.syft-version }} | ||
upload-artifact: ${{ inputs.upload-artifact }} | ||
upload-release-assets: ${{ inputs.upload-release-assets }} | ||
env: | ||
SYFT_QUIET: true | ||
- name: Sign CycloneDX SBOM | ||
if: inputs.upload-artifact == 'true' && env.GPG_PRIVATE_KEY_PASSPHRASE && env.GPG_PRIVATE_KEY_BASE64 | ||
shell: bash | ||
run: | | ||
export GNUPGHOMEDIR=gnupg/ | ||
mkdir --parent "${GNUPGHOMEDIR}" | ||
echo "${GPG_PRIVATE_KEY_PASSPHRASE}" | gpg --batch --pinentry-mode loopback --passphrase-fd 0 --quiet --import <(echo "${GPG_PRIVATE_KEY_BASE64}") | ||
echo "${GPG_PRIVATE_KEY_PASSPHRASE}" | gpg --batch --pinentry-mode loopback --passphrase-fd 0 --quiet --detach-sign --armor "${{ inputs.filename }}" | ||
rm -rf "${GNUPGHOMEDIR}" | ||
- uses: actions/upload-artifact@v3 | ||
if: inputs.upload-artifact == 'true' | ||
with: | ||
name: "${{ inputs.filename }}" | ||
path: | | ||
${{ inputs.filename }} | ||
${{ inputs.filename }}.asc | ||
- name: Upload binaries to release | ||
if: inputs.upload-release-assets == 'true' && startsWith(github.ref, 'refs/tags/') | ||
uses: svenstaro/upload-release-action@v2 | ||
with: | ||
repo_token: ${{ github.token }} | ||
file_glob: true | ||
file: "${{ inputs.filename }}?(.asc)" | ||
tag: ${{ github.ref }} | ||
overwrite: true |