
SBOM용 Git diff—CycloneDX, SPDX, Syft 문서를 비교하고, 변조를 탐지하며, CI를 게이팅합니다.
# sbomlyze
**SBOM을 위한 `git diff`.** 두 개의 Software Bill of Materials를 비교하고 빌드, 버전, 릴리스 간에 무엇이 변경되었는지 확인하세요.
sbomlyze는 버전 문자열만이 아니라 컴포넌트 해시를 비교합니다. 공격자가 버전을 올리지 않고 패키지를 교체하면 sbomlyze가 이를 탐지합니다. 생성기와 취약점 스캐너는 이를 놓칩니다.
[![CI][ci-img]][ci]
[![GitHub Marketplace][marketplace-img]][marketplace]
[![GitHub Release][release-img]][release]
[![Go Report Card][go-report-img]][go-report]
[![OpenSSF Scorecard][scorecard-img]][scorecard]
[![OpenSSF Best Practices][best-practices-img]][best-practices]
[![License: Apache-2.0][license-img]][license]
[![Downloads][download-img]][download]
[](https://github.com/rezmoss/sbomlyze-go-spdx-demo/pull/2)
이 신호가 매니페스트나 일반적인 컴포넌트 diff와 어떻게 다른지 알아보려면
[Manifest diff vs. SBOM diff vs. integrity drift](https://github.com/rezmoss/sbomlyze/blob/main/docs/manifest-vs-sbom-vs-integrity-drift.md)를 참조하세요.
> 생성기는 SBOM을 만들고 스캐너는 CVE를 찾습니다. sbomlyze는 두 SBOM 사이에 무엇이 변경되었고 그것을 신뢰해야 하는지 알려줍니다.
> 생성기 뒤에 실행하세요: `syft image:tag -o cyclonedx-json | sbomlyze - --compliance`는 임시 파일 없이 생성된 SBOM을 분석하고 점수를 매깁니다. 베이스라인과 비교하여 드리프트를 분류하고 파이프라인을 게이트하세요.
## GitHub Action 빠른 시작
[SBOMlyze Diff from GitHub Marketplace][marketplace]를 추가하여 체크인된
또는 별도로 생성된 SBOM을 git 베이스라인과 비교하세요. 아래의 변경 불가능한 SHA는
게시된 `v0.5.1` Action입니다:```yaml
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: rezmoss/sbomlyze@31503690611fda8ebba4ed2bd186eda000442594 # v0.5.1
with:
sbom-path: build/sbom.cdx.json
```
Action은 기본적으로 Job Summary를 작성하며, 정책을 강제하고, 무결성 드리프트를 보고하고, SARIF를 업로드하거나, 단일 pull-request 코멘트를 유지할 수 있습니다. 입력, 출력, 권한 및 보안 지침은 [전체 Action 레퍼런스](https://github.com/rezmoss/sbomlyze/blob/main/ACTION.md)를 참조하세요. 통과하는 의존성 업데이트와 차단된 동일 버전 해시 변경, 공개 워크플로 실행 및 SARIF 증거는 [라이브 데모 저장소](https://github.com/rezmoss/sbomlyze-action-demo)를 참조하세요.
형식별 dogfood에는 공개 [Go + SPDX](https://github.com/rezmoss/sbomlyze-go-spdx-demo), [Node + CycloneDX](https://github.com/rezmoss/sbomlyze-node-cyclonedx-demo) 또는 [container](https://github.com/rezmoss/sbomlyze-container-demo) 예제를 사용하세요. 각 예제에는 다섯 가지 재현 가능한 리뷰 시나리오가 포함되어 있습니다. [10분 베타 가이드](https://github.com/rezmoss/sbomlyze/blob/main/BETA.md)는 네 가지 핵심 활성화 및 신호 품질 질문을 수집합니다.
생성된 SBOM은 커밋할 필요가 없습니다: `baseline: workflow-artifact`는 성공한 default-branch 실행에서 가장 최근의 일치하는 아티팩트를 검색합니다. [고정된 Syft 컴패니언 워크플로](https://github.com/rezmoss/sbomlyze/blob/main/examples/workflows/syft-companion.yml)는 SBOMlyze가 리뷰와 정책을 담당하는 동안 생성 및 베이스라인 게시를 보여줍니다.
## Why sbomlyze?
많은 도구가 SBOM을 생성합니다. 이를 비교하는 도구는 적고, 변경이 일상적인지 아니면 공급망 위험 신호인지 알려주는 도구는 더 적습니다. sbomlyze가 그 격차를 채웁니다.
| Capability | **sbomlyze** | cyclonedx-cli | sbomqs | syft / trivy |
|---|:---:|:---:|:---:|:---:|
| SBOM-to-SBOM **diff** | ✅ | basic | ❌ | ❌ |
| **Integrity / tamper** drift (hash changed without version) | ✅ | ❌ | ❌ | ❌ |
| Dependency-graph diff + transitive depth risk | ✅ | ❌ | ❌ | ❌ |
| **NTIA / CISA / BSI** compliance scoring | ✅ | ❌ | ✅ | ❌ |
| Format conversion (Syft / CycloneDX / SPDX) | ✅ | ✅ | ❌ | partial |
| **TUI + Web UI** explorers | ✅ | ❌ | ❌ | ❌ |
| Policy gate + SARIF / JUnit / Markdown / HTML / Patch | ✅ | partial | partial | partial |
## Features
- **SBOM diffing**: 두 SBOM을 비교하고 추가, 제거 및 변경된 컴포넌트를 한눈에 확인
- **Drift classification**: 버전 드리프트와 **무결성 드리프트**(버전 변경 없이 해시가 변경되어 변조를 시사함) 및 메타데이터 드리프트를 구분
- **Compliance scoring**: 모든 SBOM을 **NTIA**, **CISA 2025** 및 **BSI TR-03183** 최소 요소에 대해 점수화
- **Dependency graph diff**: 전이적 의존성 및 공급망 깊이 추적
- **Multi-format support**: Syft, CycloneDX, SPDX (JSON)
- **Format conversion**: CycloneDX, SPDX 및 Syft 형식 간 변환
- **Strong identity matching**: PURL → CPE → BOM-ref → namespace/name 우선순위
- **Statistics mode**: 라이선스, 의존성 및 무결성 메트릭에 대해 단일 SBOM 분석
- **Interactive TUI mode**: 키보드 탐색 및 검색으로 SBOM 탐색
- **Web UI mode**: 드래그 앤 드롭 업로드가 가능한 브라우저 기반 SBOM 탐색기
- **Policy engine**: CI 파이프라인에서 드리프트, 라이선스 및 컴플라이언스 점수 규칙 강제
- **GitHub Marketplace Action**: Job Summary, SARIF 및 선택적 코멘트 출력으로 SBOM 드리프트에 대해 pull request 게이트
- **Duplicate & collision detection**: 동일 패키지의 여러 버전 및 모호한 신원 일치 찾기
- **Multiple output formats**: Text, JSON, SARIF, JUnit XML, Markdown, HTML, JSON Patch
- **Tolerant parsing**: 구조화된 경고와 함께 오류 발생 시 계속 진행
## Installation
### Homebrew (macOS/Linux)```bash
brew install rezmoss/sbomlyze/sbomlyze
```
### 설치 스크립트
설치 스크립트는 사용자의 OS/아키텍처에 맞는 올바른 바이너리를 다운로드합니다:```bash
# Install to ./bin
curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sh
# Install to /usr/local/bin (requires sudo)
curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sudo sh -s -- -b /usr/local/bin
# Install specific version
curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sh -s -- -v 0.4.0
```
**설치 프로그램 옵션:**
| 옵션 | 설명 |
|--------|-------------|
| `-b <dir>` | 설치 디렉터리 (기본값: `./bin`) |
| `-d` | 디버그 출력 활성화 |
| `-v <ver>` | 특정 버전 설치 (기본값: 최신) |
설치 프로그램은 항상 릴리스 체크섬을 검증합니다. 호환되는 GitHub CLI가
설치되어 있으면 릴리스의 빌드 출처도 검증하며, 해당 검증이
성공하지 않으면 실패 시 종료됩니다.
### Go 설치```bash
go install github.com/rezmoss/sbomlyze/cmd/sbomlyze@latest
```
### 바이너리 릴리스에서
[GitHub Releases](https://github.com/rezmoss/sbomlyze/releases)에서 최신 바이너리를 다운로드하세요.
v0.3.7부터 릴리스 아카이브는 GitHub artifact
attestations와 함께 게시됩니다. 다음으로 다운로드를 독립적으로 검증하세요:```bash
gh attestation verify ./sbomlyze_0.4.0_Linux_x86_64.tar.gz \
--repo rezmoss/sbomlyze \
--signer-workflow rezmoss/sbomlyze/.github/workflows/release.yml
```
서명되지 않은 apt, rpm, apk 저장소 안내는 저장소가 패키지 관리자 네이티브 서명 검증을 지원할 때까지 제거되었습니다.
**macOS 사용자:** 다운로드 후 quarantine 플래그를 제거하세요:```bash
xattr -d com.apple.quarantine ./sbomlyze
chmod +x ./sbomlyze
```
### 소스에서 빌드```bash
git clone https://github.com/rezmoss/sbomlyze.git
cd sbomlyze
go build -o sbomlyze ./cmd/sbomlyze
```
## 빠른 시작```bash
# Compare two SBOMs (the headline use case)
sbomlyze before.json after.json
# Analyze a single SBOM
sbomlyze image.json
# Read an SBOM from standard input
syft image:tag -o cyclonedx-json | sbomlyze -
# Use standard input on either side of a diff
syft image:tag -o cyclonedx-json | sbomlyze baseline.json -
# Score an SBOM against NTIA / CISA / BSI minimum elements
sbomlyze image.json --compliance
# Interactive TUI explorer
sbomlyze image.json -i
# Web UI (opens browser)
sbomlyze -web
# Convert between SBOM formats
sbomlyze convert syft.json --to spdx
sbomlyze convert cdx.json --to syft -o output.json
# JSON output for CI integration
sbomlyze before.json after.json --json
# SARIF output for GitHub Code Scanning
sbomlyze before.json after.json --format sarif
# Markdown report for PR comments
sbomlyze before.json after.json --format markdown
# Apply policy checks
sbomlyze before.json after.json --policy policy.json
```
## 사용법```
sbomlyze <sbom1|-> [sbom2|-] [options]
sbomlyze convert <sbom|-> --to <format> [-o output]
Modes:
Single file: sbomlyze <sbom> [--json] Show statistics
Interactive: sbomlyze <sbom> -i Interactive explorer
Convert: sbomlyze convert <sbom> --to <fmt> Convert SBOM format
Web server: sbomlyze -web [--port 8080] Web UI explorer
Two files: sbomlyze <sbom1> <sbom2> [...] Show diff
Use `-` in place of one SBOM path to read it from standard input.
Options:
-i, --interactive Interactive TUI explorer
-web, --web Start web UI server
--port <port> Web server port (default 8080)
--json Output in JSON format (shortcut for --format json)
--format <format> Output format: text, json, sarif, junit, markdown, html, patch
--compliance Show NTIA/CISA/BSI compliance scoring
--policy <file> Policy file for CI checks
--strict Fail on parse warnings
--tolerant Continue on parse warnings (default)
--no-pager Disable automatic paging of output
--to <format> Target format for convert: cyclonedx (cdx), spdx, syft
-o, --output <file> Output file for convert (default: stdout)
--version, -v Show version information
--help, -h Show this help message
```
## 명령어
### 통계 모드 (단일 파일)
SBOM을 분석하여 컴포넌트, 라이선스, 종속성에 대한 인사이트를 얻습니다.```bash
sbomlyze image.json
```
스캔 컨텍스트, 자동 감지된 주요 발견 사항, 통계를 포함한 출력:```
Scan Context:
Tool: syft 1.40.1
Schema: 16.0.18
Scan Scope: all-layers
Source Type: image
Source: alpine:latest
Key Findings:
💻 OS/Distro: Alpine Linux v3.21
📦 Dominated by apk: 71 of 71 packages (100.0%)
📂 8,542 files tracked on filesystem
🔗 Relationships: 71 containment + 64 dependency
📜 License profile: 72% permissive, 20% copyleft
⚠️ Low hash coverage: 0.0% (71 of 71 missing)
🔍 Top catalogers: apkdb-cataloger (71)
📦 SBOM Statistics
==================
Total Components: 71
By Package Type:
apk 71
Licenses:
With license: 71
Without license: 0
Top Licenses:
MIT 17
BSD-3-Clause 8
GPL-2.0-only 8
Integrity:
With hashes: 0
Without hashes: 71
Dependencies:
Components with deps: 65
Total dep relations: 176
```
#### 주요 발견 사항
sbomlyze는 SBOM에 대한 인사이트를 자동으로 생성합니다. 단일 파일 분석의 경우 다음이 포함됩니다:
| 발견 사항 | 설명 |
|---------|-------------|
| **OS/배포판 감지** | SBOM 메타데이터에서 운영 체제 또는 배포판을 식별합니다 |
| **주요 에코시스템** | 하나의 패키지 유형이 지배적인 경우(전체 패키지의 >60%) 보고합니다 |
| **파일시스템 풋프린트** | 파일시스템에서 추적되는 파일 수 |
| **관계 밀도** | 포함 및 의존 관계의 수를 계산합니다 |
| **위치 핫스팟** | 컴포넌트가 발견되는 상위 디렉터리 |
| **라이선스 위험 프로필** | 허용/카피레프트/알 수 없는 라이선스 비율 분석 |
| **데이터 품질 경고** | 라이선스(<50%), 해시(<50%) 또는 PURL(<80%) 커버리지가 낮을 때 경고합니다 |
| **중복 경고** | 중복 컴포넌트 그룹을 표시합니다 |
| **카탈로거 분석** | 컴포넌트를 감지한 상위 스캐너/카탈로거(Syft SBOM) |
#### 커버리지 지표
통계 모드는 데이터 품질 평가를 위한 커버리지 비율을 계산합니다:
| 지표 | 설명 |
|--------|-------------|
| **PURL 커버리지** | Package URL이 있는 컴포넌트의 비율 |
| **CPE 커버리지** | CPE가 있는 컴포넌트의 비율(취약점 스캔 준비 상태) |
| **라이선스 커버리지** | 최소 하나의 라이선스가 있는 컴포넌트의 비율 |
| **해시 커버리지** | 무결성 해시가 있는 컴포넌트의 비율 |
#### 라이선스 분류
라이선스는 자동으로 다음과 같이 분류됩니다:
| 카테고리 | 예시 |
|----------|----------|
| **카피레프트** | GPL, LGPL, AGPL, MPL, EPL, CDDL |
| **허용적** | MIT, BSD, Apache, ISC, Zlib, Unlicense |
| **퍼블릭 도메인** | 퍼블릭 도메인 헌정 |
| **알 수 없음** | 인식되지 않거나 누락된 라이선스 |
### 변환 모드
CycloneDX, SPDX 및 Syft JSON 형식 간에 SBOM을 변환합니다. 입력 형식은 자동으로 감지됩니다.```bash
# CycloneDX to SPDX
sbomlyze convert image.cdx.json --to spdx
# Syft to CycloneDX (cdx is an alias for cyclonedx)
sbomlyze convert syft-output.json --to cdx
# SPDX to Syft, writing to a file
sbomlyze convert spdx-output.json --to syft -o converted.json
```
#### 지원되는 대상 형식
| 형식 | `--to` 값 | 출력 |
|--------|-------------|--------|
| CycloneDX 1.5 | `cyclonedx` 또는 `cdx` | 메타데이터, 종속성 및 속성을 포함한 CycloneDX JSON |
| SPDX 2.3 | `spdx` | 패키지, 관계 및 외부 참조를 포함한 SPDX JSON |
| Syft | `syft` | 아티팩트, 관계, 소스 및 배포판 정보를 포함한 Syft JSON |
#### 보존되는 항목
변환은 컴포넌트 이름, 버전, PURL, CPE, 라이선스, 해시, 공급업체 정보 및 종속성 관계를 보존합니다. 형식별 필드(예: Syft 언어, foundBy, locations)는 CDX로 변환할 때 CycloneDX 속성을 통해 전달됩니다.
### Diff 모드 (두 파일)
두 SBOM을 비교하여 버전 간에 변경된 사항을 확인합니다.```bash
sbomlyze v1.0.json v2.0.json
```
#### Diff 개요
diff는 나란히 배치된 메타데이터 비교(파일 이름, 크기, OS 정보, 도구 정보, 컴포넌트 수)로 시작하며, 사용 가능한 경우 스캔 컨텍스트 세부 정보가 뒤따릅니다.
#### 출력```
📊 Drift Summary:
📦 Version drift: 58 components
⚠️ Integrity drift: 1 component (hash changed without version change!)
📝 Metadata drift: 2 components
🔑 Key Findings:
📈 Attack surface: +5 packages (7.0%), +120 files (3.2%)
🚨 2 version downgrades detected: openssl 3.1.4→3.0.2, curl 8.5.0→8.4.0
🔄 56 version upgrades (2 major, 12 minor, 42 patch) among 65 shared packages
⚠️ Integrity drift (1 total): 1 npm (review recommended)
❌ python ecosystem entirely removed (15 → 0 packages)
➕ New ecosystem: golang (8 packages)
✅ Core system packages stable: apk (71) unchanged
+ Added (2):
+ libgcrypt 1.10.3-r0
+ libgpg-error 1.49-r0
- Removed (3):
- libapk 3.0.3-r1
- libgcc 15.2.0-r2
- nghttp3 1.13.1-r0
~ Changed (58):
~ nginx
version: 1.29.4-r1 -> 1.27.3-r1
~ suspicious-pkg ⚠️ [INTEGRITY]
hash[SHA256]: abc123 -> def456
>> Added dependencies:
pkg:apk/alpine/libxslt: +[so:libgcrypt.so.20]
<< Removed dependencies:
pkg:apk/alpine/libcurl: -[so:libnghttp3.so.9]
🔗 New transitive dependencies (3):
+ pkg:npm/lodash (depth 2)
via: [pkg:npm/my-app pkg:npm/express pkg:npm/lodash]
+ pkg:npm/underscore (depth 3)
via: [pkg:npm/my-app pkg:npm/express pkg:npm/lodash pkg:npm/underscore]
📊 New deps by depth:
Depth 2: 1
Depth 3+ (risky): 2 ⚠️
```
#### Diff 주요 발견 사항
diff 모드에서 sbomlyze는 두 SBOM을 비교하여 더 풍부한 인사이트를 자동 생성합니다:
| 발견 사항 | 설명 |
|---------|-------------|
| **스캔 컨텍스트 불일치** | SBOM 간에 스키마 버전이나 스캔 범위가 변경된 경우 경고 |
| **공격 표면 델타** | 패키지, 파일, 관계 수 변화를 백분율과 함께 표시 |
| **사라진/새로운 생태계** | 완전히 나타나거나 사라진 패키지 유형 |
| **OS/배포판 마이그레이션** | 스캔 간 운영 체제 변경 감지 |
| **버전 변경 분석** | 업그레이드와 다운그레이드 수를 집계하고, 변경을 major/minor/patch로 분류 |
| **버전 다운그레이드** | 다운그레이드를 보안 신호로 표시하고 컴포넌트 세부 정보 제공 |
| **무결성 드리프트 컨텍스트** | 패키지 유형별로 무결성 드리프트를 분류하고 위험 가이드 제공 |
| **지배적 경로 패턴** | 유형 및 파일시스템 경로별로 집중된 변경 사항 |
| **제거/추가 핫스팟** | 변경의 영향을 받은 상위 디렉터리 |
| **안정적 유형** | 수가 동일한 패키지 유형 (변경되지 않은 핵심) |
| **라이선스 카테고리 변화** | copyleft/permissive 균형의 변화 |
| **카탈로거 격차** | Before에서는 패키지를 찾았지만 After에서는 찾지 못한 스캐너 |
#### 유형별 패키지 샘플
추가 및 제거된 컴포넌트는 패키지 유형별로 그룹화되어 샘플 목록과 함께 제공되므로, 각 생태계에서 무엇이 변경되었는지 쉽게 확인할 수 있습니다.
## 컴플라이언스 점수 산정
감사자와 조달 팀이 계속 묻는 질문, 즉 **"이 SBOM이 충분히 완전한가?"** 에 답하기 위해 세 가지 주요 최소 요소 프레임워크에 대해 모든 SBOM의 점수를 산정합니다.```bash
# Score a single SBOM
sbomlyze image.json --compliance
# Score alongside a diff
sbomlyze before.json after.json --compliance
# As JSON for CI
sbomlyze image.json --compliance --json
```
### 평가된 프레임워크
| 프레임워크 | 검사 항목 | 주요 요구사항 |
|-----------|--------|----------------------|
| **NTIA 최소 요소** (2021) | 7 | 이름, 버전, 공급자, 고유 ID(PURL/CPE), 의존성 관계, SBOM 작성자, 타임스탬프 |
| **CISA 2025 최소 요소** (2025년 8월 초안) | 10 | NTIA에 더해 소프트웨어 생산자, 라이선스 정보, **컴포넌트 해시**, 도구 이름 추가 |
| **BSI TR-03183-2** (v2.1.0, 2025) | 9 | 컴포넌트 생성자 연락처, **SHA-512 해시**, SPDX 형식 라이선스, SBOM 생성자 연락처 요구 |
### 점수 표시
각 프레임워크는 백분율(통과한 검사 / 전체 검사)과 종합 점수(프레임워크 전체 평균)를 보고하며, 상태 표시기는 다음과 같습니다:
| 표시기 | 점수 |
|-----------|-------|
| 🟢 | ≥ 90% |
| 🟡 | 70–89% |
| 🟠 | 50–69% |
| 🔴 | < 50% |
JSON 출력(`--compliance --json`)에는 검사별 통과/실패 세부 정보가 포함된 전체 보고서가 포함되며, HTML 형식은 컴플라이언스 보고서를 보고서 페이지에 포함합니다.
### CI에서 컴플라이언스 게이팅
[정책 엔진](#policy-engine)을 통해 컴플라이언스 임계값을 적용합니다. 임계값을 설정하면 `--compliance` 플래그 없이도 컴플라이언스 평가가 트리거됩니다:```json
{
"min_ntia_score": 85,
"min_cisa_score": 70,
"min_bsi_score": 80,
"min_overall_compliance": 75
}
```
## 2.3.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.```bash
sbomlyze image.json --policy compliance-policy.json
```
## 의존성 그래프 차이
sbomlyze는 단순한 컴포넌트 목록 차이를 넘어 전체 의존성 그래프를 분석하여, 전이적 의존성을 통해 유입되는 공급망 위험을 탐지합니다.
### 기능
| 기능 | 설명 |
|---------|-------------|
| **엣지 차이** | 추가/제거된 직접 의존성 (A가 B에 의존) |
| **전이적 도달 가능성** | 그래프를 통해 나타나는 새로운 간접 의존성 |
| **전이적 손실 추적** | 제거된 전이적 의존성 |
| **경로 추적** | 각각의 새로운 전이적 의존성이 어떻게 도달되는지 정확히 표시 |
| **깊이 추적** | 각각의 새로운 의존성이 코드로부터 몇 홉 떨어져 있는지 |
| **위험 요약** | 깊이 3+ 의존성을 더 높은 위험으로 표시 |
### 깊이가 중요한 이유
그래프 더 깊은 곳에서 유입되는 의존성은:
- 감사 및 검토가 더 어려움
- 명시적 승인 없이 끌어오는 경우가 많음
- 공급망 공격의 흔한 경로 (예: event-stream 사건)
깊이 요약은 검토 우선순위를 정하는 데 도움이 됩니다:
| 깊이 | 위험 수준 | 설명 |
|-------|------------|-------------|
| **1** | 낮음 | 직접 의존성 (직접 선택한 것) |
| **2** | 중간 | 의존성의 의존성 |
| **3+** | 높음 ⚠️ | 깊은 전이적 의존성 - 주의 깊게 검토 |
### 예시: 깊은 전이적 의존성 탐지```bash
# Before: app -> express (simple, 1 dep)
# After: app -> express -> lodash -> underscore -> deep-lib (chain of 4)
sbomlyze before.json after.json
```
I'm ready to translate the Kitploit tool content from English to Korean. Please provide the chunk 37 content you'd like me to translate.```
🔗 New transitive dependencies (3):
+ lodash (depth 2)
via: [app express lodash]
+ underscore (depth 3)
via: [app express lodash underscore]
+ deep-lib (depth 4)
via: [app express lodash underscore deep-lib]
📊 New deps by depth:
Depth 2: 1
Depth 3+ (risky): 2 ⚠️
```
### 종속성 그래프를 위한 JSON 출력```json
{
"dependencies": {
"added_deps": {
"pkg:npm/express": ["pkg:npm/lodash", "pkg:npm/body-parser"]
},
"removed_deps": {},
"transitive_new": [
{
"target": "pkg:npm/underscore",
"via": ["pkg:npm/my-app", "pkg:npm/express", "pkg:npm/lodash", "pkg:npm/underscore"],
"depth": 3
}
],
"transitive_lost": [],
"depth_summary": {
"depth_1": 0,
"depth_2": 2,
"depth_3_plus": 2
}
}
}
```
## 드리프트 감지
sbomlyze는 컴포넌트 변경을 세 가지 드리프트 유형으로 분류하여, 정상적인 업데이트와 잠재적으로 의심스러운 변경을 구분할 수 있도록 도와줍니다.
### 드리프트 유형
| 유형 | 지표 | 설명 | 심각도 |
|------|-----------|-------------|----------|
| **버전** | 📦 | 버전 번호 변경됨 | 정상 |
| **무결성** | ⚠️ | 버전 변경 없이 해시 변경됨 | 높음 - 조사 필요! |
| **메타데이터** | 📝 | 메타데이터(라이선스 등)만 변경됨 | 낮음 |
### 무결성 드리프트 (보안 신호)
무결성 드리프트는 컴포넌트의 해시가 변경되었지만 버전은 동일하게 유지될 때 발생합니다. 이는 다음을 나타낼 수 있습니다:
- **공급망 공격**: 패키지가 악성 버전으로 교체됨
- **버전 범프 없는 재빌드**: 합법적이지만 좋지 않은 관행
- **다른 빌드 환경**: 재현성 문제```bash
# Example output with integrity drift
~ suspicious-pkg ⚠️ [INTEGRITY]
hash[SHA256]: abc123 -> def456
```
**권장 사항**: 무결성 드리프트는 항상 조사해야 합니다. 양성일 수도 있지만, 공급망 보안을 위한 핵심 신호입니다.
### 드리프트에 대한 JSON 출력
드리프트 요약은 `diff` 객체 내부에 있습니다:```json
{
"diff": {
"changed": [
{
"id": "pkg:npm/suspicious-pkg",
"name": "suspicious-pkg",
"changes": ["hash[SHA-256]: abc123 -> def456"],
"drift": {
"type": "integrity",
"hash_changes": {
"changed": {
```
---
[Read more](https://github.com/rezmoss/sbomlyze)