Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions docs/Docusaurus/docs/modules/engine_core.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,7 @@ Configuration of the driven adapters in the main layer and management of on/off
"RECURSE": true,
"INSTALL_DEPENDENCIES": true,
"DEBUG_PIPELINES": ["pipeline_name1", "pipeline_name2"],
"LIFECYCLE_PIPELINES": {
"pipeline_name1": "pre-build"
},
"REQUIRED_ONLY_PIPELINES": ["pipeline_name1", "pipeline_name2"],
"BREAK_ON_BUILD_FAILURE": true,
"BUILD_FAILURE_PATTERNS": ["BUILD FAILED", "BUILD FAILURE", "npm ERR!"],
"OVERRIDE_REGISTRIES": false,
Expand Down
5 changes: 5 additions & 0 deletions docs/Docusaurus/docs/modules/engine_sca/engine_container.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ Defines exclusion rules for repositories and specific vulnerability findings.
"where": "all",
"create_date": "24012023",
"expired_date": "22092023",
"severity": "high",
"hu": "345345",
"reason": "False Positive"
}
Expand All @@ -243,6 +244,7 @@ Defines exclusion rules for repositories and specific vulnerability findings.
"cve_id": "CVE-2023-6237",
"expired_date": "21092024",
"create_date": "24012023",
"severity": "high",
"hu": "345345"
}
]
Expand All @@ -263,6 +265,7 @@ Defines exclusion rules for repositories and specific vulnerability findings.
"cve_id": "CVE-2023-6237",
"expired_date": "21092024",
"create_date": "24012023",
"severity": "high",
"hu": "345345"
}
]
Expand Down Expand Up @@ -292,6 +295,8 @@ Defines exclusion rules for repositories and specific vulnerability findings.
- `where`: Scope of exclusion (`"all"` for global or specific image/path)
- `create_date`: Date when exclusion was created (format: DDMMYYYY)
- `expired_date`: Expiration date for the exclusion (format: DDMMYYYY)
- `severity`: Vulnerability severity level in lowercase (e.g., `"critical"`, `"high"`, `"medium"`, `"low"`) used to match against the finding's severity
- `priority`: Alternative to `severity` per the `Exclusions` model - equally interchangeable, since an exclusion is applied when either `severity` or `priority` matches the finding (e.g., `"Very Critical"`, `"Critical"`, `"High"`, `"Medium Low"`)
- `hu`: Human user identifier for audit trail
- `reason`: Justification for exclusion (e.g., `"False Positive"`, `"Business Risk Accepted"`)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ Defines exclusion rules for repositories and specific vulnerability findings.
"where": "all",
"create_date": "19022024",
"expired_date": "undefined",
"severity": "high",
"hu": "4662904"
}
]
Expand All @@ -132,6 +133,7 @@ Defines exclusion rules for repositories and specific vulnerability findings.
"where": "all",
"create_date": "19022024",
"expired_date": "undefined",
"severity": "high",
"hu": "4662904"
}
]
Expand All @@ -158,6 +160,8 @@ Each exclusion entry contains:
- `where`: Scope of exclusion (`"all"` for global or specific dependency/path)
- `create_date`: Date when exclusion was created (format: DDMMYYYY)
- `expired_date`: Expiration date for the exclusion (`"undefined"` for permanent exclusions)
- `severity`: Vulnerability severity level in lowercase (e.g., `"critical"`, `"high"`, `"medium"`, `"low"`) used to match against the finding's severity
- `priority`: Alternative to `severity` per the `Exclusions` model - equally interchangeable, since an exclusion is applied when either `severity` or `priority` matches the finding (e.g., `"Very Critical"`, `"Critical"`, `"High"`, `"Medium Low"`)
- `hu`: Human user identifier for audit trail

## Main Responsibilities
Expand Down
4 changes: 1 addition & 3 deletions example_remote_config_local/engine_core/ConfigTool.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,7 @@
"EXCLUDE_PATHS": ["**/test/**"],
"RECURSE": true,
"DEBUG_PIPELINES": ["pipeline_name1", "pipeline_name2"],
"LIFECYCLE_PIPELINES": {
"pipeline_name1": "pre-build"
},
"REQUIRED_ONLY_PIPELINES": ["pipeline_name1", "pipeline_name2"],
"BREAK_ON_BUILD_FAILURE": true,
"BUILD_FAILURE_PATTERNS": ["BUILD FAILED", "BUILD FAILURE", "npm ERR!"],
"OVERRIDE_REGISTRIES": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"where": "all",
"create_date": "24012023",
"expired_date": "22092023",
"severity": "high",
"hu": "345345",
"reason": "False Positive"
}
Expand All @@ -28,6 +29,7 @@
"cve_id": "CVE-2023-6237",
"expired_date": "21092024",
"create_date": "24012023",
"severity": "high",
"hu": "345345"
}
]
Expand All @@ -48,6 +50,7 @@
"cve_id": "CVE-2023-6237",
"expired_date": "21092024",
"create_date": "24012023",
"severity": "high",
"hu": "345345"
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"where": "all",
"create_date": "19022024",
"expired_date": "undefined",
"severity": "high",
"hu": "4662904"
}
]
Expand All @@ -28,6 +29,7 @@
"where": "all",
"create_date": "19022024",
"expired_date": "undefined",
"severity": "high",
"hu": "4662904"
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def get_components(self, artifact, config, service_name) -> "list[Component]":
recurse = config["CDXGEN"].get("RECURSE", True)
install_deps = config["CDXGEN"].get("INSTALL_DEPENDENCIES", True)
debug_pipelines = config["CDXGEN"].get("DEBUG_PIPELINES", [])
lifecycle_pipelines = config["CDXGEN"].get("LIFECYCLE_PIPELINES", {})
required_only_pipelines = config["CDXGEN"].get("REQUIRED_ONLY_PIPELINES", [])
spec_version = config["CDXGEN"].get("SPEC_VERSION", "1.6")
break_on_build_failure = config["CDXGEN"].get("BREAK_ON_BUILD_FAILURE", True)
build_failure_patterns = config["CDXGEN"].get("BUILD_FAILURE_PATTERNS", [])
Expand Down Expand Up @@ -90,50 +90,20 @@ def get_components(self, artifact, config, service_name) -> "list[Component]":
logger.warning(f"{os_platform} is not supported.")
return None

