diff --git a/README.md b/README.md index c4f70d8..9ead865 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,13 @@ # donotpassgo -A composite workflow that runs general code checks on Go projects, an optional test input is available to trigger unit tests. See [steps](#steps) for more information on the jobs run +donotpassgo is a github/gitea action to run unit tests and standards/security checks for Go applications. donotpassgo supports running unit tests using the standard go library as well as support for Ginkgo. Static code analysis is ran using gosec and dependencies are scanned using govulncheck -## Usage -adding donotpassgo to workflows is simple, just add the following step to your yaml file: -```yaml -- name: "checkpoint" - uses: https://code.jakeyoungdev.com/actions/donotpassgo@main -``` - -donotpassgo has optional support for running unit tests, this can be added by setting the test flag to standard -```yaml -- name: "checkpoint" - uses: https://code.jakeyoungdev.com/actions/donotpassgo@main - with: - test: standard -``` - -running unit tests with ginkgo is also supported by setting the test flag to ginkgo -```yaml -- name: "checkpoint" - uses: https://code.jakeyoungdev.com/actions/donotpassgo@main - with: - test: ginkgo -``` - -## Steps -donotpassgo runs several workflow jobs to ensure quality and secure go code, these steps may be updated as new tools develop. -### Dependency Scans -[govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck) is installed using golang and is used to scan for vulnerabilities in the project dependencies and standard library. -### Static Code Analysis -[gosec](https://github.com/securego/gosec) inspects source code for security problems -### Unit Tests -donotpassgo supports two unit tests libraries: the standard go library and [ginkgo](https://github.com/onsi/ginkgo) \ No newline at end of file +## Inputs +|Input|Required|Values|Default|Description| +|-----|-----|-----|-----|-----| +|test-library|false|standard,ginkgo,none|none|unit testing library to use, tests are skipped if set to 'none'| +|test-version|false|any ginkgo version|latest|the version of the testing library to use (only ginkgo supported atm, value is ignored if using standard lib testing)| +|test-fail|false|yes,no|yes|does the job fail if unit tests fail| +|static|false|yes,no|yes|do static code checks run| +|static-fail|false|yes,no|yes|does the job fail if static code checks fail| +|vulnerability|false|yes,no|yes|do dependencies get scanned for vulnerabilities| +|vulnerability-fail|false|yes,no|yes|does the job fail if vulnerabilities are found| \ No newline at end of file diff --git a/action.yaml b/action.yaml index aed5b2f..481c534 100644 --- a/action.yaml +++ b/action.yaml @@ -1,27 +1,57 @@ name: "donotpassgo" -description: "general go code checks" +description: "go security checks and unit tests" inputs: - test: - description: "runs unit tests with specified library" + test-library: #TEST_LIBRARY + description: "if set, tests are run with the specific library (standard|ginkgo)" required: false default: "none" + test-version: #TEST_VERSION + description: "the test library version, if the library is none or standard this value is ignored" + required: false + default: "latest" + test-fail: #TEST_FAIL + description: "override switch to prevent jobs from failing when unit tests do" + required: false + default: "yes" + static: #STATIC_FLAG + description: "if set, static code checks are ran with gosec (yes|no)" + required: false + default: "yes" + static-fail: #STATIC_FAIL + description: "override switch to prevent jobs from failing when static code analysis does" + required: false + default: "yes" + vulnerability: #VULN_CHECK + description: "if set, dependencies are scanned with govulncheck (yes|no)" + required: false + default: "yes" + vulnerability-fail: #VULN_FAIL + description: "override switch to prevent jobs from failing when vulnerability scan does" + required: false + default: "yes" + runs: using: "composite" steps: + - name: "install dependencies" + shell: bash + run: ${{ github.action_path }}/src/install.sh + env: + TEST_LIBRARY: ${{ inputs.test-library }} + TEST_VERSION: ${{ inputs.test-version }} + - name: "run unit tests" shell: bash - run: ${{ github.action_path }}/test.sh + run: ${{ github.action_path }}/src/test.sh env: - LIBRARY: ${{ inputs.test }} + TEST_LIBRARY: ${{ inputs.test-library }} + TEST_FAIL: ${{ inputs.test-fail }} - - name: "install govulncheck" - run: | - go install golang.org/x/vuln/cmd/govulncheck@latest - - - name: "dependency scan" - run: govulncheck ./... - - - name: "static code analysis" - uses: securego/gosec@master - with: - args: ./... \ No newline at end of file + - name: "run security checks" + shell: bash + run: ${{ github.action_path }}/src/security.sh + env: + STATIC_FLAG: ${{ inputs.static }} + STATIC_FAIL: ${{ inputs.static-fail }} + VULN_CHECK: ${{ inputs.vulnerability }} + VULN_FAIL: ${{ inputs.vulnerability-fail }} \ No newline at end of file diff --git a/src/install.sh b/src/install.sh new file mode 100755 index 0000000..4e285d1 --- /dev/null +++ b/src/install.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -eo pipefail + +version=$(go version); +if [[ ! -n "$version" ]]; then + echo "[FATAL] golang is not installed"; + exit 1; +fi + +go install golang.org/x/vuln/cmd/govulncheck@latest +go install github.com/securego/gosec/v2/cmd/gosec@latest + +if [[ "$TEST_LIBRARY" == "ginkgo" ]]; then + go install github.com/onsi/ginkgo/v2/ginkgo@$TEST_VERSION +fi \ No newline at end of file diff --git a/src/security.sh b/src/security.sh new file mode 100755 index 0000000..54ee8ca --- /dev/null +++ b/src/security.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +set -eo pipefail + +if [[ "$STATIC_FLAG" == "no" && "$VULN_CHECK" == "no" ]]; then + echo "[INFO] no security flags set, skipping!"; + exit 0; +fi + +toolchain=$(go mod edit -json go.mod | jq -r ".Toolchain // empty"); +version=$(go env -json | jq -r ".GOVERSION // empty"); + +if [[ -n "$toolchain" ]]; then + echo "[DEBUG] overwriting version with toolchain"; + version=$toolchain; +fi + +if [[ "$STATIC_FLAG" == "yes" ]]; then + if GOTOOLCHAIN=$version gosec ./...; then + echo "[INFO] gosec passed!"; + else + if [[ "$STATIC_FAIL" == "yes" ]]; then + echo "[FATAL] gosec failed!"; + exit 1; + else + echo "[INFO] gosec failed!"; + fi + fi +fi + +if [ "$VULN_CHECK" == "yes" ]; then + if GOTOOLCHAIN=$version govulncheck ./...; then + echo "[INFO] govulncheck passed!"; + else + if [ "$VULN_FAIL" == "yes" ]; then + echo "[FATAL] govulncheck failed!" + exit 1; + else + echo "[INFO] govulncheck failed!" + fi + fi +fi \ No newline at end of file diff --git a/src/test.sh b/src/test.sh new file mode 100755 index 0000000..29e6a8c --- /dev/null +++ b/src/test.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +set -eo pipefail + +if [[ "$TEST_LIBRARY" == "none" ]]; then + echo "[INFO] test-library input not set, skipping unit tests."; + exit 0; +fi + +echo "[INFO] running unit tests"; +if [[ "$TEST_LIBRARY" == "standard" ]]; then + if go test ./...; then + echo "[INFO] unit tests passed!"; + exit 0; + else + if [[ "$TEST_FAIL" == "yes" ]]; then + echo "[FATAL] unit tests failed!"; + exit 1; + else + echo "[INFO] unit tests failed!"; + fi + fi +fi + +if [[ "$TEST_LIBRARY" == "ginkgo" ]]; then + if ginkgo ./...; then + echo "[INFO] unit tests passed!"; + exit 0; + else + if [[ "$TEST_FAIL" == "yes" ]]; then + echo "[FATAL] unit tests failed!"; + exit 1; + else + echo "[INFO] unit tests failed!"; + fi + fi +fi \ No newline at end of file diff --git a/test.sh b/test.sh deleted file mode 100755 index 39dfe8a..0000000 --- a/test.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -if [[ "$LIBRARY" == "none" ]]; then - echo "Test flag not set, skipping unit tests." - exit 0 -fi - -if [[ "$LIBRARY" == "standard" ]]; then - echo "Running unit tests with standard library" - if go test ./...; then - echo "Tests passed!" - exit 0 - else - echo "Tests failed!" - exit 1 - fi -fi - -if [[ "$LIBRARY" == "ginkgo" ]]; then - echo "Running unit tests with ginkgo" - go install github.com/onsi/ginkgo/v2/ginkgo@v2.23.4 - if ginkgo ./...; then - echo "Tests passed!" - exit 0 - else - echo "Tests failed!" - exit 1 - fi -fi \ No newline at end of file