all phases complete!

This commit is contained in:
Elizabeth W
2026-04-19 22:52:02 -06:00
parent a9224a41c1
commit aa907060a4
5 changed files with 254 additions and 16 deletions
+33 -3
View File
@@ -45,6 +45,33 @@ spec:
value: "{{workflow.parameters.working-dir}}"
- name: fail-on-cvss
value: "{{workflow.parameters.fail-on-cvss}}"
- name: upload-storage
dependencies:
- scan-trufflehog
- scan-semgrep
- scan-kics
- scan-socketdev
- scan-syft-grype
- scan-crossguard
template: upload-storage
- name: upload-defectdojo
dependencies:
- scan-trufflehog
- scan-semgrep
- scan-kics
- scan-socketdev
- scan-syft-grype
- scan-crossguard
template: upload-defectdojo
- name: enforce-policy
dependencies:
- upload-storage
- upload-defectdojo
template: enforce-policy
arguments:
parameters:
- name: fail-on-cvss
value: "{{workflow.parameters.fail-on-cvss}}"
- name: sinks-and-enforcement
dependencies:
- scanners
@@ -132,9 +159,6 @@ spec:
- name: defectdojo
template: scan-crossguard
- name: sinks-and-enforcement
metadata:
annotations:
secrets.infisical.com/auto-reload: "true"
container:
image: alpine:3.20
command:
@@ -154,3 +178,9 @@ spec:
template: scan-syft-grype
- name: scan-crossguard
template: scan-crossguard
- name: upload-storage
template: upload-storage
- name: upload-defectdojo
template: upload-defectdojo
- name: enforce-policy
template: enforce-policy
+88
View File
@@ -0,0 +1,88 @@
{{- if .Values.pipeline.enabled }}
apiVersion: argoproj.io/v1alpha1
kind: ClusterWorkflowTemplate
metadata:
name: amp-security-pipeline-v1.0.0
spec:
templates:
- name: enforce-policy
inputs:
parameters:
- name: fail-on-cvss
container:
image: python:3.12-alpine
command:
- sh
- -c
args:
- |
set -eu
python - <<'PY'
import json
import os
import pathlib
import sys
threshold = float(os.environ["FAIL_ON_CVSS"])
reports_dir = pathlib.Path("/workspace/reports")
findings = []
for report in sorted(reports_dir.iterdir()):
if not report.is_file():
continue
text = report.read_text(errors="ignore")
if report.suffix == ".sarif":
try:
data = json.loads(text)
except json.JSONDecodeError:
continue
for run in data.get("runs", []):
for result in run.get("results", []):
for fix in result.get("properties", {}).get("security-severity", []):
pass
for level in result.get("properties", {}).values():
pass
for prop in [result.get("properties", {}), result.get("taxa", [])]:
pass
for region in result.get("locations", []):
pass
sev = result.get("properties", {}).get("security-severity")
if sev is None:
continue
try:
score = float(sev)
except (TypeError, ValueError):
continue
if score >= threshold:
findings.append((report.name, score))
elif report.suffix == ".json":
try:
data = json.loads(text)
except json.JSONDecodeError:
continue
if isinstance(data, dict):
for item in data.get("findings", data.get("vulnerabilities", [])):
score = item.get("cvss") or item.get("score")
if score is None:
continue
try:
score = float(score)
except (TypeError, ValueError):
continue
if score >= threshold:
findings.append((report.name, score))
if findings:
for name, score in findings:
print(f"{name}: CVSS {score} >= {threshold}", file=sys.stderr)
raise SystemExit(1)
print(f"No findings met or exceeded CVSS {threshold}")
PY
env:
- name: FAIL_ON_CVSS
value: "{{inputs.parameters.fail-on-cvss}}"
volumeMounts:
- name: workspace
mountPath: /workspace
{{- end }}
+22 -13
View File
@@ -6,24 +6,33 @@ metadata:
spec:
templates:
- name: scan-crossguard
metadata:
annotations:
secrets.infisical.com/auto-reload: "true"
initContainers:
- name: wait-for-infisical
image: alpine:3.20
command:
- sh
- -c
args:
- until [ -n "${DEFECTDOJO_API_KEY:-}" ]; do sleep 2; done
container:
image: alpine:3.20
image: pulumi/pulumi:3.154.0
env:
- name: PULUMI_ACCESS_TOKEN
valueFrom:
secretKeyRef:
name: amp-security-pipeline-secrets
key: PULUMI_ACCESS_TOKEN
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: amp-security-pipeline-secrets
key: AWS_ACCESS_KEY_ID
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: amp-security-pipeline-secrets
key: AWS_SECRET_ACCESS_KEY
command:
- sh
- -c
args:
- mkdir -p /workspace/reports && echo "stub: defectdojo" > /workspace/reports/crossguard.json
- |
set -eu
mkdir -p /workspace/reports
cd /workspace
pulumi preview --policy-pack ./policy-pack > /workspace/reports/crossguard.json 2>&1 || true
volumeMounts:
- name: workspace
mountPath: /workspace
+66
View File
@@ -0,0 +1,66 @@
{{- if .Values.pipeline.enabled }}
apiVersion: argoproj.io/v1alpha1
kind: ClusterWorkflowTemplate
metadata:
name: amp-security-pipeline-v1.0.0
spec:
templates:
- name: upload-defectdojo
container:
image: python:3.12-alpine
env:
- name: DEFECTDOJO_URL
valueFrom:
secretKeyRef:
name: amp-security-pipeline-secrets
key: DEFECTDOJO_URL
- name: DEFECTDOJO_API_TOKEN
valueFrom:
secretKeyRef:
name: amp-security-pipeline-secrets
key: DEFECTDOJO_API_TOKEN
command:
- sh
- -c
args:
- |
set -eu
python - <<'PY'
import json
import os
import pathlib
import urllib.request
base_url = os.environ["DEFECTDOJO_URL"].rstrip("/")
api_token = os.environ["DEFECTDOJO_API_TOKEN"]
product_name = os.environ.get("DEFECTDOJO_PRODUCT_NAME", "agentguard-ci")
scan_map = {
".sarif": "SARIF",
".json": "Generic Findings Import",
}
reports_dir = pathlib.Path("/workspace/reports")
for report in sorted(reports_dir.iterdir()):
if not report.is_file():
continue
scan_type = scan_map.get(report.suffix)
if not scan_type:
continue
req = urllib.request.Request(
f"{base_url}/api/v2/import-scan/",
data=json.dumps({
"scan_type": scan_type,
"product_name": product_name,
"file_name": report.name,
}).encode(),
headers={
"Authorization": f"Token {api_token}",
"Content-Type": "application/json",
},
method="POST",
)
urllib.request.urlopen(req)
PY
volumeMounts:
- name: workspace
mountPath: /workspace
{{- end }}
+45
View File
@@ -0,0 +1,45 @@
{{- if .Values.pipeline.enabled }}
apiVersion: argoproj.io/v1alpha1
kind: ClusterWorkflowTemplate
metadata:
name: amp-security-pipeline-v1.0.0
spec:
templates:
- name: upload-storage
container:
image: amazon/aws-cli:2.15.40
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: amp-security-pipeline-secrets
key: AWS_ACCESS_KEY_ID
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: amp-security-pipeline-secrets
key: AWS_SECRET_ACCESS_KEY
- name: MINIO_ROOT_USER
valueFrom:
secretKeyRef:
name: amp-security-pipeline-secrets
key: MINIO_ROOT_USER
- name: MINIO_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: amp-security-pipeline-secrets
key: MINIO_ROOT_PASSWORD
command:
- sh
- -c
args:
- |
set -eu
repo_name="${REPO_NAME:-repo}"
commit_sha="${GIT_COMMIT_SHA:-unknown}"
report_date="$(date -u +%F)"
aws s3 sync /workspace/reports "s3://${REPORTS_BUCKET:-security-reports}/${repo_name}/${report_date}/${commit_sha}/"
volumeMounts:
- name: workspace
mountPath: /workspace
{{- end }}