diff --git a/.editorconfig b/.editorconfig index 4622c58..02e8abc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,5 +17,5 @@ indent_size = 4 [{Dockerfile,Dockerfile.}*] indent_size = 4 -[*{.mk,Makefile}] +[{Makefile,*.mk,go.mod,go.sum,*.go,.gitmodules}] indent_style = tab diff --git a/.github/workflows/check-file-format.yaml b/.github/workflows/check-file-format.yaml index 060cda3..2fabaa3 100644 --- a/.github/workflows/check-file-format.yaml +++ b/.github/workflows/check-file-format.yaml @@ -12,4 +12,4 @@ jobs: fetch-depth: 0 - run: | export BRANCH_NAME=origin/${{ github.event.repository.default_branch }} - ./scripts/githooks/editorconfig-pre-commit.sh + ./scripts/githooks/check-file-format.sh diff --git a/.github/workflows/check-markdown-format.yaml b/.github/workflows/check-markdown-format.yaml index 6bdb13c..9ead025 100644 --- a/.github/workflows/check-markdown-format.yaml +++ b/.github/workflows/check-markdown-format.yaml @@ -12,4 +12,4 @@ jobs: fetch-depth: 0 - run: | export BRANCH_NAME=origin/${{ github.event.repository.default_branch }} - ./scripts/githooks/markdown-pre-commit.sh + ./scripts/githooks/check-markdown-format.sh diff --git a/.github/workflows/check-terraform-format.yaml b/.github/workflows/check-terraform-format.yaml index af62fcc..f8c58c5 100644 --- a/.github/workflows/check-terraform-format.yaml +++ b/.github/workflows/check-terraform-format.yaml @@ -10,4 +10,4 @@ jobs: - uses: actions/checkout@v3 - run: | export CHECK_ONLY=true - ./scripts/githooks/terraform-pre-commit.sh + ./scripts/githooks/check-terraform-format.sh diff --git a/.github/workflows/cicd-pipeline.yaml b/.github/workflows/cicd-pipeline.yaml index 2791556..a152286 100644 --- a/.github/workflows/cicd-pipeline.yaml +++ b/.github/workflows/cicd-pipeline.yaml @@ -15,9 +15,9 @@ jobs: build_timestamp: ${{ steps.metadata.outputs.build_timestamp }} build_epoch: ${{ steps.metadata.outputs.build_epoch }} nodejs_version: ${{ steps.metadata.outputs.nodejs_version }} + python_version: ${{ steps.metadata.outputs.python_version }} terraform_version: ${{ steps.metadata.outputs.terraform_version }} steps: - - uses: actions/checkout@v3 - id: metadata run: | datetime=$(date -u +'%Y-%m-%dT%H:%M:%S%z') @@ -25,6 +25,7 @@ jobs: echo "build_timestamp=$(date --date=$datetime -u +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT echo "build_epoch=$(date --date=$datetime -u +'%s')" >> $GITHUB_OUTPUT echo "nodejs_version=$(grep nodejs .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT + echo "python_version=$(grep python .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT echo "terraform_version=$(grep terraform .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT scan-secrets: uses: ./.github/workflows/scan-secrets.yaml @@ -36,6 +37,8 @@ jobs: uses: ./.github/workflows/check-terraform-format.yaml cloc-repository: uses: ./.github/workflows/cloc-repository.yaml + scan-dependencies: + uses: ./.github/workflows/scan-dependencies.yaml cicd-pipeline-test: runs-on: ubuntu-latest needs: @@ -46,6 +49,7 @@ jobs: check-markdown-format, check-terraform-format, cloc-repository, + scan-dependencies, ] timeout-minutes: 10 permissions: @@ -66,6 +70,9 @@ jobs: export BUILD_DATETIME="${{ needs.get-metadata.outputs.build_datetime }}" export BUILD_TIMESTAMP="${{ needs.get-metadata.outputs.build_timestamp }}" export BUILD_EPOCH="${{ needs.get-metadata.outputs.build_epoch }}" + export NODEJS_VERSION="${{ needs.get-metadata.outputs.nodejs_version }}" + export PYTHON_VERSION="${{ needs.get-metadata.outputs.python_version }}" + export TERRAFORM_VERSION="${{ needs.get-metadata.outputs.terraform_version }}" make list-variables - name: Test Terraform run: | @@ -89,6 +96,9 @@ jobs: export BUILD_DATETIME="${{ needs.get-metadata.outputs.build_datetime }}" export BUILD_TIMESTAMP="${{ needs.get-metadata.outputs.build_timestamp }}" export BUILD_EPOCH="${{ needs.get-metadata.outputs.build_epoch }}" + export NODEJS_VERSION="${{ needs.get-metadata.outputs.nodejs_version }}" + export PYTHON_VERSION="${{ needs.get-metadata.outputs.python_version }}" + export TERRAFORM_VERSION="${{ needs.get-metadata.outputs.terraform_version }}" make list-variables - name: Setup Node uses: actions/setup-node@v3 diff --git a/.github/workflows/scan-dependencies.yaml b/.github/workflows/scan-dependencies.yaml new file mode 100644 index 0000000..5064168 --- /dev/null +++ b/.github/workflows/scan-dependencies.yaml @@ -0,0 +1,29 @@ +name: Scan Dependencies + +on: + workflow_call: + +jobs: + scan-dependencies: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: | + ./scripts/sbom-generator.sh + - uses: actions/upload-artifact@v3 + with: + name: sbom-spdx.json + path: ./sbom-spdx.json + - run: | + ./scripts/cve-scanner.sh + - uses: actions/upload-artifact@v3 + with: + name: cve-scan.json + path: ./cve-scan.json + # - uses: aws-actions/configure-aws-credentials@v2 + # with: + # role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ vars.AWS_ROLE_NAME }} + # aws-region: ${{ vars.AWS_REGION }} + # - run: | + # aws s3 cp ./sbom-spdx.json s3://? + # aws s3 cp ./cve-scan.json s3://? diff --git a/.github/workflows/scan-secrets.yaml b/.github/workflows/scan-secrets.yaml index 1778509..247c198 100644 --- a/.github/workflows/scan-secrets.yaml +++ b/.github/workflows/scan-secrets.yaml @@ -4,7 +4,7 @@ on: workflow_call: jobs: - secret-scan: + scan-secrets: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -12,4 +12,4 @@ jobs: fetch-depth: 0 - run: | export ALL_FILES=true - ./scripts/githooks/secret-scan-pre-commit.sh + ./scripts/githooks/scan-secrets.sh diff --git a/.tool-versions b/.tool-versions index 2f36b1a..594a876 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,3 @@ nodejs 20.3.0 terraform 1.5.0 +pre-commit 3.3.3 diff --git a/Makefile b/Makefile index f0a0f28..ccaa310 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +include ./scripts/init.mk + example-build: # Build example project cd examples/react-app yarn install @@ -10,50 +12,10 @@ example-upload: # Upload example files - mandatory: AWS_S3_BUCKET_NAME=[AWS S3 b config: # Configure development environment make githooks-install make \ - node-install \ + nodejs-install \ terraform-install \ ||: -githooks-install: # Install git hooks configured in this repository - echo "./scripts/githooks/pre-commit" > .git/hooks/pre-commit - chmod +x .git/hooks/pre-commit - -terraform-install: # Install Terraform - asdf plugin add terraform ||: - asdf install terraform - -node-install: # Install Node.js - asdf plugin add nodejs ||: - asdf install nodejs - -# ============================================================================== - -help: # List Makefile targets - @awk 'BEGIN {FS = ":.*?# "} /^[ a-zA-Z0-9_-]+:.*? # / {printf "\033[36m%-41s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort - -list-variables: # List all the variables available to make - @$(foreach v, $(sort $(.VARIABLES)), - $(if $(filter-out default automatic, $(origin $v)), - $(if $(and $(patsubst %_PASSWORD,,$v), $(patsubst %_PASS,,$v), $(patsubst %_KEY,,$v), $(patsubst %_SECRET,,$v)), - $(info $v=$($v) ($(value $v)) [$(flavor $v),$(origin $v)]), - $(info $v=****** (******) [$(flavor $v),$(origin $v)]) - ) - ) - ) - -.DEFAULT_GOAL := help -.EXPORT_ALL_VARIABLES: -.NOTPARALLEL: -.ONESHELL: -.PHONY: * -MAKEFLAGS := --no-print-director -SHELL := /bin/bash -ifeq (true, $(shell [[ "$(VERBOSE)" =~ ^(true|yes|y|on|1|TRUE|YES|Y|ON)$$ ]] && echo true)) - .SHELLFLAGS := -cex -else - .SHELLFLAGS := -ce -endif - .SILENT: \ config \ githooks-install diff --git a/scripts/cloc-repository.sh b/scripts/cloc-repository.sh index 73fec5c..4eb71db 100755 --- a/scripts/cloc-repository.sh +++ b/scripts/cloc-repository.sh @@ -13,7 +13,8 @@ set -e # ============================================================================== -image_version=latest +# SEE: https://github.com/make-ops-tools/gocloc/pkgs/container/gocloc, use the `linux/amd64` os/arch +image_version=latest@sha256:6888e62e9ae693c4ebcfed9f1d86c70fd083868acb8815fe44b561b9a73b5032 # ============================================================================== diff --git a/scripts/config/.gitleaks.toml b/scripts/config/.gitleaks.toml new file mode 100644 index 0000000..92e5970 --- /dev/null +++ b/scripts/config/.gitleaks.toml @@ -0,0 +1,19 @@ +# SEE: https://github.com/gitleaks/gitleaks/#configuration + +[extend] +useDefault = true # SEE: https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml + +[[rules]] +description = "IPv4" +id = "ipv4" +regex = '''[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}''' + +[rules.allowlist] +regexTarget = "match" +regexes = [ + # Exclude the private network IPv4 addresses as well as the DNS servers for Google and OpenDNS + '''(127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|10\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]{1,3}\.[0-9]{1,3}|192\.168\.[0-9]{1,3}\.[0-9]{1,3}|0\.0\.0\.0|255\.255\.255\.255|8\.8\.8\.8|8\.8\.4\.4|208\.67\.222\.222|208\.67\.220\.220)''', +] + +[allowlist] +files = ['.terraform.lock.hcl', 'poetry.lock', 'yarn.lock'] diff --git a/scripts/config/.grype.yaml b/scripts/config/.grype.yaml new file mode 100644 index 0000000..80c752e --- /dev/null +++ b/scripts/config/.grype.yaml @@ -0,0 +1,19 @@ +# If using SBOM input, automatically generate CPEs when packages have none +add-cpes-if-none: true + +# ignore: +# # This is the full set of supported rule fields: +# - vulnerability: CVE-2008-4318 +# fix-state: unknown +# package: +# name: libcurl +# version: 1.5.1 +# type: npm +# location: "/usr/local/lib/node_modules/**" + +# # We can make rules to match just by vulnerability ID: +# - vulnerability: CVE-2014-54321 + +# # ...or just by a single package field: +# - package: +# type: gem diff --git a/scripts/config/.pre-commit.yaml b/scripts/config/.pre-commit.yaml new file mode 100644 index 0000000..fce7ea5 --- /dev/null +++ b/scripts/config/.pre-commit.yaml @@ -0,0 +1,29 @@ +repos: +- repo: local + hooks: + - id: scan-secrets + name: Scan Secrets + entry: ./scripts/githooks/scan-secrets.sh + language: script + pass_filenames: false +- repo: local + hooks: + - id: check-file-format + name: Check File Format + entry: ./scripts/githooks/check-file-format.sh + language: script + pass_filenames: false +- repo: local + hooks: + - id: check-markdown-format + name: Check Markdown Format + entry: ./scripts/githooks/check-markdown-format.sh + language: script + pass_filenames: false +- repo: local + hooks: + - id: check-terraform-format + name: Check Terraform Format + entry: ./scripts/githooks/check-terraform-format.sh + language: script + pass_filenames: false diff --git a/scripts/config/.syft.yaml b/scripts/config/.syft.yaml new file mode 100644 index 0000000..e9f5f58 --- /dev/null +++ b/scripts/config/.syft.yaml @@ -0,0 +1,83 @@ +# a list of globs to exclude from scanning. same as --exclude ; for example: +# exclude: +# - "/etc/**" +# - "./out/**/*.json" +exclude: + - ./.git/** + +# maximum number of workers used to process the list of package catalogers in parallel +parallelism: 3 + +# cataloging packages is exposed through the packages and power-user subcommands +package: + # search within archives that do contain a file index to search against (zip) + # note: for now this only applies to the java package cataloger + # SYFT_PACKAGE_SEARCH_INDEXED_ARCHIVES env var + search-indexed-archives: true + # search within archives that do not contain a file index to search against (tar, tar.gz, tar.bz2, etc) + # note: enabling this may result in a performance impact since all discovered compressed tars will be decompressed + # note: for now this only applies to the java package cataloger + # SYFT_PACKAGE_SEARCH_UNINDEXED_ARCHIVES env var + search-unindexed-archives: true + cataloger: + # enable/disable cataloging of packages + # SYFT_PACKAGE_CATALOGER_ENABLED env var + enabled: true + # the search space to look for packages (options: all-layers, squashed) + # same as -s ; SYFT_PACKAGE_CATALOGER_SCOPE env var + scope: "squashed" + +# cataloging file contents is exposed through the power-user subcommand +file-contents: + cataloger: + # enable/disable cataloging of secrets + # SYFT_FILE_CONTENTS_CATALOGER_ENABLED env var + enabled: true + # the search space to look for secrets (options: all-layers, squashed) + # SYFT_FILE_CONTENTS_CATALOGER_SCOPE env var + scope: "squashed" + # skip searching a file entirely if it is above the given size (default = 1MB; unit = bytes) + # SYFT_FILE_CONTENTS_SKIP_FILES_ABOVE_SIZE env var + skip-files-above-size: 1048576 + # file globs for the cataloger to match on + # SYFT_FILE_CONTENTS_GLOBS env var + globs: [] + +# cataloging file metadata is exposed through the power-user subcommand +file-metadata: + cataloger: + # enable/disable cataloging of file metadata + # SYFT_FILE_METADATA_CATALOGER_ENABLED env var + enabled: true + # the search space to look for file metadata (options: all-layers, squashed) + # SYFT_FILE_METADATA_CATALOGER_SCOPE env var + scope: "squashed" + # the file digest algorithms to use when cataloging files (options: "sha256", "md5", "sha1") + # SYFT_FILE_METADATA_DIGESTS env var + digests: ["sha256"] + +# cataloging secrets is exposed through the power-user subcommand +secrets: + cataloger: + # enable/disable cataloging of secrets + # SYFT_SECRETS_CATALOGER_ENABLED env var + enabled: true + # the search space to look for secrets (options: all-layers, squashed) + # SYFT_SECRETS_CATALOGER_SCOPE env var + scope: "all-layers" + # show extracted secret values in the final JSON report + # SYFT_SECRETS_REVEAL_VALUES env var + reveal-values: false + # skip searching a file entirely if it is above the given size (default = 1MB; unit = bytes) + # SYFT_SECRETS_SKIP_FILES_ABOVE_SIZE env var + skip-files-above-size: 1048576 + # name-regex pairs to consider when searching files for secrets. Note: the regex must match single line patterns + # but may also have OPTIONAL multiline capture groups. Regexes with a named capture group of "value" will + # use the entire regex to match, but the secret value will be assumed to be entirely contained within the + # "value" named capture group. + additional-patterns: {} + # names to exclude from the secrets search, valid values are: "aws-access-key", "aws-secret-key", "pem-private-key", + # "docker-config-auth", and "generic-api-key". Note: this does not consider any names introduced in the + # "secrets.additional-patterns" config option. + # SYFT_SECRETS_EXCLUDE_PATTERN_NAMES env var + exclude-pattern-names: [] diff --git a/scripts/cve-scanner.sh b/scripts/cve-scanner.sh new file mode 100755 index 0000000..4f3d3b0 --- /dev/null +++ b/scripts/cve-scanner.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +set -e + +# Script to scan an SBOM file for CVEs (Common Vulnerabilities and Exposures). +# +# Usage: +# $ ./cve-scanner.sh +# +# Options: +# VERBOSE=true # Show all the executed commands, default is `false` + +# ============================================================================== + +# SEE: https://github.com/anchore/grype/pkgs/container/grype, use the `linux/amd64` os/arch +image_version=v0.63.1@sha256:124447c7abae54d6fdad2d3a18c9c71d88af46404c55437c3acbf6dde524c417 + +# ============================================================================== + +function main() { + + docker run --rm --platform linux/amd64 \ + --volume $PWD:/scan \ + ghcr.io/anchore/grype:$image_version \ + sbom:/scan/sbom-spdx.json \ + --config /scan/scripts/config/.grype.yaml \ + --output json \ + --file=/scan/cve-scan.json +} + +function is_arg_true() { + + if [[ "$1" =~ ^(true|yes|y|on|1|TRUE|YES|Y|ON)$ ]]; then + return 0 + else + return 1 + fi +} + +# ============================================================================== + +is_arg_true "$VERBOSE" && set -x + +main $* + +exit 0 diff --git a/scripts/githooks/editorconfig-pre-commit.sh b/scripts/githooks/check-file-format.sh similarity index 94% rename from scripts/githooks/editorconfig-pre-commit.sh rename to scripts/githooks/check-file-format.sh index 5b4a430..ba6b4e8 100755 --- a/scripts/githooks/editorconfig-pre-commit.sh +++ b/scripts/githooks/check-file-format.sh @@ -7,7 +7,7 @@ set +e # according to the style defined in the `.editorconfig` file. # # Usage: -# $ ./editorconfig-pre-commit.sh +# $ ./check-file-format.sh # # Options: # BRANCH_NAME=other-branch-than-main # Branch to compare with, default is `origin/main` @@ -26,8 +26,9 @@ set +e # ============================================================================== -exit_code=0 +# SEE: https://hub.docker.com/r/mstruebing/editorconfig-checker/tags, use the `linux/amd64` os/arch image_version=2.7.0@sha256:0f8f8dd4f393d29755bef2aef4391d37c34e358d676e9d66ce195359a9c72ef3 +exit_code=0 # ============================================================================== diff --git a/scripts/githooks/markdown-pre-commit.sh b/scripts/githooks/check-markdown-format.sh similarity index 88% rename from scripts/githooks/markdown-pre-commit.sh rename to scripts/githooks/check-markdown-format.sh index 43909d9..457076f 100755 --- a/scripts/githooks/markdown-pre-commit.sh +++ b/scripts/githooks/check-markdown-format.sh @@ -6,7 +6,7 @@ set -e # over changed files. # # Usage: -# $ ./markdown-pre-commit.sh +# $ ./check-markdown-format.sh # # Options: # BRANCH_NAME=other-branch-than-main # Branch to compare with, default is `origin/main` @@ -26,7 +26,8 @@ set -e # ============================================================================== -image_version=v0.34.0@sha256:230b1e0e0fa1c7dd6261e025cacf6761ac5ba3557a6a919eec910d731817ff28 +# SEE: https://github.com/igorshubovych/markdownlint-cli/pkgs/container/markdownlint-cli, use the `linux/amd64` os/arch +image_version=v0.35.0@sha256:4ec089301e2e3e1298424f4d2b5d9e18af3aa005402590770c339b6637100dc6 # ============================================================================== diff --git a/scripts/githooks/terraform-pre-commit.sh b/scripts/githooks/check-terraform-format.sh similarity index 96% rename from scripts/githooks/terraform-pre-commit.sh rename to scripts/githooks/check-terraform-format.sh index e486dd6..68af555 100755 --- a/scripts/githooks/terraform-pre-commit.sh +++ b/scripts/githooks/check-terraform-format.sh @@ -5,7 +5,7 @@ set -e # Pre-commit git hook to check format Terraform code. # # Usage: -# $ ./terraform-pre-commit.sh +# $ ./check-terraform-format.sh # # Options: # CHECK_ONLY=true # Do not format, run check only, default is `false` diff --git a/scripts/githooks/pre-commit b/scripts/githooks/pre-commit deleted file mode 100755 index ed98324..0000000 --- a/scripts/githooks/pre-commit +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -e - -# Pre-commit git hook runner - -# ============================================================================== - -project_dir=$(git rev-parse --show-toplevel) -cd $project_dir - -pre_commit_scripts=$(ls -1 $project_dir/scripts/githooks/*-pre-commit.sh 2> /dev/null) -for script in $pre_commit_scripts; do - printf "Running githook: $(echo $script | sed "s;$project_dir/;;g")\n" - $script "$@" -done -printf "Successfully run all githooks\n" diff --git a/scripts/githooks/secret-scan-pre-commit.sh b/scripts/githooks/scan-secrets.sh similarity index 73% rename from scripts/githooks/secret-scan-pre-commit.sh rename to scripts/githooks/scan-secrets.sh index b61e36e..b9eb760 100755 --- a/scripts/githooks/secret-scan-pre-commit.sh +++ b/scripts/githooks/scan-secrets.sh @@ -5,7 +5,7 @@ set -e # Pre-commit git hook to scan for secrets hardcoded in the codebase. # # Usage: -# $ ./secret-scan-pre-commit.sh +# $ ./scan-secrets.sh # # Options: # ALL_FILES=true # Scan whole git history or 'last-commit', default is `false` @@ -18,7 +18,8 @@ set -e # ============================================================================== -image_version=v8.16.3@sha256:05b48ff3f4fd7daa9487b42cbf9d576f2dc0dbe2551e3d0a8738e18ba2278091 +# SEE: https://github.com/gitleaks/gitleaks/pkgs/container/gitleaks, use the `linux/amd64` os/arch +image_version=v8.17.0@sha256:99e40155529614d09d264cc886c1326c9a4593ad851ccbeaaed8dcf03ff3d3d7 # ============================================================================== @@ -34,12 +35,17 @@ function main() { # Scan staged files only cmd="protect --source=/scan --verbose --staged" fi + # Include base line file if it exists + if [ -f $PWD/scripts/config/.gitleaks-baseline.json ]; then + cmd="$cmd --baseline-path /scan/scripts/config/.gitleaks-baseline.json" + fi docker run --rm --platform linux/amd64 \ --volume=$PWD:/scan \ --workdir=/scan \ ghcr.io/gitleaks/gitleaks:$image_version \ - $cmd + $cmd \ + --config /scan/scripts/config/.gitleaks.toml } function is_arg_true() { diff --git a/scripts/init.mk b/scripts/init.mk new file mode 100644 index 0000000..350e5a6 --- /dev/null +++ b/scripts/init.mk @@ -0,0 +1,80 @@ +# This file is part of the repository template project. Please, DO NOT edit this file. + +nodejs-install: # Install Node.js + make _install-dependency name="nodejs" + make _install-dependency name="yarn" version=latest + +python-install: # Install Python + make _install-dependency name="python" + make _install-dependency name="poetry" version=latest + +terraform-install: # Install Terraform + make _install-dependency name="terraform" + +githooks-install: # Install git hooks configured in this repository + make _install-dependency name="pre-commit" + pre-commit install \ + --config ./scripts/config/.pre-commit.yaml \ + --install-hooks + +githooks-run: # Run git hooks configured in this repository + pre-commit run \ + --config ./scripts/config/.pre-commit.yaml \ + --all-files + +asdf-install: # Install asdf from https://asdf-vm.com/ + if [ -d "${HOME}/.asdf" ]; then + ( cd "${HOME}/.asdf"; git pull ) + else + git clone --depth=1 https://github.com/asdf-vm/asdf.git "${HOME}/.asdf" ||: + fi + asdf plugin update --all + +_install-dependency: # Install asdf dependency - mandatory: name=[listed in the `./.tool-versions` file]; optional: version=[if not listed] + asdf plugin add ${name} ||: + asdf install ${name} $(or ${version},) + +clean:: # Remove all generated and temporary files + rm -rf \ + docs/diagrams/.*.bkp \ + docs/diagrams/.*.dtmp \ + cve-scan*.json \ + sbom-spdx*.json + +help: # List Makefile targets + awk 'BEGIN {FS = ":.*?# "} /^[ a-zA-Z0-9_-]+:.*? # / {printf "\033[36m%-41s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort + +list-variables: # List all the variables available to make + $(foreach v, $(sort $(.VARIABLES)), + $(if $(filter-out default automatic, $(origin $v)), + $(if $(and $(patsubst %_PASSWORD,,$v), $(patsubst %_PASS,,$v), $(patsubst %_KEY,,$v), $(patsubst %_SECRET,,$v)), + $(info $v=$($v) ($(value $v)) [$(flavor $v),$(origin $v)]), + $(info $v=****** (******) [$(flavor $v),$(origin $v)]) + ) + ) + ) + +.DEFAULT_GOAL := help +.EXPORT_ALL_VARIABLES: +.NOTPARALLEL: +.ONESHELL: +.PHONY: * +MAKEFLAGS := --no-print-director +SHELL := /bin/bash +ifeq (true, $(shell [[ "$(VERBOSE)" =~ ^(true|yes|y|on|1|TRUE|YES|Y|ON)$$ ]] && echo true)) + .SHELLFLAGS := -cex +else + .SHELLFLAGS := -ce +endif + +.SILENT: \ + _install-dependency \ + asdf-install \ + clean \ + githooks-install \ + githooks-run \ + help \ + list-variables \ + nodejs-install \ + python-install \ + terraform-install diff --git a/scripts/sbom-generator.sh b/scripts/sbom-generator.sh new file mode 100755 index 0000000..ed9ecc0 --- /dev/null +++ b/scripts/sbom-generator.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +set -e + +# Script to generate SBOM (Software Bill of Materials) for the repository +# content and any artefact created by the CI/CD pipeline. +# +# Usage: +# $ ./generate-sbom.sh +# +# Options: +# VERBOSE=true # Show all the executed commands, default is `false` + +# ============================================================================== + +# SEE: https://github.com/anchore/syft/pkgs/container/syft, use the `linux/amd64` os/arch +image_version=v0.84.1@sha256:9a8f80eee3984d4a3f9a86e4d66e739e30dfc34564d76d3574f98798db5d5b35 + +# ============================================================================== + +function main() { + + create-sbom + enrich-sbom +} + +function create-sbom() { + + docker run --rm --platform linux/amd64 \ + --volume $PWD:/scan \ + ghcr.io/anchore/syft:$image_version \ + packages dir:/scan \ + --config /scan/scripts/config/.syft.yaml \ + --output spdx-json=/scan/sbom-spdx.tmp.json +} + +function enrich-sbom() { + + git_url=$(git config --get remote.origin.url) + git_branch=$(git rev-parse --abbrev-ref HEAD) + git_commit_hash=$(git rev-parse HEAD) + git_tags=$(echo \"$(git tag | tr '\n' ',' | sed 's/,$//' | sed 's/,/","/g')\" | sed 's/""//g') + pipeline_run_id=${GITHUB_RUN_ID:-0} + pipeline_run_number=${GITHUB_RUN_NUMBER:-0} + pipeline_run_attempt=${GITHUB_RUN_ATTEMPT:-0} + + docker run --rm --platform linux/amd64 \ + --volume $PWD:/repo \ + --workdir /repo \ + ghcr.io/make-ops-tools/jq:latest \ + '.creationInfo |= . + {"repository":{"url":"'${git_url}'","branch":"'${git_branch}'","tags":['${git_tags}'],"commitHash":"'${git_commit_hash}'"},"pipeline":{"id":'${pipeline_run_id}',"number":'${pipeline_run_number}',"attempt":'${pipeline_run_attempt}'}}' \ + sbom-spdx.tmp.json \ + > sbom-spdx.json + rm -f sbom-spdx.tmp.json +} + +function is_arg_true() { + + if [[ "$1" =~ ^(true|yes|y|on|1|TRUE|YES|Y|ON)$ ]]; then + return 0 + else + return 1 + fi +} + +# ============================================================================== + +is_arg_true "$VERBOSE" && set -x + +main $* + +exit 0