diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 152a4d7c42ca5d3431defe5e9b7dc545d7236513..8d2967bd53003de3a3fe5af5efce1ee91e6f443e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,6 +8,17 @@ unit-tests: script: - "nix-shell --run 'nix-build nixos/unit-tests.nix' && cat result" +vulnerability-scan: + stage: "test" + script: + - "ci-tools/vulnerability-scan security-report.json" + - "ci-tools/count-vulnerabilities <security-report.json" + artifacts: + paths: + - "security-report.json" + expose_as: "security report" + + system-tests: stage: "test" timeout: "3 hours" @@ -29,4 +40,3 @@ deploy-to-production: script: - echo -n "Hello $GITLAB_USER_LOGIN from $CI_JOB_NAME. I was triggered by $CI_PIPELINE_SOURCE " - echo "and would like to deploy the $CI_COMMIT_BRANCH branch to the production environment." - diff --git a/ci-tools/count-vulnerabilities b/ci-tools/count-vulnerabilities new file mode 100755 index 0000000000000000000000000000000000000000..9db1c5e7e3aa756dc5b151fbcc30bc4572dd1eba --- /dev/null +++ b/ci-tools/count-vulnerabilities @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +from sys import stdin +from json import load + +def main(): + vulnix_report = load(stdin) + print("Vulnerable packages: {}".format(len(vulnix_report))) + print("Vulnerability count: {}".format( + len(set(sum((deriv["affected_by"] for deriv in vulnix_report), []))), + )) + +if __name__ == '__main__': + main() diff --git a/ci-tools/vulnerability-scan b/ci-tools/vulnerability-scan new file mode 100755 index 0000000000000000000000000000000000000000..48bf51e071a398f37565717a22b2066d3f905fbe --- /dev/null +++ b/ci-tools/vulnerability-scan @@ -0,0 +1,54 @@ +#!/usr/bin/env sh + +set -xeo pipefail + +# +# `morph build ...` output is like +# +# Selected 2/2 hosts (name filter:-0, limits:-0): +# 0: xx.xx.xx.xx (secrets: 1, health checks: 0) +# 1: yy.yy.yy.yy (secrets: 2, health checks: 0) +# +# /nix/store/d7spc457nnzh0rnv0f5lh1q2j435j1b9-morph +# nix result path: +# /nix/store/d7spc457nnzh0rnv0f5lh1q2j435j1b9-morph +# +# Get the last line so we can scan it. +# + +OUTPUT=$1 + +[ -e scan-target ] && rm -v scan-target +nix-shell --run ' +set -x +if morph_result=$(morph build morph/grid/testing/grid.nix 2>&1); then + object=$(echo "$morph_result" | tail -n 1) + ln -s "$object" scan-target +else + echo "$morph_result" + + # exit status 0-3 reserved for vulnix result. + exit 4 +fi +' + +# vulnix exits with an error status if there are vulnerabilities. We told +# GitLab to allow this by setting `allow_failure` to true in the GitLab CI +# config. vulnix exit status indicates what vulnix thinks happened. If we +# upgrade to a newer GitLab then we can make GitLab pipeline behavior vary +# based on this. +# +# For now, allow 0 (no errors), 1 (only whitelisted errors), and 2 +# (non-whitelisted errors). 3 indicates unexpected error so we let that +# propagate. +set +e +nix-shell -p vulnix --run 'vulnix --json ./scan-target/' | tee "$OUTPUT" +vulnix_status=$? +set -e + +echo "vulnix status: $vulnix_status" +if [ $vulnix_status -eq 3 ]; then + exit $vulnix_status +else + exit 0 +fi diff --git a/morph/grid/testing/grid.nix b/morph/grid/testing/grid.nix index 3a1c5f3921c196843b0a4cd1b18f20388a75edde..65f97a97fa949ac0eed0249c4b89bd7399ebf436 100644 --- a/morph/grid/testing/grid.nix +++ b/morph/grid/testing/grid.nix @@ -6,7 +6,12 @@ import ../../lib/make-grid.nix { config = ./config.json; nodes = cfg: let - sshUsers = import ../../../../PrivateStorageSecrets/staging-users.nix; + importDef = default: path: ( + if builtins.pathExists path + then import path + else default + ); + sshUsers = importDef {} ../../../../PrivateStorageSecrets/staging-users.nix; in { "payments.privatestorage-staging.com" = import ../../lib/issuer.nix ({ inherit sshUsers;