Skip to content

[Industrial Edge Insights Time Series] SDLe Scans workflow (by @SudarshanaPanda via workflow_dispatch) #4

[Industrial Edge Insights Time Series] SDLe Scans workflow (by @SudarshanaPanda via workflow_dispatch)

[Industrial Edge Insights Time Series] SDLe Scans workflow (by @SudarshanaPanda via workflow_dispatch) #4

---
# SPDX-FileCopyrightText: (C) 2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
name: "[Industrial Edge Insights Time Series] SDLe Scans"
run-name: "[Industrial Edge Insights Time Series] SDLe Scans workflow (by @${{ github.actor }} via ${{ github.event_name }})"
# Only run at most 1 workflow concurrently per PR, unlimited for branches
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
on:
workflow_dispatch:
inputs:
target:
description: 'Which Scans to run'
type: choice
options:
- all-scans
- trivy-fs-scan
- trivy-image-scan
- trivy-config-scan
- trivy-dockerfile-scan
- trivy-helm-scan
- bandit-scan
- virus-scan
- dbs-scan
- codeql-scan
workflow_call:
inputs:
target:
description: 'Which Scans to run'
required: false
type: string
jobs:
trivy-fs-scan:
if: ${{ (inputs.target == 'trivy-fs-scan') || (inputs.target == 'all-scans') }}
permissions:
contents: read
packages: read # needed for actions/checkout
runs-on: ubuntu-24.04
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Trivy from Aqua Security APT repo
run: |
sudo apt-get update
sudo apt-get install -y gnupg lsb-release wget apt-transport-https curl jq
curl -fsSL https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo gpg --dearmor -o /usr/share/keyrings/trivy.gpg
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/trivy.list > /dev/null
sudo apt-get update
sudo apt-get install -y trivy
- name: Trivy filesystem/repo scan
continue-on-error: true
shell: bash
run: |
pwd
cd manufacturing-ai-suite/industrial-edge-insights-time-series/
trivy --version
which trivy
trivy image --download-db-only
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/html.tpl -o trivy-html.tpl
cat << 'EOF' > csv.tpl
{{ range . }}
Trivy Vulnerability Scan Results ({{- .Target -}})
VulnerabilityID,Severity,CVSS Score,Title,Library,Vulnerable Version,Fixed Version,Information URL,Triage Information
{{ range .Vulnerabilities }}
{{- .VulnerabilityID }},
{{- .Severity }},
{{- range $key, $value := .CVSS }}
{{- if (eq $key "nvd") }}
{{- .V3Score -}}
{{- end }}
{{- end }},
{{- quote .Title }},
{{- quote .PkgName }},
{{- quote .InstalledVersion }},
{{- quote .FixedVersion }},
{{- .PrimaryURL }}
{{ else -}}
No vulnerabilities found at this time.
{{ end }}
Trivy Dependency Scan Results ({{ .Target }})
ID,Name,Version,Notes
{{ range .Packages -}}
{{- quote .ID }},
{{- quote .Name }},
{{- quote .Version }}
{{ else -}}
No dependencies found at this time.
{{ end }}
{{ end }}
EOF
# Use the downloaded template
trivy fs . --format template --template "@trivy-html.tpl" -o "trivy_fs_full_report_code_scan.html"
trivy fs --list-all-pkgs --format template --template "@csv.tpl" --output trivy-fs-full-report.csv .
trivy fs --ignore-unfixed . | tee trivy-fs-full-report-ignore-unfixed.txt
- name: Upload Trivy FS Scan Report
continue-on-error: true
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: Trivy Report - Filesystem Scan
path: |
manufacturing-ai-suite/industrial-edge-insights-time-series/trivy*
trivy-image-scan:
if: ${{ (inputs.target == 'trivy-image-scan') || (inputs.target == 'all-scans') }}
permissions:
contents: read
packages: read # needed for actions/checkout
runs-on: ubuntu-24.04
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Trivy from Aqua Security APT repo
run: |
sudo apt-get update
sudo apt-get install -y gnupg lsb-release wget apt-transport-https curl jq
curl -fsSL https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo gpg --dearmor -o /usr/share/keyrings/trivy.gpg
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/trivy.list > /dev/null
sudo apt-get update
sudo apt-get install -y trivy
- name: Install Trivy
continue-on-error: true
shell: bash
run: |
pwd
cd manufacturing-ai-suite/industrial-edge-insights-time-series/
trivy --version
which trivy
trivy image --download-db-only
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/html.tpl -o trivy-html.tpl
cat << 'EOF' > csv.tpl
{{ range . }}
Trivy Vulnerability Scan Results ({{- .Target -}})
VulnerabilityID,Severity,CVSS Score,Title,Library,Vulnerable Version,Fixed Version,Information URL,Triage Information
{{ range .Vulnerabilities }}
{{- .VulnerabilityID }},
{{- .Severity }},
{{- range $key, $value := .CVSS }}
{{- if (eq $key "nvd") }}
{{- .V3Score -}}
{{- end }}
{{- end }},
{{- quote .Title }},
{{- quote .PkgName }},
{{- quote .InstalledVersion }},
{{- quote .FixedVersion }},
{{- .PrimaryURL }}
{{ else -}}
No vulnerabilities found at this time.
{{ end }}
Trivy Dependency Scan Results ({{ .Target }})
ID,Name,Version,Notes
{{ range .Packages -}}
{{- quote .ID }},
{{- quote .Name }},
{{- quote .Version }}
{{ else -}}
No dependencies found at this time.
{{ end }}
{{ end }}
EOF
- name: Trivy Image Scan
continue-on-error: true
shell: bash
run: |
pwd
echo "Building Wind Turbine Sample App and scanning Image"
cd manufacturing-ai-suite/industrial-edge-insights-time-series/
make down
sed -i -e "s|OPC_UA_SERVER_IMAGE=.*|OPC_UA_SERVER_IMAGE=ia-opcua-server:1.0.0-weekly|g" .env
sed -i -e "s|MQTT_PUBLISHER_IMAGE=.*|MQTT_PUBLISHER_IMAGE=ia-mqtt-publisher:1.1.0-weekly|g" .env
make build
trivy image intel/ia-opcua-server:1.0.0-weekly --ignore-unfixed --format template --template "@trivy-html.tpl" -o trivy-image-scan-opcua-server-ignore-unfixed.html
trivy image intel/ia-opcua-server:1.0.0-weekly --ignore-unfixed --format template --template "@csv.tpl" -o trivy-image-scan-opcua-server-ignore-unfixed.csv
trivy image --quiet --format spdx-json --output trivy-image-scan-opcua-server.spdx.json intel/ia-opcua-server:1.0.0-weekly
trivy image --list-all-pkgs --format template --template "@csv.tpl" --output trivy-image-scan_opcua-server-list-all-pkgs.csv intel/ia-opcua-server:1.0.0-weekly
trivy image --ignore-unfixed intel/ia-opcua-server:1.0.0-weekly | tee trivy-image-scan-opcua-server-ignore-unfixed.txt
trivy image intel/ia-mqtt-publisher:1.1.0-weekly --ignore-unfixed --format template --template "@trivy-html.tpl" -o trivy-image-scan-mqtt-publisher-ignore-unfixed.html
trivy image intel/ia-mqtt-publisher:1.1.0-weekly --ignore-unfixed --format template --template "@csv.tpl" -o trivy-image-scan-mqtt-publisher-ignore-unfixed.csv
trivy image --quiet --format spdx-json --output trivy-image-scan-mqtt-publisher.spdx.json intel/ia-mqtt-publisher:1.1.0-weekly
trivy image --list-all-pkgs --format template --template "@csv.tpl" --output trivy-image-scan-mqtt-publisher-list-all-pkgs.csv ia-mqtt-publisher:latest
trivy image --ignore-unfixed ia-mqtt-publisher:latest | tee trivy-image-scan-mqtt-publisher-ignore-unfixed.txt
echo "completed Wind Turbine Sample App Image scanning"
- name: Upload Trivy Image Scan Report
continue-on-error: true
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: Trivy Report - Image Scan
path: |
manufacturing-ai-suite/industrial-edge-insights-time-series/trivy-image-scan*
trivy-config-helm-scan:
if: ${{ (inputs.target == 'trivy-config-scan') || (inputs.target == 'trivy-helm-scan') || (inputs.target == 'all-scans') }}
permissions:
contents: read
packages: read # needed for actions/checkout
runs-on: ubuntu-24.04
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Trivy from Aqua Security APT repo
run: |
sudo apt-get update
sudo apt-get install -y gnupg lsb-release wget apt-transport-https curl jq
curl -fsSL https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo gpg --dearmor -o /usr/share/keyrings/trivy.gpg
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/trivy.list > /dev/null
sudo apt-get update
sudo apt-get install -y trivy
- name: Install Trivy
continue-on-error: true
shell: bash
run: |
pwd
cd manufacturing-ai-suite/industrial-edge-insights-time-series/
trivy --version
which trivy
trivy image --download-db-only
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/html.tpl -o trivy-html.tpl
cat << 'EOF' > csv.tpl
{{ range . }}
Trivy Vulnerability Scan Results ({{- .Target -}})
VulnerabilityID,Severity,CVSS Score,Title,Library,Vulnerable Version,Fixed Version,Information URL,Triage Information
{{ range .Vulnerabilities }}
{{- .VulnerabilityID }},
{{- .Severity }},
{{- range $key, $value := .CVSS }}
{{- if (eq $key "nvd") }}
{{- .V3Score -}}
{{- end }}
{{- end }},
{{- quote .Title }},
{{- quote .PkgName }},
{{- quote .InstalledVersion }},
{{- quote .FixedVersion }},
{{- .PrimaryURL }}
{{ else -}}
No vulnerabilities found at this time.
{{ end }}
Trivy Dependency Scan Results ({{ .Target }})
ID,Name,Version,Notes
{{ range .Packages -}}
{{- quote .ID }},
{{- quote .Name }},
{{- quote .Version }}
{{ else -}}
No dependencies found at this time.
{{ end }}
{{ end }}
EOF
- name: Trivy config scan for helm charts
run: |
cd manufacturing-ai-suite/industrial-edge-insights-time-series/
make gen_helm_charts
cd helm
trivy config . >> trivy-wind-turbine-helm.txt
- name: Upload Scan artifact to Github
uses: actions/upload-artifact@v4
with:
name: Trivy Report - Config scan for Helm
path: manufacturing-ai-suite/industrial-edge-insights-time-series/helm/trivy-wind-turbine-helm.txt
trivy-config-dockerfile-scan:
if: ${{ (inputs.target == 'trivy-config-scan') || (inputs.target == 'trivy-dockerfile-scan') || (inputs.target == 'all-scans') }}
permissions:
contents: read
packages: read # needed for actions/checkout
name: Scan Dockerfiles (OPCUA & mqttpublisher)
strategy:
fail-fast: false
matrix:
include:
- dockerfile-path: manufacturing-ai-suite/industrial-edge-insights-time-series/simulator/opcua-server/Dockerfile
output-report-path: trivy-opcua-dockerfile.json
scan-name: Time Series OPCUA Dockerfile
- dockerfile-path: manufacturing-ai-suite/industrial-edge-insights-time-series/simulator/mqtt-publisher/Dockerfile
output-report-path: trivy-mqttpublisher-dockerfile.json
scan-name: Time Series mqttpublisher Dockerfile
uses: open-edge-platform/edge-ai-libraries/.github/workflows/trivy-config-mode.yaml@e6e04af3dbca805db9118b85a22ad2998f7eec39
with:
dockerfile-path: ${{ matrix.dockerfile-path }}
trivy-report-format: 'json'
severity-levels: 'HIGH,CRITICAL'
output-report-path: ${{ matrix.output-report-path }}
name: ${{ matrix.scan-name }}
bandit-scans:
if: ${{ (inputs.target == 'bandit-scan') || (inputs.target == 'all-scans') }}
permissions:
contents: read
packages: read # needed for actions/checkout
name: Run Bandit Scan
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- ubuntu_version: ubuntu24
steps:
- name: Check out edge-ai-suites repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Run Bandit Scan
run: |
mkdir -p reports
docker pull ghcr.io/pycqa/bandit/bandit
echo "### Bandit Scan Results" >> $GITHUB_STEP_SUMMARY
docker run --rm -v "${{ github.workspace }}:/src" ghcr.io/pycqa/bandit/bandit -r /src/manufacturing-ai-suite/industrial-edge-insights-time-series/ -f json -o /src/reports/bandit-report.json || true >> $GITHUB_STEP_SUMMARY
echo "Please find full report in bandit-report.txt" >> $GITHUB_STEP_SUMMARY
ls -al
pwd
- name: Convert JSON to CSV
run: |
python3 <<EOF
import json
import csv
with open("reports/bandit-report.json") as f:
data = json.load(f)
with open("reports/bandit-report.csv", "w", newline="") as csvfile:
fieldnames = ["filename", "line_number", "issue_text", "severity", "confidence", "test_name"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for issue in data.get("results", []):
writer.writerow({
"filename": issue["filename"],
"line_number": issue["line_number"],
"issue_text": issue["issue_text"],
"severity": issue["issue_severity"],
"confidence": issue["issue_confidence"],
"test_name": issue["test_name"]
})
EOF
- name: Upload Scan Reports
uses: actions/upload-artifact@v4
with:
name: bandit-report
path: |
reports/bandit-report.json
reports/bandit-report.csv
virus-scans:
if: ${{ (inputs.target == 'virus-scan') || (inputs.target == 'all-scans') }}
permissions:
contents: read
packages: read # needed for actions/checkout
name: Run Virus Scan
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- ubuntu_version: ubuntu24
steps:
- name: Check out edge-ai-libraries repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Run Virus Scan
run: |
mkdir -p reports
docker pull clamav/clamav
echo "### Virus Scan Results" >> $GITHUB_STEP_SUMMARY
docker run --rm -v "${{ github.workspace }}:/src" clamav/clamav clamscan -r /src/manufacturing-ai-suite/industrial-edge-insights-time-series/ > ./reports/clamav-report.txt || true
echo "Please find full report in clamav-report.txt" >> $GITHUB_STEP_SUMMARY
- name: Upload Scan Reports
uses: actions/upload-artifact@v4
with:
name: virus-reports
path: reports/clamav-report.txt
DBS_job:
if: ${{ (inputs.target == 'dbs-scan') || (inputs.target == 'all-scans') }}
runs-on: ubuntu-24.04
permissions:
contents: read
packages: read # needed for actions/checkout
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
persist-credentials: false
- name: check the system
run: |
docker ps &&
uname -a &&
docker version &&
git version &&
docker compose version
- name: Checkout docker/docker-bench-security (master)
uses: actions/checkout@v4
with:
repository: docker/docker-bench-security
ref: master
path: docker-bench-security
persist-credentials: false
- name: Build Docker Bench Security
run: |
cd docker-bench-security
docker build --no-cache -t docker-bench-security .
- name: Checkout Time Series Analytics microservice (edge-ai-libraries)
uses: actions/checkout@v4
with:
repository: open-edge-platform/edge-ai-libraries
ref: main
path: edge-ai-libraries
persist-credentials: false
- name: Building Time Series Analytics microservices
run: |
cd ./edge-ai-libraries/microservices/time-series-analytics/docker
docker compose down -v
docker compose build
- name: Deploy Wind Turbine Sample App
run: |
cd manufacturing-ai-suite/industrial-edge-insights-time-series/
make down
# Generate random values for sensitive environment variables
INFLUXDB_USERNAME=$(cat /dev/urandom | tr -dc 'a-zA-Z' | head -c 8)
INFLUXDB_PASSWORD=$(openssl rand -hex 10)
VISUALIZER_GRAFANA_USER=$(cat /dev/urandom | tr -dc 'a-zA-Z' | head -c 8)
VISUALIZER_GRAFANA_PASSWORD=$(openssl rand -hex 10)
MR_PSQL_PASSWORD=$(openssl rand -hex 10)
MR_MINIO_ACCESS_KEY=$(openssl rand -hex 10)
MR_MINIO_SECRET_KEY=$(openssl rand -hex 10)
sed -i "s/INFLUXDB_USERNAME=.*/INFLUXDB_USERNAME=${INFLUXDB_USERNAME}/g" .env
sed -i "s/INFLUXDB_PASSWORD=.*/INFLUXDB_PASSWORD=${INFLUXDB_PASSWORD}/g" .env
sed -i "s/VISUALIZER_GRAFANA_USER=.*/VISUALIZER_GRAFANA_USER=${VISUALIZER_GRAFANA_USER}/g" .env
sed -i "s/VISUALIZER_GRAFANA_PASSWORD=.*/VISUALIZER_GRAFANA_PASSWORD=${VISUALIZER_GRAFANA_PASSWORD}/g" .env
sed -i "s/MR_PSQL_PASSWORD=.*/MR_PSQL_PASSWORD=${MR_PSQL_PASSWORD}/g" .env
sed -i "s/MR_MINIO_ACCESS_KEY=.*/MR_MINIO_ACCESS_KEY=${MR_MINIO_ACCESS_KEY}/g" .env
sed -i "s/MR_MINIO_SECRET_KEY=.*/MR_MINIO_SECRET_KEY=${MR_MINIO_SECRET_KEY}/g" .env
make build
echo "Deploying using opcua ingestion"
make up_opcua_ingestion app=wind-turbine-anomaly-detection
- name: DBS download and scan for Wind Turbine Sample App
run: |
cd manufacturing-ai-suite/industrial-edge-insights-time-series/
docker run --rm --net host --pid host --userns host --cap-add audit_control \
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
-v /etc:/etc:ro \
-v /usr/bin/containerd:/usr/bin/containerd:ro \
-v /usr/bin/runc:/usr/bin/runc:ro \
-v /usr/lib/systemd:/usr/lib/systemd:ro \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--label docker_bench_security \
docker-bench-security > dbs_scan_windturbine_sample_app.txt
- name: Undeploy Time Series Analytics microservice
run: |
cd manufacturing-ai-suite/industrial-edge-insights-time-series/
make down
- name: Upload Scan artifact to Github
uses: actions/upload-artifact@v4
with:
name: DBS_time-series-analytics
path: manufacturing-ai-suite/industrial-edge-insights-time-series/dbs_scan_*
codeql-job:
name: CodeQL Scan - Python
if: ${{ (inputs.target == 'codeql-scan') || (inputs.target == 'all-scans') }}
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ubuntu-24.04
permissions:
security-events: write
packages: read
actions: read
contents: read
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
with:
languages: 'python'
source-root: manufacturing-ai-suite/industrial-edge-insights-time-series/
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
with:
category: "/language:python"
upload: "never"
output: results
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install dependencies
run: |
pip install reportlab
- name: Convert SARIF to PDF
run: |
python - <<EOF
import json
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
def parse_sarif(sarif_file):
with open(sarif_file, 'r') as file:
data = json.load(file)
return data
def generate_pdf(data, output_file):
c = canvas.Canvas(output_file, pagesize=letter)
width, height = letter
c.drawString(100, height - 100, "SARIF Report")
y_position = height - 150
for run in data.get('runs', []):
for result in run.get('results', []):
message = result.get('message', {}).get('text', 'No message')
severity = result.get('level', 'Unknown')
location = result.get('locations', [{}])[0].get('physicalLocation', {}).get('artifactLocation', {}).get('uri', 'Unknown location')
c.drawString(100, y_position, f"Message: {message}")
c.drawString(100, y_position - 20, f"Severity: {severity}")
c.drawString(100, y_position - 40, f"Location: {location}")
y_position -= 80
if y_position < 100:
c.showPage()
y_position = height - 100
c.save()
sarif_data = parse_sarif('results/python.sarif')
generate_pdf(sarif_data, 'sarif_report.pdf')
EOF
- name: Create ZIP File
run: |
zip codeql_reports.zip results/python.sarif sarif_report.pdf
- name: Upload ZIP Artifact
uses: actions/upload-artifact@v4
with:
name: Wind Turbine CodeQL Reports
path: codeql_reports.zip