산출물 레퍼런스¶
생성된 SBOM은 CycloneDX 1.6 JSON 형식이고, --spec-version 1.7을 주면 1.7입니다. AI 모델과 데이터셋 SBOM은 항상 1.7입니다. 최종 CycloneDX SBOM을 변환한 SPDX 2.3 JSON 파일은 CLI 스캔에서 --spdx로 만들거나, UI에서는 스캔이 끝난 뒤 결과 화면에서 내보냅니다. 두 경로 모두 같은 변환을 거치므로 결과 파일은 동일합니다. 이때도 정본은 CycloneDX이며, CycloneDX에만 있는 데이터(취약점, bomlens:* 속성, 선언한 AI 서비스가 더하는 services[])는 SPDX 파일로 옮겨지지 않습니다. AI 모델과 데이터셋 스캔은 AI와 Dataset 프로파일을 쓴 SPDX 3.0.1 문서(_bom.spdx3.json, 아래 표)도 만듭니다.
파일명은 {Project}_{Version}_bom.json입니다(예: MyApp_1.0.0_bom.json).
산출물 파일¶
| 파일 | 생성 조건 | 설명 |
|---|---|---|
{Project}_{Version}_bom.json |
항상 | SBOM (CycloneDX 1.6, --spec-version 1.7이면 1.7) |
{Project}_{Version}_bom.refused.json |
선언 파일(--components, 또는 스캔 대상 루트의 sbom-declared.cdx.json)이 거부된 소스 스캔 또는 Yocto 빌드 디렉터리 스캔 |
스캔이 멈춘 시점까지 만든 SBOM으로, 선언 구성요소가 빠져 있다. _bom.json을 쓰지 않고 이 파일이 그 자리를 대신하므로, _bom.json을 가져가는 단계가 불완전한 SBOM을 쓰지 않는다. 스캔은 사유를 출력하고 1로 종료한다. 정규화, 서명, 업로드를 하지 않고 보고서도 만들지 않는다. 웹 UI는 실패한 스캔 화면에서 이 파일을 보거나 내려받게 한다. 같은 프로젝트와 버전을 다음에 스캔하면 지워진다. 무엇을 거부하고, 왜 거부하나? 참고 |
{Project}_{Version}_bom.spdx.json |
--spdx / --all, 또는 UI의 SPDX 2.3으로 내보내기 |
SBOM (SPDX 2.3, CycloneDX 결과를 변환) |
{Project}_{Version}_bom.spdx3.json |
AI 모델과 데이터셋 스캔(--model, --model-file, 데이터셋), --no-spdx3를 주지 않은 경우 |
AI SBOM을 AI와 Dataset 프로파일을 쓴 SPDX 3.0.1 문서(JSON-LD)로 담은 파일. 값은 CycloneDX 결과, 그 결과에 대한 고정 규칙, 모델 공개자의 선언(--ai-declare)에서만 가져오며 추정하지 않는다. SPDX에 "알 수 없음" 값이 없는 필수 필드(모델과 데이터의 공급 주체와 제작 주체, 출시일과 생성일, 내려받기 주소, 문서 작성자)는 선언하기 전까지 비어 있고, 그동안 문서에 초안이라고 표시한다. 기반 모델은 id와 라이선스로만 식별한다. 배포 가중치 범위는 CycloneDX 속성 확장의 bomlens:weights:scope(full, adapter, quantized, merged)로 담는다. --analyze 입력으로는 쓸 수 없다 |
{Project}_{Version}_spdx3-check.json / .md |
SPDX 3.0.1 문서와 함께 | 요소마다 각 필드가 스캔에서 왔는지, 선언에서 왔는지, 비어 있는지와, 채워지지 않은 필수 필드, 모델 공개자가 판단해야 할 항목(개인정보, 안전 위험, 자율성)을 정리한 검사 결과. service.state는 선언한 서비스와 모델 값이 CycloneDX SBOM에 들어 있는지를 알린다. none(선언도 없고 SBOM에도 없음), applied(SBOM이 선언과 같음), pendingScan(둘이 다르며 다시 스캔하면 반영됨) 중 하나다. 법적 자문이 아닌 안내 |
{Project}_{Version}_ai-declaration.template.json |
SPDX 3.0.1 문서와 함께 | 이 스캔의 빈 선언 양식. 모델과 데이터셋, 스캔이 찾은 기반 모델마다 사람이 채울 필드가 들어 있다. 채워서 --ai-declare로 다시 넘긴다 |
{Project}_{Version}_ai-declaration.json |
--ai-declare <file>(받아들인 파일), 또는 웹 UI에서 저장한 선언 |
모델 공개자가 선언한 내용. _vex.json처럼 같은 프로젝트와 버전을 다시 스캔해도 지워지지 않고, 다시 스캔하면 다시 적용된다. 새 스캔에 없는 데이터셋이나 기반 모델을 적은 파일은 거부하며, 그 경우 문서는 초안으로 남는다. 데이터셋 항목에는 sources[]를 적을 수 있다. 허브 데이터셋은 {"ref": "huggingface:<id>", "relation": "extended"}로 적으며 다음 스캔에서 허브에서 읽어 그 데이터셋과 함께 판정한다. 문장으로만 아는 원천은 {"name": "...", "license": "<허브 라이선스 태그나 SPDX ID>", "relation": "other"}로 적으며 SPDX 3.0.1 문서에만 기록되고 확인되지 않은 것으로 표시된다. SPDX ID가 아닌 라이선스는 문장으로만 남는다. 허브에 없는 데이터에는 문장으로 적는 원천만 넣을 수 있다. model.license(허브 라이선스 태그나 SPDX ID)는 모델 자체의 라이선스다. 스캔이 라이선스를 읽지 못했거나 other만 읽었을 때 SPDX 문서에 들어가고(SPDX 라이선스 하나에 대응하는 허브 태그나 LicenseRef-일 때만 SPDX 식으로 기록), 선언만으로 만든 모델은 SBOM에도 이 라이선스가 들어가 이것으로 판정한다. 선언에는 모델을 실행하는 서비스(service)와 모델의 입력과 출력 종류, 규제 제출용 값도 적을 수 있다. 선언한 AI 서비스를 참고한다 |
{Project}_{Version}_component-versions.template.csv |
버전 없는 컴포넌트를 찾은 펌웨어, 루트 파일시스템, 바이너리 스캔 | 그 컴포넌트의 이름을 --component-versions 형식(name,version,reason 머리글의 CSV)으로 적고 버전은 비워 둔 파일. 세 가지 사유를 설명하는 주석 줄이 함께 들어 있고, 이미 사유가 붙은 컴포넌트는 넣지 않는다. 버전을, 버전이 없으면 사유를 채워 --component-versions로 다시 넘긴다 |
{Project}_{Version}_NOTICE.txt / .html |
--notice / --all / 오픈소스 위험 보고서 기본 |
오픈소스 고지문 |
{Project}_{Version}_NOTICE.pdf |
위와 동일한 조건, 이미지에 PDF 렌더러가 포함된 경우(--build-arg SBOM_PDF=true) |
고지문을 PDF로 렌더링한 파일. 렌더러가 없으면 로그만 남기고 건너뜀 |
{Project}_{Version}_security.json / .md / .html |
--security / --all / 오픈소스 위험 보고서 기본 |
Trivy 보안보고서 |
{Project}_{Version}_risk-report.md / .html |
기본(전 모드) — --no-report로 생략 |
오픈소스 위험 보고서 |
{Project}_{Version}_conformance.json / .md / .html |
SBOM을 생성하는 모든 스캔에서 만들어지며 --no-report를 줘도 생략되지 않는다(--no-report는 오픈소스 위험 보고서만 건너뛴다). --analyze도 만든다(그것이 검증 대상이므로) |
적합성 검사 보고서. 모든 SBOM에 규제 크로스워크 집계가 함께 담긴다(EU 사이버복원력법은 BSI TR-03183-2로, 2026년판 미국 SBOM 최소 요소 — 참고용이며 준수 판정 아님). AI SBOM이면 G7 검사와 함께, 아직 비어 있는 권고 요소마다 이를 충족하는 CycloneDX 조각을 담는다. 보고서를 만드는 중 best-effort 후처리 단계가 실패하면 그 단계 이름을 기록하므로, 통과 판정이 모든 단계가 문제없이 돌았다는 증명은 아니다. 통과/실패 판정이나 개별 검사 항목의 상태에는 영향을 주지 않는다. 예시는 적합성 검사 보고서를 참고한다 |
{Project}_{Version}_ai-profile.json / .md |
AI SBOM (--model, 또는 모델 컴포넌트가 있는 SBOM에 --analyze) |
AI 준수 개요: G7 요약, 메울 수 있는 공백과 참고 링크, 라이선스 표시 컴포넌트, 규제 크로스워크, 모델 위험 판정(riskAssessment: 모델별 ok/conditional/caution/review 판정과 조건, 근거, 사용 형태. 법적 자문이 아닌 안내). 같은 요약이 적합성 검사 보고서 HTML 맨 위에 나오므로 별도 HTML은 만들지 않는다 |
{Project}_{Version}_scancode.json |
--deep-license |
scancode 원본 결과 |
{Project}_{Version}_files.json |
소스를 갖는 스캔(펌웨어 스캔은 항상, 다른 모드는 --deep-license가 아직 _scancode.json을 만들지 않은 경우) |
소스 트리 뷰를 뒷받침하는 ScanCode 형식 파일 트리 인벤토리(구조만, 라이선스 없음) |
{Project}_{Version}_source.json |
소스를 갖는 스캔 | 스캔한 트리의 파일 내용 스냅샷, 파일 뷰어를 뒷받침(스캔한 트리 자체는 컨테이너 종료와 함께 사라짐) |
{Project}_{Version}_input.json |
--analyze |
CycloneDX 변환이 덮어쓰기 전, 공급사 SBOM 원본의 포맷·스펙 버전·도구·작성 정보를 보존 |
{Project}_{Version}_yocto_vex.json |
Yocto 빌드(빌드 디렉터리를 직접 지정하거나 그 위에 --analyze) |
빌드가 이미 패치했거나 무관하다고 판정한 CVE 건수 — CycloneDX 결과나 보안보고서에는 미해결 항목만 남아 있어 이 수치를 알 수 없다 |
{Project}_{Version}_vex.json |
웹 UI 전용, 취약점 화면에서 CVE에 판단(영향 있음/영향 없음/이미 고침/조사 중, 근거 메모는 선택)을 저장할 때 생긴다 | 이 스캔에 저장된 판단을 컴포넌트와 CVE 기준으로 담는다. CLI는 만들지 않으며, 해당 스캔에 첫 판단을 저장하기 전에는 없다. 다른 파일과 달리 스캔이 다시 만들지 않고, 같은 프로젝트와 버전을 재스캔해도 지워지지 않는다. 이전 스캔에 남긴 판단은 재스캔 뒤에도 그대로 남는다 |
{Project}_{Version}_vex.cdx.json |
웹 UI 전용, 취약점 화면에서 VEX 내보내기를 누를 때 만들어진다(저장된 판단이 하나 이상 필요) | _vex.json의 판단을 다른 도구가 읽을 수 있는 독립된 CycloneDX VEX 문서로 담는다. 스캔의 SBOM이 1.7이면 1.7, 그 밖에는 1.6으로 쓴다. 네 가지 상태는 CycloneDX analysis.state 값으로 바뀌어 기록되고(영향 있음은 exploitable, 영향 없음은 not_affected, 이미 고침은 resolved, 조사 중은 in_triage), 메모는 analysis.detail에 들어간다. 화면이 자유 서술을 받는 반면 CycloneDX는 정해진 목록만 허용하므로 justification은 쓰지 않는다. 각 항목은 문서 안에 들어 있는 해당 컴포넌트의 사본(이름, 버전, PURL)을 가리키므로 파일 하나로 완결된다. 컴포넌트가 SBOM에 없는 판단은 제외하고 화면이 그 건수를 알려 주며, 펌웨어 발견 항목은 이름과 버전이 바이너리에서 오므로 대표적인 경우다. 내보낼 때마다 새로 만들고, 같은 프로젝트와 버전을 재스캔하면 지워지므로 그 뒤에는 다시 내보낸다 |
{Project}_{Version}_vex_imported.json |
CLI의 --vex <file>, 또는 웹 UI 취약점 화면의 VEX 가져오기에 CycloneDX VEX 문서를 줄 때 생긴다 |
공급사가 보낸 VEX 문서 중 이 스캔 SBOM의 컴포넌트에 해당하는 진술과, 그 문서가 설명하는 제품이다. 직접 남긴 판단(_vex.json)과는 따로 보관한다. 받은 진술이 내 판단을 덮어쓰지 않으며 화면도 둘을 다른 이름으로 표시한다. CycloneDX analysis.state는 네 가지 상태로 옮긴다(exploitable은 영향 있음, not_affected와 false_positive는 영향 없음, resolved와 resolved_with_pedigree는 이미 고침, in_triage는 조사 중). 그 밖의 상태는 무시한다. 문서의 제품이나 버전이 스캔한 SBOM의 루트와 다르면 거부하고 아무것도 저장하지 않는다. 가져오기에 성공하면 이 파일을 교체하고, 거부되거나 적용할 진술이 없는 가져오기는 이전 파일을 그대로 둔다. 제품 자체를 가리키는 진술은 컴포넌트 없이 한 번만 저장하며, 그 CVE의 발견 항목 중 자기 진술이 없는 것 모두에 적용한다. _vex.json처럼 같은 프로젝트와 버전을 재스캔해도 지워지지 않는다 |
{Project}_{Version}_reachability.cdx.json |
Go 소스나 Go 실행 파일 스캔에 --reachability를 주고, govulncheck가 Go 취약점 데이터베이스를 읽었을 때 생긴다 |
SBOM의 컴포넌트(같은 모듈과 버전)에 해당하는 Go 보안 권고마다 govulncheck가 내린 판정을 담은 독립 CycloneDX 1.6 VEX 문서다. 영향받는 코드에 도달하지 않으면 analysis.state는 not_affected이다. 모듈은 필요하지만 영향받는 패키지가 빌드에 없으면 justification은 code_not_present, 패키지는 있지만 영향받는 함수를 호출하지 않거나 실행 파일에 링크되지 않았으면 code_not_reachable이다. 도달하면 exploitable이다. analysis.detail에 어느 경우인지와 호출 경로나 심볼을 적는다. id는 권고에 CVE가 있으면 그 CVE이고, Go 식별자와 다른 식별자는 references에 있다. 소스 스캔에서는 metadata.properties에 판정 범위(bomlens:reachability:goos, goarch, build-tags, modules)를 남긴다. 보안 보고서가 이 문서를 읽어, 해당 발견 항목마다 _security.json에 bomlens:reachability(state, justification, detail, level, mode)를 붙이고 문서에 Reachability 요약을 둔다 |
{Project}_{Version}_vendored.cdx.json |
소스 스캔에서 --identify-vendored, opt-in SCANOSS 이미지 필요 |
소스 트리 안에서 식별한 번들 오픈소스 컴포넌트(SCANOSS) |
{Project}_{Version}_security_trivy.json |
보안보고서를 생성할 때, 다른 엔진(grype, cve-bin-tool, Yocto)이 결과를 더한 경우 | _security.json으로 병합하기 전에 따로 남긴 Trivy 자체 결과 |
bomlens-events.jsonl |
BOMLENS_EVENTS=file |
진행 이벤트, 한 줄에 JSON 객체 하나. 엔진 계약 참고 |
bomlens-result.json |
항상 | 실행 결과 매니페스트. 실행이 어떻게 끝났는지, 단계별 결과, 출력 파일별 역할을 담습니다. 엔진 계약 참고 |
{Project}_{Version}_security_epss.json |
보안보고서를 생성할 때마다 | 취약점별 EPSS 점수와 KEV 여부(오프라인 생성 시 null/false), 보안보고서 우선순위 산정에 사용 |
{Project}_{Version}_bom.json.sig |
--sign |
cosign 서명 (--spdx와 함께 쓰면 _bom.spdx.json.sig도 생성). AI 스캔에는 _bom.spdx3.json.sig도 추가되며, 초안도 서명한다. 서명은 파일의 출처를 보증할 뿐 완성 여부를 뜻하지 않는다 |
{new}_model-diff.json |
--diff <old.json> <new.json> |
이미 생성한 SBOM 두 개를 비교한 AI 모델 변동 보고서. 매칭된 모델의 판정·라이선스·해시 변화와, 한쪽 파일에만 있는 컴포넌트를 담는다. 새 쪽 입력 파일 이름을 따르며(<new>_bom.json → <new>_model-diff.json), {Project}_{Version}이 아니다 — --diff는 프로젝트나 버전을 따로 받지 않는다 |
{P}=프로젝트 이름, {V}=버전 (특수문자는 _로 정규화).
위 표의 생성 조건은 CLI 옵션 기준입니다. 웹 UI와 데스크톱 앱에서는 새 스캔 화면의 생성 옵션(고지문, 보안 보고서)이 같은 역할을 하고, 만들어진 파일은 결과 화면의 산출물 섹션에 모두 표시되어 형식별로 또는 ZIP 하나로 내려받을 수 있습니다. SPDX는 스캔 옵션이 아닙니다. 산출물 섹션의 SBOM 카드에 있는 SPDX 2.3으로 내보내기 버튼으로 필요할 때 완성된 SBOM을 변환하며, 변환된 파일은 산출물 목록과 ZIP 묶음에 함께 들어갑니다. UI에는 서명 기능이 없어 이렇게 내보낸 SPDX는 서명되지 않으므로, 서명이 필요하면 CLI에서 --spdx --sign을 쓰세요. 웹 UI와 데스크톱 앱을 참고하세요.
선언한 AI 서비스¶
AI 선언(--ai-declare, 또는 웹 UI에서 저장한 선언)에는 최상위 service 객체로 모델을 실행하는 서비스를 적을 수 있고, 스캔으로 읽을 수 없는 모델 값 몇 가지도 적을 수 있습니다. service는 문서가 데이터셋이 아니라 모델을 기술할 때만 받으며, 값이 하나도 없는 service는 선언하지 않은 것으로 봅니다. 이 값들이 무엇을 위한 것인지는 AI 모델 가이드에서 설명합니다.
| 키 | 값 |
|---|---|
name |
서비스 이름. 필수 |
packageVersion |
서비스 버전. 필수 |
downloadLocation |
서비스를 제공하는 주소(URI). 필수 |
suppliedBy |
서비스를 제공하는 조직, {"type": "Organization", "name": "..."}. 필수 |
releaseTime |
출시일, YYYY-MM-DDThh:mm:ssZ. 필수 |
informationAboutApplication |
서비스의 용도를 적은 글 |
domain[] |
서비스가 쓰이는 분야를 적은 글 |
autonomyType |
AI의 결정에 사람이 관여하는지. yes(사람이 관여하지 않는 완전 자동), no(사람이 관여함), noAssertion(모름) |
inputModality[], outputModality[] |
입력과 출력의 종류. text, image, audio, video, timeseries, structured, code, other |
dataFlows[] |
들어오고 나가는 데이터. 항목마다 {flow, classification, name, description, source[], destination[]}이다. flow는 inbound, outbound, bi-directional, unknown 중 하나다. classification은 필수(200자 이내)이며 개인정보처럼 어떤 데이터인지 적는다. name과 description은 선택이며, 설명에는 서비스가 그 데이터를 어떻게 쓰는지 적는다. source[]와 destination[]은 주소(URI)다 |
standardCompliance[] |
서비스가 따르는 표준의 이름 |
disclosureUrl |
서비스의 AI 사용을 설명하는 공개 페이지(URI) |
externalModels[] |
서비스가 API로 호출하는 AI 모델. 항목마다 {key, name, suppliedBy, packageVersion, endpoint}이다. key(영문 소문자, 숫자, ., _, -로 64자 이내, 목록 안에서 중복 불가)와 name은 필수이고, endpoint는 URI다 |
필수 키는 SPDX가 서비스에 요구하는 항목이며, 모두 적을 때까지 문서는 초안으로 남습니다. 선언의 model에는 다음 다섯 키를 더 적을 수 있습니다.
| 키 | 값 |
|---|---|
inputModality[], outputModality[] |
모델의 입력과 출력 종류. 값은 서비스와 같다 |
trainingComputeFlops |
모델 학습에 쓴 연산량(부동소수점 연산 횟수). "3.2e24"나 "1500000"처럼 문자열로 적은 양의 10진수 |
trainingComputeBasis |
그 수치를 산정한 방법을 적은 글 |
adversarialTesting |
적대적 시험을 했는지. yes, no, noAssertion |
SPDX 3.0.1 문서에서 서비스는 software_primaryPurpose가 application인 ai_AIPackage이며, 범위(scope)가 runtime인 dependsOn 관계로 모델과 이어집니다. 외부 모델은 각각 용도가 model인 software_Package입니다. 데이터 흐름, 입력과 출력 종류, 모델의 규제 값은 CycloneDX 속성 확장으로 들어갑니다. bomlens:service:dataFlow(흐름마다 하나, serviceData를 압축한 JSON 문자열), bomlens:service:input과 :output, bomlens:model:input과 :output, bomlens:regulatory:*입니다.
스캔은 같은 내용을 CycloneDX SBOM에도 기록합니다. 선언한 데이터셋 원천을 읽은 다음, 위험 판정과 G7 검사보다 먼저 도는 단계입니다.
| 위치 | 내용 |
|---|---|
services[], bom-ref service:declared/<이름> |
서비스. name, version, provider.name, endpoints[0](서비스 주소), description(용도), data[](serviceData 형식의 데이터 흐름), 유형이 documentation인 externalReferences 항목(공개 페이지), 그리고 bomlens:service:domain, :autonomyType, :input, :output, :releaseTime 속성 |
services[], bom-ref service:declared-external/<key> |
외부 모델마다 하나. name, version, provider.name, endpoints, bomlens:service:declarationKey |
dependencies[] |
서비스가 모델의 bom-ref와 각 외부 모델에 의존 |
declarations.claims[] |
표준마다 하나. 대상(target)은 서비스, 서술(predicate)은 표준 이름, 근거(reasoning)는 "publisher's declaration, not verified by BomLens" |
| 모델 컴포넌트 | bomlens:regulatory:trainingComputeFlops, :trainingComputeBasis, :adversarialTesting 속성과, modelCard.modelParameters.inputs[]와 outputs[]에 적은 입력과 출력 종류({"format": "text"}) |
이렇게 기록한 서비스에는 모두 bomlens:origin=declared-input과 bomlens:service:kind(application 또는 external-model)가 붙고, 서비스 본체에는 bomlens:service:declarationDigest도 붙습니다. 모델 컴포넌트에는 선언에서 채운 위치마다 bomlens:declared 속성이 붙습니다. 값은 속성 이름이나 modelCard 경로이며, 이 단계가 modelCard나 modelCard.modelParameters를 새로 만들었다면 그 경로도 적습니다. 스캔이 이미 입력이나 출력을 기록했다면 그 값을 그대로 두고 bomlens:declared:observedKept 속성에 그 위치를 적습니다. bomlens:model:declarationDigest는 모델 값이 어느 선언에서 왔는지 기록합니다. 선언한 형식을 담으려고 새로 만든 modelCard.modelParameters는 G7 검사에서 모델 카드로 세지 않습니다. 이 단계는 같은 SBOM에 여러 번 돌려도 됩니다. 이전 실행이 쓴 내용을 먼저 지우므로, 서비스가 없는 선언을 적용하면 예전 서비스가 지워집니다. SPDX 변환기가 거부한 선언은 아예 적용하지 않습니다.
G7 시스템 속성 요소는 선언한 서비스를 읽고, 이렇게 충족된 요소는 "있음 (발행자 선언, BomLens가 확인하지 않음)"으로 나옵니다. SPDX 2.3 내보내기와 --diff는 서비스를 다루지 않습니다. BomLens v1.13 이하는 service나 새 모델 키가 있는 선언을 "unknown key(s)" 오류로 거부합니다.
SBOM 구조¶
bomFormat "CycloneDX"
specVersion "1.6" (--spec-version 1.7이면 "1.7")
metadata
├── timestamp 생성 시각 (ISO 8601)
└── component 프로젝트 정보 (name, version, type)
components[]
├── type "library" | "framework" | "application"
├── name 컴포넌트 이름
├── version 버전
├── purl Package URL (고유 식별자)
├── supplier 컴포넌트 공급자 (패키지 메타데이터에 있을 때)
└── licenses[] 라이선스 정보 (SPDX ID)
compositions[] 의존성 그래프 완전성 (아래 참고)
언어별 PURL 형식은 지원 생태계를 참고하세요.
컴포넌트의 supplier.name은 패키지 메타데이터에 이미 적힌 값으로만 채웁니다. 생성 도구가 읽은 publisher(Maven POM의 <organization>, npm 게시자), authors(PyPI, RubyGems, Composer), 예전 형식의 author 필드 순서로 처음 있는 값을 씁니다. 값 안의 꺾쇠괄호 부분은 지우고, 괄호나 대괄호는 안에 이메일 주소나 URL만 있을 때 지웁니다. 그래서 npm 형식 Name <email> (url)의 이메일 주소와 URL이 빠지고, Example (Holdings), Inc.처럼 다른 내용이 든 괄호는 그대로 남습니다. 괄호 밖에 있는 이메일 주소와 URL(http://, https://, ftp://, www.)도 지우며, 그 앞에 닫히지 않은 괄호가 있으면 함께 지웁니다. 그래서 Alice <a@x.org>, Bob <b@y.org>는 Alice, Bob, Jane Doe jane@example.org는 Jane Doe, Bob <b@x.org>; Carol <c@y.org>는 Bob; Carol이 됩니다. 이메일 주소나 URL만 있는 값은 쓰지 않으며, 작성자가 여럿이면 쉼표로 잇습니다. 어느 필드에서 왔는지는 bomlens:supplierSource 속성(publisher, authors, author)에 남습니다. 세 필드가 모두 없는 컴포넌트에는 공급자를 넣지 않고, 이미 공급자가 있는 컴포넌트는 그대로 둡니다. 하위 컴포넌트(components[].components)에도 같은 규칙을 적용합니다. 배포판과 펌웨어 패키지(pkg:deb, pkg:rpm, pkg:apk, pkg:alpm, pkg:opkg, pkg:generic)와 operating-system 컴포넌트에는 공급자를 넣지 않습니다. 생성 도구가 이 패키지에서 읽는 게시자는 패키지 관리자이고 대개 개인 한 명이며, 배포판 이름을 추정해 대신 넣지도 않습니다. --analyze로 받은 공급사 SBOM과 --merge 결과는 작성된 그대로 둡니다.
소스 스캔은 프로젝트가 버전을 고정했는지도 metadata.component.properties에 기록합니다. bomlens:source:versionPinning 값이 pinned이면 lock 파일이 있거나 requirements.txt의 모든 줄에 정확한 버전이 있는 것이고, unpinned이면 requirements.txt, package.json, pyproject.toml, setup.py, setup.cfg 옆에 lock 파일이 없고 모든 버전이 고정되어 있지 않은 것입니다. unpinned일 때 SBOM의 버전은 스캔한 날 새로 설치하면 받게 될 버전이어서, 실제로 실행한 버전과 다를 수 있습니다. 웹 UI가 안내를 보이고, 위험 보고서는 취약점 집계 아래에 같은 내용을 적습니다. 스캔이 판단하지 못했으면 이 속성은 없습니다.
의존성 그래프 완전성¶
생성된 SBOM은 의존성 그래프가 얼마나 완전한지 나타내는 compositions[0].aggregate 항목을 담습니다.
| 값 | 의미 |
|---|---|
complete |
그래프가 완전히 해석됐다는 적극적인 근거를 찾았습니다. 생태계의 lock/resolve 단계가 성공했거나 lock 파일이 이미 커밋돼 있었고, 의존 엣지가 하나 이상 있는 경우입니다. |
incomplete |
스캔에 알려진 실패가 있었습니다. cdxgen 대신 syft 폴백이 돌았거나, 펌웨어 패키지 목록화 단계가 실패했거나, poetry.lock이 없는 Poetry 프로젝트를 일부만 변환했거나 그 의존성을 풀지 못한 경우입니다. |
unknown |
그래프가 완전하다고 확인해 주는 근거가 SBOM에 없습니다. 어느 쪽으로도 적극적인 근거가 없을 때의 기본값이며, 예를 들면 image/rootfs/firmware/binary 스캔(syft 혼자서는 패키지 사이 의존 관계를 못 봄), AI 모델·데이터셋·병합 SBOM, Maven 소스 스캔(해석이 됐는지 저하됐는지 가릴 신뢰할 수 있는 신호가 없음)이 여기 해당합니다. unknown은 결함이 아닙니다. 도구가 판단할 근거를 찾지 못했다는 뜻일 뿐, 뭔가 잘못됐다는 뜻이 아닙니다. |
분석 대상 공급사 SBOM이 자체 compositions 선언을 이미 가지고 있다면 절대 덮어쓰지 않습니다.
적합성 검사 보고서의 전이 의존성 검사는 이 값을 detail 문구에 덧붙입니다(예: "12 edge(s), declared complete"). 통과/실패 판정에는 영향을 주지 않습니다.
전처리 단계가 돌았거나 이미 커밋된 lock 파일로 충족된 경우, 성공·실패와 무관하게 bomlens:prep-step-applied 속성에 기록됩니다. bomlens:pipeline-step-failed는 실패만 기록합니다. 위 aggregate 값은 둘을 함께 봐서 정해집니다.