result_sbom = self._run_cdxgen(command_prefix, artifact, service_name, exclude_types, exclude_paths, recurse, install_deps, lifecycle_pipelines, enable_debug, spec_version, failure_patterns)
required_only = service_name in required_only_pipelines if required_only_pipelines else False
result_sbom = self._run_cdxgen(command_prefix, artifact, service_name, exclude_types, exclude_paths, recurse, install_deps, required_only, enable_debug, spec_version, failure_patterns)
return get_list_component(result_sbom, config["CDXGEN"]["OUTPUT_FORMAT"])
except Exception as e:
logger.error(f"Error generating SBOM: {e}")
return None

def _run_cdxgen(self, command_prefix, artifact, service_name, exclude_types, exclude_paths, recurse, install_deps, lifecycle_pipelines, enable_debug=False, spec_version="1.6", failure_patterns=None):
def _run_cdxgen(self, command_prefix, artifact, service_name, exclude_types, exclude_paths, recurse, install_deps, required_only=False, enable_debug=False, spec_version="1.6", failure_patterns=None):
failure_patterns = failure_patterns or []
result_file = f"{service_name}_SBOM.json"
command = [
command_prefix,
artifact,
"-o",
result_file,
"--spec-version",
spec_version
]

if exclude_types:
for ex in exclude_types:
command.extend(
["--exclude-type", ex]
)

if exclude_paths:
for ex in exclude_paths:
command.extend(
["--exclude", ex]
)

if lifecycle_pipelines.get(service_name):
command.extend(
["--lifecycle", lifecycle_pipelines.get(service_name)]
)

if not recurse:
command.append(
"--no-recurse"
)

if not install_deps:
command.append(
"--no-install-deps"
)
command = self._build_cdxgen_command(
command_prefix, artifact, result_file, spec_version,
exclude_types, exclude_paths, required_only, recurse, install_deps
)

try:
result = subprocess.run(
Expand All @@ -142,23 +112,9 @@ def _run_cdxgen(self, command_prefix, artifact, service_name, exclude_types, exc
stderr=subprocess.PIPE,
text=True
)

if enable_debug:
if result.stdout:
logger.info(f"CDXGEN stdout: {result.stdout}")
if result.stderr:
logger.info(f"CDXGEN stderr: {result.stderr}")

matched_pattern = self._detect_build_failure(
f"{result.stdout or ''}\n{result.stderr or ''}", failure_patterns
)
if matched_pattern:
self._remove_incomplete_sbom(result_file)
raise Exception(
f"Detected build failure pattern '{matched_pattern}' in cdxgen output for "
f"'{service_name}'. The underlying build likely failed; aborting to avoid "
"generating an incomplete or empty SBOM."
)
self._log_debug_output(result, enable_debug)
self._check_build_failure(result, failure_patterns, service_name, result_file)

if result.returncode == 0:
print(f"SBOM generated and saved to: {result_file}")
Expand All @@ -169,6 +125,53 @@ def _run_cdxgen(self, command_prefix, artifact, service_name, exclude_types, exc
except Exception as e:
logger.error(f"Error running cdxgen: {e}")

def _build_cdxgen_command(self, command_prefix, artifact, result_file, spec_version, exclude_types, exclude_paths, required_only, recurse, install_deps):
command = [
command_prefix,
artifact,
"-o",
result_file,
"--spec-version",
spec_version
]

for ex in exclude_types or []:
command.extend(["--exclude-type", ex])

for ex in exclude_paths or []:
command.extend(["--exclude", ex])

if required_only:
command.append("--required-only")

if not recurse:
command.append("--no-recurse")

if not install_deps:
command.append("--no-install-deps")

return command

def _log_debug_output(self, result, enable_debug):
if not enable_debug:
return
if result.stdout:
logger.info(f"CDXGEN stdout: {result.stdout}")
if result.stderr:
logger.info(f"CDXGEN stderr: {result.stderr}")

def _check_build_failure(self, result, failure_patterns, service_name, result_file):
matched_pattern = self._detect_build_failure(
f"{result.stdout or ''}\n{result.stderr or ''}", failure_patterns
)
if matched_pattern:
self._remove_incomplete_sbom(result_file)
raise Exception(
f"Detected build failure pattern '{matched_pattern}' in cdxgen output for "
f"'{service_name}'. The underlying build likely failed; aborting to avoid "
"generating an incomplete or empty SBOM."
)

def _detect_build_failure(self, output, patterns):
"""Return the first configured regex pattern that matches the cdxgen output, if any."""
if not output or not patterns:
Expand Down
Loading
Loading