Compare commits
5 Commits
0.6.1
...
909c4eb6f8
| Author | SHA1 | Date | |
|---|---|---|---|
|
909c4eb6f8
|
|||
|
95a989b770
|
|||
|
5ee910f3ad
|
|||
|
6c166c53c8
|
|||
|
f15738006e
|
@@ -0,0 +1,188 @@
|
|||||||
|
name: Security Scan
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: 27 8 * * *
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security-scan:
|
||||||
|
runs-on: running-man
|
||||||
|
|
||||||
|
env:
|
||||||
|
TARGET_DIR: .
|
||||||
|
COSIGN_VERSION: v3.0.5
|
||||||
|
SYFT_VERSION: v1.42.3
|
||||||
|
GRYPE_VERSION: v0.110.0
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Cosign (bootstrap)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
FILE="cosign-linux-amd64"
|
||||||
|
|
||||||
|
curl -fLO https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/${FILE}
|
||||||
|
|
||||||
|
chmod +x ${FILE}
|
||||||
|
mv ${FILE} /usr/local/bin/cosign
|
||||||
|
|
||||||
|
cosign version
|
||||||
|
|
||||||
|
- name: Install Syft (verified)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
VERSION_NO_V="${SYFT_VERSION#v}"
|
||||||
|
FILE="syft_${VERSION_NO_V}_linux_amd64.tar.gz"
|
||||||
|
BASE_URL="https://github.com/anchore/syft/releases/download/${SYFT_VERSION}"
|
||||||
|
|
||||||
|
curl -fLO ${BASE_URL}/${FILE}
|
||||||
|
curl -fLO ${BASE_URL}/syft_${VERSION_NO_V}_checksums.txt
|
||||||
|
curl -fLO ${BASE_URL}/syft_${VERSION_NO_V}_checksums.txt.sig
|
||||||
|
curl -fLO ${BASE_URL}/syft_${VERSION_NO_V}_checksums.txt.pem
|
||||||
|
|
||||||
|
cosign verify-blob \
|
||||||
|
--signature syft_${VERSION_NO_V}_checksums.txt.sig \
|
||||||
|
--certificate syft_${VERSION_NO_V}_checksums.txt.pem \
|
||||||
|
--certificate-identity-regexp "https://github.com/anchore/syft" \
|
||||||
|
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
|
||||||
|
syft_${VERSION_NO_V}_checksums.txt
|
||||||
|
|
||||||
|
CHECKSUM_LINE=$(grep " ${FILE}$" syft_${VERSION_NO_V}_checksums.txt)
|
||||||
|
if [ -z "$CHECKSUM_LINE" ]; then
|
||||||
|
echo "Missing checksum entry for ${FILE}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$CHECKSUM_LINE" | sha256sum -c -
|
||||||
|
|
||||||
|
tar -xzf ${FILE}
|
||||||
|
mv syft /usr/local/bin/
|
||||||
|
|
||||||
|
syft version
|
||||||
|
|
||||||
|
- name: Install Grype (verified)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
VERSION_NO_V="${GRYPE_VERSION#v}"
|
||||||
|
FILE="grype_${VERSION_NO_V}_linux_amd64.tar.gz"
|
||||||
|
BASE_URL="https://github.com/anchore/grype/releases/download/${GRYPE_VERSION}"
|
||||||
|
|
||||||
|
curl -fLO ${BASE_URL}/${FILE}
|
||||||
|
curl -fLO ${BASE_URL}/grype_${VERSION_NO_V}_checksums.txt
|
||||||
|
curl -fLO ${BASE_URL}/grype_${VERSION_NO_V}_checksums.txt.sig
|
||||||
|
curl -fLO ${BASE_URL}/grype_${VERSION_NO_V}_checksums.txt.pem
|
||||||
|
|
||||||
|
cosign verify-blob \
|
||||||
|
--signature grype_${VERSION_NO_V}_checksums.txt.sig \
|
||||||
|
--certificate grype_${VERSION_NO_V}_checksums.txt.pem \
|
||||||
|
--certificate-identity-regexp "https://github.com/anchore/grype" \
|
||||||
|
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
|
||||||
|
grype_${VERSION_NO_V}_checksums.txt
|
||||||
|
|
||||||
|
CHECKSUM_LINE=$(grep " ${FILE}$" grype_${VERSION_NO_V}_checksums.txt)
|
||||||
|
if [ -z "$CHECKSUM_LINE" ]; then
|
||||||
|
echo "Missing checksum entry for ${FILE}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$CHECKSUM_LINE" | sha256sum -c -
|
||||||
|
|
||||||
|
tar -xzf ${FILE}
|
||||||
|
mv grype /usr/local/bin/
|
||||||
|
|
||||||
|
grype version
|
||||||
|
|
||||||
|
- name: Generate SBOM
|
||||||
|
working-directory: ${{ env.TARGET_DIR }}
|
||||||
|
run: |
|
||||||
|
syft dir:. -o json > sbom.json
|
||||||
|
|
||||||
|
- name: Show SBOM contents
|
||||||
|
working-directory: ${{ env.TARGET_DIR }}
|
||||||
|
run: |
|
||||||
|
echo "Packages discovered by Syft:"
|
||||||
|
jq -r '.artifacts[] | "\(.name)@\(.version) [\(.type)]"' sbom.json | sort
|
||||||
|
|
||||||
|
- name: Run Grype scan (JSON)
|
||||||
|
id: audit
|
||||||
|
continue-on-error: true
|
||||||
|
working-directory: ${{ env.TARGET_DIR }}
|
||||||
|
run: |
|
||||||
|
grype sbom:sbom.json -o json > grype.json
|
||||||
|
|
||||||
|
echo "Vulnerabilities (fixable only):"
|
||||||
|
jq -r '
|
||||||
|
.matches[]
|
||||||
|
| select((.vulnerability.fix.versions | length) > 0)
|
||||||
|
| "\(.artifact.name)@\(.artifact.version) -> \(.vulnerability.id) [\(.vulnerability.severity)] | fixed: \(.vulnerability.fix.versions[0])"
|
||||||
|
' grype.json
|
||||||
|
|
||||||
|
# Fail only on fixable MEDIUM/HIGH/CRITICAL
|
||||||
|
jq -e '
|
||||||
|
[
|
||||||
|
.matches[]?
|
||||||
|
| select(
|
||||||
|
(
|
||||||
|
.vulnerability.severity == "Medium" or
|
||||||
|
.vulnerability.severity == "High" or
|
||||||
|
.vulnerability.severity == "Critical"
|
||||||
|
)
|
||||||
|
and
|
||||||
|
(
|
||||||
|
(.vulnerability.fix.versions | length) > 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
| length == 0
|
||||||
|
' grype.json
|
||||||
|
|
||||||
|
- name: Show full Grype table
|
||||||
|
working-directory: ${{ env.TARGET_DIR }}
|
||||||
|
run: |
|
||||||
|
echo "Full Grype report:"
|
||||||
|
grype sbom:sbom.json -o table
|
||||||
|
|
||||||
|
- name: Notify Node-RED on vulnerabilities
|
||||||
|
if: steps.audit.outcome == 'failure'
|
||||||
|
working-directory: ${{ env.TARGET_DIR }}
|
||||||
|
run: |
|
||||||
|
jq '
|
||||||
|
{
|
||||||
|
repo: "guardutils/mirro",
|
||||||
|
summary: (
|
||||||
|
"Total: " +
|
||||||
|
(
|
||||||
|
[
|
||||||
|
.matches[]
|
||||||
|
| select((.vulnerability.fix.versions | length) > 0)
|
||||||
|
] | length | tostring
|
||||||
|
)
|
||||||
|
),
|
||||||
|
vulnerabilities: [
|
||||||
|
.matches[]
|
||||||
|
| select((.vulnerability.fix.versions | length) > 0)
|
||||||
|
| {
|
||||||
|
library: .artifact.name,
|
||||||
|
cve: .vulnerability.id,
|
||||||
|
severity: .vulnerability.severity,
|
||||||
|
installed: .artifact.version,
|
||||||
|
fixed: (.vulnerability.fix.versions[0]),
|
||||||
|
title: .vulnerability.description,
|
||||||
|
url: .vulnerability.dataSource
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
' grype.json \
|
||||||
|
| curl -s -X POST https://nodered.sysmd.uk/vulns-alert \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
--data-binary @-
|
||||||
|
|
||||||
|
- name: Fail workflow if vulnerabilities found
|
||||||
|
if: steps.audit.outcome == 'failure'
|
||||||
|
run: exit 1
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
---
|
|
||||||
name: Trivy Scan
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: 17 8 * * *
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
security-scan:
|
|
||||||
runs-on: running-man
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Trivy scan via Docker
|
|
||||||
id: trivy
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
docker run --rm \
|
|
||||||
--volumes-from "$HOSTNAME" \
|
|
||||||
aquasec/trivy:latest \
|
|
||||||
fs /workspace/guardutils/mirro \
|
|
||||||
--scanners vuln \
|
|
||||||
--pkg-types library \
|
|
||||||
--include-dev-deps \
|
|
||||||
--severity MEDIUM,HIGH,CRITICAL \
|
|
||||||
--ignore-unfixed \
|
|
||||||
--format json \
|
|
||||||
--output /workspace/guardutils/mirro/trivy.json \
|
|
||||||
--exit-code 1
|
|
||||||
|
|
||||||
- name: Notify Node-RED on vulnerabilities
|
|
||||||
if: steps.trivy.outcome == 'failure'
|
|
||||||
run: |
|
|
||||||
jq -r '
|
|
||||||
{
|
|
||||||
repo: "guardutils/mirro",
|
|
||||||
summary: (
|
|
||||||
"Total: " +
|
|
||||||
((.Results[].Vulnerabilities | length) | tostring)
|
|
||||||
),
|
|
||||||
vulnerabilities: [
|
|
||||||
.Results[].Vulnerabilities[] | {
|
|
||||||
library: .PkgName,
|
|
||||||
cve: .VulnerabilityID,
|
|
||||||
severity: .Severity,
|
|
||||||
installed: .InstalledVersion,
|
|
||||||
fixed: .FixedVersion,
|
|
||||||
title: .Title,
|
|
||||||
url: .PrimaryURL
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
' trivy.json \
|
|
||||||
| curl -s -X POST https://nodered.sysmd.uk/trivy-alert \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
--data-binary @-
|
|
||||||
|
|
||||||
- name: Fail workflow if vulnerabilities found
|
|
||||||
if: steps.trivy.outcome == 'failure'
|
|
||||||
run: exit 1
|
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/PyCQA/bandit
|
- repo: https://github.com/PyCQA/bandit
|
||||||
rev: 1.7.9
|
rev: 1.9.4
|
||||||
hooks:
|
hooks:
|
||||||
- id: bandit
|
- id: bandit
|
||||||
files: ^src/mirro/
|
files: ^src/mirro/
|
||||||
args: ["-lll", "-iii", "-s", "B110,B112"]
|
args: ["-lll", "-iii", "-s", "B110,B112"]
|
||||||
|
|
||||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||||
rev: 25.11.0
|
rev: 26.3.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
language_version: python3.13
|
language_version: python3.13
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.4.0
|
rev: v6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
|
|||||||
Reference in New Issue
Block a user