add working dir as input to step
This commit is contained in:
@@ -1,17 +1,18 @@
|
|||||||
{{- define "template.enforce-policy" }}
|
{{- define "template.enforce-policy" -}}
|
||||||
- name: enforce-policy
|
- name: enforce-policy
|
||||||
inputs:
|
inputs:
|
||||||
parameters:
|
parameters:
|
||||||
- name: fail-on-cvss
|
- name: fail-on-cvss
|
||||||
container:
|
container:
|
||||||
image: agentguard-tools:latest
|
image: "{{ .Values.pipeline.toolsImage.repository }}:{{ .Values.pipeline.toolsImage.tag }}"
|
||||||
command:
|
imagePullPolicy: {{ .Values.pipeline.toolsImage.pullPolicy }}
|
||||||
- node
|
command:
|
||||||
- /app/dist/enforce-policy.js
|
- node
|
||||||
env:
|
- /app/dist/enforce-policy.js
|
||||||
- name: FAIL_ON_CVSS
|
env:
|
||||||
value: "{{inputs.parameters.fail-on-cvss}}"
|
- name: FAIL_ON_CVSS
|
||||||
volumeMounts:
|
value: {{ `{{inputs.parameters.fail-on-cvss}}` | quote }}
|
||||||
- name: workspace
|
volumeMounts:
|
||||||
mountPath: /workspace
|
- name: workspace
|
||||||
|
mountPath: /workspace
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,22 +1,25 @@
|
|||||||
{{- define "template.scan-kics" }}
|
{{- define "template.scan-kics" -}}
|
||||||
- name: scan-kics
|
- name: scan-kics
|
||||||
container:
|
inputs:
|
||||||
image: checkmarx/kics:1.7.14
|
parameters:
|
||||||
command:
|
- name: working-dir
|
||||||
- sh
|
container:
|
||||||
- -c
|
image: {{ .Values.images.kics | quote }}
|
||||||
args:
|
command:
|
||||||
- |
|
- sh
|
||||||
set -eu
|
- -c
|
||||||
mkdir -p /workspace/reports
|
args:
|
||||||
kics scan -p /workspace -o /workspace/reports --report-formats sarif,json --output-name kics || true
|
- |
|
||||||
if [ -f /workspace/reports/kics.sarif ]; then
|
set -eu
|
||||||
exit 0
|
mkdir -p /workspace/reports
|
||||||
fi
|
kics scan -p "/workspace/{{ `{{inputs.parameters.working-dir}}` }}" -o /workspace/reports --report-formats sarif,json --output-name kics || true
|
||||||
if [ -f /workspace/reports/kics.json ]; then
|
if [ -f /workspace/reports/kics.sarif ]; then
|
||||||
cp /workspace/reports/kics.json /workspace/reports/kics.sarif
|
exit 0
|
||||||
fi
|
fi
|
||||||
volumeMounts:
|
if [ -f /workspace/reports/kics.json ]; then
|
||||||
- name: workspace
|
cp /workspace/reports/kics.json /workspace/reports/kics.sarif
|
||||||
mountPath: /workspace
|
fi
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /workspace
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
{{- define "template.scan-semgrep" }}
|
{{- define "template.scan-semgrep" -}}
|
||||||
- name: scan-semgrep
|
- name: scan-semgrep
|
||||||
container:
|
inputs:
|
||||||
image: returntocorp/semgrep:1.85.0
|
parameters:
|
||||||
command:
|
- name: working-dir
|
||||||
- sh
|
container:
|
||||||
- -c
|
image: {{ .Values.images.semgrep | quote }}
|
||||||
args:
|
command:
|
||||||
- |
|
- sh
|
||||||
set -eu
|
- -c
|
||||||
mkdir -p /workspace/reports
|
args:
|
||||||
semgrep scan --config auto --sarif --output /workspace/reports/semgrep.sarif /workspace || true
|
- |
|
||||||
volumeMounts:
|
set -eu
|
||||||
- name: workspace
|
mkdir -p /workspace/reports
|
||||||
mountPath: /workspace
|
semgrep scan --config auto --sarif --output /workspace/reports/semgrep.sarif "/workspace/{{ `{{inputs.parameters.working-dir}}` }}" || true
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /workspace
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,22 +1,25 @@
|
|||||||
{{- define "template.scan-socketdev" }}
|
{{- define "template.scan-socketdev" -}}
|
||||||
- name: scan-socketdev
|
- name: scan-socketdev
|
||||||
container:
|
inputs:
|
||||||
image: socketdev/socketcli:latest
|
parameters:
|
||||||
env:
|
- name: working-dir
|
||||||
- name: SOCKET_DEV_API_KEY
|
container:
|
||||||
valueFrom:
|
image: {{ .Values.images.socketdev | quote }}
|
||||||
secretKeyRef:
|
env:
|
||||||
name: amp-security-pipeline-secrets
|
- name: SOCKET_DEV_API_KEY
|
||||||
key: SOCKET_DEV_API_KEY
|
valueFrom:
|
||||||
command:
|
secretKeyRef:
|
||||||
- sh
|
name: amp-security-pipeline-secrets
|
||||||
- -c
|
key: SOCKET_DEV_API_KEY
|
||||||
args:
|
command:
|
||||||
- |
|
- sh
|
||||||
set -eu
|
- -c
|
||||||
mkdir -p /workspace/reports
|
args:
|
||||||
socketdev scan /workspace --format json --output /workspace/reports/socketdev.json || true
|
- |
|
||||||
volumeMounts:
|
set -eu
|
||||||
- name: workspace
|
mkdir -p /workspace/reports
|
||||||
mountPath: /workspace
|
socketdev scan "/workspace/{{ `{{inputs.parameters.working-dir}}` }}" --format json --output /workspace/reports/socketdev.json || true
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /workspace
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
{{- define "template.scan-syft-grype" }}
|
{{- define "template.scan-syft-grype" -}}
|
||||||
- name: scan-syft-grype
|
- name: scan-syft-grype
|
||||||
container:
|
inputs:
|
||||||
image: anchore/syft:latest
|
parameters:
|
||||||
command:
|
- name: working-dir
|
||||||
- sh
|
container:
|
||||||
- -c
|
image: {{ .Values.images.syftGrype | quote }}
|
||||||
args:
|
command:
|
||||||
- |
|
- sh
|
||||||
set -eu
|
- -c
|
||||||
mkdir -p /workspace/reports
|
args:
|
||||||
syft scan dir:/workspace -o cyclonedx-json=/workspace/reports/sbom.json || true
|
- |
|
||||||
grype sbom:/workspace/reports/sbom.json -o sarif=/workspace/reports/grype.sarif || true
|
set -eu
|
||||||
volumeMounts:
|
mkdir -p /workspace/reports
|
||||||
- name: workspace
|
syft scan dir:/workspace/{{ `{{inputs.parameters.working-dir}}` }} -o cyclonedx-json=/workspace/reports/sbom.json || true
|
||||||
mountPath: /workspace
|
grype sbom:/workspace/reports/sbom.json -o sarif=/workspace/reports/grype.sarif || true
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /workspace
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
{{- define "template.scan-trufflehog" }}
|
{{- define "template.scan-trufflehog" -}}
|
||||||
- name: scan-trufflehog
|
- name: scan-trufflehog
|
||||||
container:
|
inputs:
|
||||||
image: trufflesecurity/trufflehog:latest
|
parameters:
|
||||||
command:
|
- name: working-dir
|
||||||
- sh
|
container:
|
||||||
- -c
|
image: {{ .Values.images.trufflehog | quote }}
|
||||||
args:
|
command:
|
||||||
- |
|
- sh
|
||||||
set -eu
|
- -c
|
||||||
mkdir -p /workspace/reports
|
args:
|
||||||
trufflehog filesystem /workspace --json > /workspace/reports/trufflehog.json || true
|
- |
|
||||||
volumeMounts:
|
set -eu
|
||||||
- name: workspace
|
mkdir -p /workspace/reports
|
||||||
mountPath: /workspace
|
trufflehog filesystem "/workspace/{{ `{{inputs.parameters.working-dir}}` }}" --json > /workspace/reports/trufflehog.json || true
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /workspace
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,22 +1,39 @@
|
|||||||
{{- define "template.upload-defectdojo" }}
|
{{- define "template.upload-defectdojo" -}}
|
||||||
- name: upload-defectdojo
|
- name: upload-defectdojo
|
||||||
container:
|
container:
|
||||||
image: agentguard-tools:latest
|
image: "{{ .Values.pipeline.toolsImage.repository }}:{{ .Values.pipeline.toolsImage.tag }}"
|
||||||
env:
|
imagePullPolicy: {{ .Values.pipeline.toolsImage.pullPolicy }}
|
||||||
- name: DEFECTDOJO_URL
|
env:
|
||||||
valueFrom:
|
- name: DEFECTDOJO_URL
|
||||||
secretKeyRef:
|
valueFrom:
|
||||||
name: amp-security-pipeline-secrets
|
secretKeyRef:
|
||||||
key: DEFECTDOJO_URL
|
name: amp-security-pipeline-secrets
|
||||||
- name: DEFECTDOJO_API_TOKEN
|
key: DEFECTDOJO_URL
|
||||||
valueFrom:
|
- name: DEFECTDOJO_API_TOKEN
|
||||||
secretKeyRef:
|
valueFrom:
|
||||||
name: amp-security-pipeline-secrets
|
secretKeyRef:
|
||||||
key: DEFECTDOJO_API_TOKEN
|
name: amp-security-pipeline-secrets
|
||||||
command:
|
key: DEFECTDOJO_API_TOKEN
|
||||||
- node
|
- name: DEFECTDOJO_PRODUCT_TYPE_NAME
|
||||||
- /app/dist/upload-defectdojo.js
|
value: {{ .Values.defectdojo.productTypeName | quote }}
|
||||||
volumeMounts:
|
- name: DEFECTDOJO_PRODUCT_NAME
|
||||||
- name: workspace
|
value: {{ .Values.defectdojo.productName | quote }}
|
||||||
mountPath: /workspace
|
- name: DEFECTDOJO_ENGAGEMENT_NAME
|
||||||
|
value: {{ .Values.defectdojo.engagementName | quote }}
|
||||||
|
- name: DEFECTDOJO_MINIMUM_SEVERITY
|
||||||
|
value: {{ .Values.defectdojo.minimumSeverity | quote }}
|
||||||
|
- name: DEFECTDOJO_ACTIVE
|
||||||
|
value: {{ .Values.defectdojo.active | quote }}
|
||||||
|
- name: DEFECTDOJO_VERIFIED
|
||||||
|
value: {{ .Values.defectdojo.verified | quote }}
|
||||||
|
- name: DEFECTDOJO_CLOSE_OLD_FINDINGS
|
||||||
|
value: {{ .Values.defectdojo.closeOldFindings | quote }}
|
||||||
|
- name: DEFECTDOJO_AUTO_CREATE_CONTEXT
|
||||||
|
value: {{ .Values.defectdojo.autoCreateContext | quote }}
|
||||||
|
command:
|
||||||
|
- node
|
||||||
|
- /app/dist/upload-defectdojo.js
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /workspace
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,39 +1,49 @@
|
|||||||
{{- define "template.upload-storage" }}
|
{{- define "template.upload-storage" -}}
|
||||||
- name: upload-storage
|
- name: upload-storage
|
||||||
container:
|
container:
|
||||||
image: amazon/aws-cli:2.15.40
|
image: {{ .Values.images.awsCli | quote }}
|
||||||
env:
|
env:
|
||||||
- name: AWS_ACCESS_KEY_ID
|
- name: AWS_ACCESS_KEY_ID
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: amp-security-pipeline-secrets
|
name: amp-security-pipeline-secrets
|
||||||
key: AWS_ACCESS_KEY_ID
|
key: AWS_ACCESS_KEY_ID
|
||||||
- name: AWS_SECRET_ACCESS_KEY
|
- name: AWS_SECRET_ACCESS_KEY
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: amp-security-pipeline-secrets
|
name: amp-security-pipeline-secrets
|
||||||
key: AWS_SECRET_ACCESS_KEY
|
key: AWS_SECRET_ACCESS_KEY
|
||||||
- name: MINIO_ROOT_USER
|
- name: MINIO_ROOT_USER
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: amp-security-pipeline-secrets
|
name: amp-security-pipeline-secrets
|
||||||
key: MINIO_ROOT_USER
|
key: MINIO_ROOT_USER
|
||||||
- name: MINIO_ROOT_PASSWORD
|
- name: MINIO_ROOT_PASSWORD
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: amp-security-pipeline-secrets
|
name: amp-security-pipeline-secrets
|
||||||
key: MINIO_ROOT_PASSWORD
|
key: MINIO_ROOT_PASSWORD
|
||||||
command:
|
- name: REPORTS_BUCKET
|
||||||
- sh
|
value: {{ .Values.storage.reportsBucket | quote }}
|
||||||
- -c
|
- name: REPO_NAME
|
||||||
args:
|
value: {{ .Values.pipeline.repoName | quote }}
|
||||||
- |
|
- name: STORAGE_ENDPOINT
|
||||||
set -eu
|
value: {{ .Values.storage.endpoint | quote }}
|
||||||
repo_name="${REPO_NAME:-repo}"
|
command:
|
||||||
commit_sha="${GIT_COMMIT_SHA:-unknown}"
|
- sh
|
||||||
report_date="$(date -u +%F)"
|
- -c
|
||||||
aws s3 sync /workspace/reports "s3://${REPORTS_BUCKET:-security-reports}/${repo_name}/${report_date}/${commit_sha}/"
|
args:
|
||||||
volumeMounts:
|
- |
|
||||||
- name: workspace
|
set -eu
|
||||||
mountPath: /workspace
|
commit_sha="${GIT_COMMIT_SHA:-unknown}"
|
||||||
|
report_date="$(date -u +%F)"
|
||||||
|
sync_target="s3://${REPORTS_BUCKET}/${REPO_NAME}/${report_date}/${commit_sha}/"
|
||||||
|
if [ -n "${STORAGE_ENDPOINT}" ]; then
|
||||||
|
aws --endpoint-url "${STORAGE_ENDPOINT}" s3 sync /workspace/reports "${sync_target}"
|
||||||
|
else
|
||||||
|
aws s3 sync /workspace/reports "${sync_target}"
|
||||||
|
fi
|
||||||
|
volumeMounts:
|
||||||
|
- name: workspace
|
||||||
|
mountPath: /workspace
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,68 +1,102 @@
|
|||||||
import * as fs from 'node:fs';
|
import { promises as fs } from 'node:fs';
|
||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
export async function uploadReports() {
|
function resolveScanType(fileName: string): string | undefined {
|
||||||
const baseUrl = (process.env.DEFECTDOJO_URL || "").replace(/\/$/, "");
|
if (fileName.endsWith('.sarif')) {
|
||||||
|
return 'SARIF';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileName === 'generic-findings.json') {
|
||||||
|
return 'Generic Findings Import';
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function uploadReports(): Promise<void> {
|
||||||
|
const baseUrl = (process.env.DEFECTDOJO_URL || '').replace(/\/$/, '');
|
||||||
const apiToken = process.env.DEFECTDOJO_API_TOKEN;
|
const apiToken = process.env.DEFECTDOJO_API_TOKEN;
|
||||||
const productName = process.env.DEFECTDOJO_PRODUCT_NAME || "agentguard-ci";
|
const productTypeName = process.env.DEFECTDOJO_PRODUCT_TYPE_NAME || 'Homelab Security';
|
||||||
|
const productName = process.env.DEFECTDOJO_PRODUCT_NAME || 'agentguard-ci';
|
||||||
|
const engagementName = process.env.DEFECTDOJO_ENGAGEMENT_NAME || 'Default Pipeline';
|
||||||
|
const minimumSeverity = process.env.DEFECTDOJO_MINIMUM_SEVERITY || 'Info';
|
||||||
|
const active = process.env.DEFECTDOJO_ACTIVE || 'true';
|
||||||
|
const verified = process.env.DEFECTDOJO_VERIFIED || 'true';
|
||||||
|
const closeOldFindings = process.env.DEFECTDOJO_CLOSE_OLD_FINDINGS || 'false';
|
||||||
|
const autoCreateContext = process.env.DEFECTDOJO_AUTO_CREATE_CONTEXT || 'true';
|
||||||
|
|
||||||
if (!baseUrl || !apiToken) {
|
if (!baseUrl || !apiToken) {
|
||||||
console.error("DEFECTDOJO_URL and DEFECTDOJO_API_TOKEN must be set.");
|
console.error('DEFECTDOJO_URL and DEFECTDOJO_API_TOKEN must be set.');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const scanMap: Record<string, string> = {
|
const reportsDir = '/workspace/reports';
|
||||||
".sarif": "SARIF",
|
let fileNames: string[];
|
||||||
".json": "Generic Findings Import",
|
|
||||||
};
|
|
||||||
|
|
||||||
const reportsDir = "/workspace/reports";
|
try {
|
||||||
if (!fs.existsSync(reportsDir)) {
|
fileNames = (await fs.readdir(reportsDir)).sort();
|
||||||
console.log("No reports directory found.");
|
} catch {
|
||||||
|
console.log('No reports directory found.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const files = fs.readdirSync(reportsDir).sort();
|
for (const fileName of fileNames) {
|
||||||
|
const fullPath = path.join(reportsDir, fileName);
|
||||||
for (const file of files) {
|
const stats = await fs.stat(fullPath);
|
||||||
const fullPath = path.join(reportsDir, file);
|
if (!stats.isFile()) {
|
||||||
if (!fs.statSync(fullPath).isFile()) continue;
|
continue;
|
||||||
|
}
|
||||||
const ext = path.extname(file);
|
|
||||||
const scanType = scanMap[ext];
|
const scanType = resolveScanType(fileName);
|
||||||
if (!scanType) continue;
|
if (!scanType) {
|
||||||
|
console.log(`Skipping ${fileName}: no DefectDojo importer is configured for this file yet.`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reportContents = await fs.readFile(fullPath);
|
||||||
|
const form = new FormData();
|
||||||
|
form.append('scan_type', scanType);
|
||||||
|
form.append('product_type_name', productTypeName);
|
||||||
|
form.append('product_name', productName);
|
||||||
|
form.append('engagement_name', engagementName);
|
||||||
|
form.append('test_title', fileName);
|
||||||
|
form.append('minimum_severity', minimumSeverity);
|
||||||
|
form.append('active', active);
|
||||||
|
form.append('verified', verified);
|
||||||
|
form.append('close_old_findings', closeOldFindings);
|
||||||
|
form.append('auto_create_context', autoCreateContext);
|
||||||
|
form.append('file', new Blob([reportContents]), fileName);
|
||||||
|
|
||||||
|
console.log(`Uploading ${fileName} to DefectDojo as ${scanType}...`);
|
||||||
|
|
||||||
console.log(`Uploading ${file} as ${scanType}...`);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${baseUrl}/api/v2/import-scan/`, {
|
const response = await fetch(`${baseUrl}/api/v2/reimport-scan/`, {
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
"Authorization": `Token ${apiToken}`,
|
Authorization: `Token ${apiToken}`,
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: form,
|
||||||
scan_type: scanType,
|
|
||||||
product_name: productName,
|
|
||||||
file_name: file,
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
console.error(`Failed to upload ${file}: ${response.status} ${response.statusText} - ${text}`);
|
console.error(`Failed to upload ${fileName}: ${response.status} ${response.statusText} - ${text}`);
|
||||||
process.exitCode = 1;
|
process.exitCode = 1;
|
||||||
} else {
|
continue;
|
||||||
console.log(`Successfully uploaded ${file}`);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
console.error(`Network error uploading ${file}:`, e);
|
console.log(`Successfully uploaded ${fileName}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Network error uploading ${fileName}:`, error);
|
||||||
process.exitCode = 1;
|
process.exitCode = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
||||||
uploadReports();
|
uploadReports().catch((error: unknown) => {
|
||||||
|
console.error('Unexpected upload failure:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user