Skip to content

feat(sbom): conformance scoring wired into SBOM ingest + read API (model 3)#410

Merged
haksungjang merged 1 commit into
mainfrom
feat/model3-conformance-wiring
Jun 14, 2026
Merged

feat(sbom): conformance scoring wired into SBOM ingest + read API (model 3)#410
haksungjang merged 1 commit into
mainfrom
feat/model3-conformance-wiring

Conversation

@haksungjang

Copy link
Copy Markdown
Contributor

모델 3 (받은 SBOM) — conformance 채점·저장·노출

#409에서 머지된 conformance 채점기(services/sbom_conformance.py)를 #406이 만든 기존 CycloneDX 인제스트 파이프라인에 배선하고, 결과를 저장·노출한다. (동시 세션이 CycloneDX 업로드 배관을 이미 끝냈으므로, 이 PR은 빠져 있던 "품질 검증" 조각을 채운다.)

포함

  • 모델 + 마이그 0033sbom_conformance 테이블. 인제스트 스캔당 1행(scan_id UNIQUE FK CASCADE + denormalized project_id): result(pass·warn·fail), n_fail/n_warn, component_count, PURL·라이선스·해시 커버리지, 체크별 JSONB 배열. forward-only.
  • tasks/ingest_sbom.pyconformance 스테이지(진행률 20)가 원본 업로드 바이트를 채점해 컴포넌트 적재 전에 결과를 저장. 등급은 자문(advisory) — fail이어도 기록·노출만 하고 매칭을 중단하지 않음. persist는 delete-then-insert라 Celery acks_late 재진입 시 행을 교체(_reset_scan_for_rerun는 이 테이블을 건드리지 않음).
  • GET /v1/projects/{project_id}/scans/{scan_id}/conformance + SbomConformanceRead 스키마. 외부인 404 존재은닉, (scan_id, project_id) 술어로 교차 프로젝트 읽기 차단. OpenAPI 스냅샷 갱신.
  • 테스트 — 파이프라인: 결과 행(등급/커버리지/체크) 단언 + 강제 재진입이 행을 교체(중복 없음, 라이프사이클 규칙 5). API: 정상 읽기 + 교차팀 404(권한이 상태보다 먼저, 규칙 1) + 검증부재 404 + 타프로젝트 404.
  • 문서(EN/KO) — SBOM 업로드 가이드에 "conformance 결과" 절(엔드포인트·등급 의미·임계값·비차단 안내). KO 번역투 린트 S1·S2 0건.

검증

  • ruff·mypy 클린. 순수 서비스 단위 49건 로컬 통과. 마이그레이션 오프라인 SQL 생성 정상.
  • 통합/API 테스트는 CI에서 실행(로컬은 DB+fastasi 버전 제약).

남은 모델 3

  • SPDX 입력 활성화(현재 인제스트는 CycloneDX 전용 — 변환기는 #409에 있으니 배선만): 별도 PR + security-reviewer.
  • 프론트 "받은 SBOM" conformance 패널 + 체크 카탈로그 FE 미러 정합 테스트.

…model 3)

Wires the conformance scorer (sbom_conformance, merged in #409) into the
existing CycloneDX ingest pipeline (#406) and exposes the verdict:

- models/sbom_conformance.py + alembic 0033: one sbom_conformance row per
  ingested scan (scan_id UNIQUE FK CASCADE, denormalised project_id), holding
  result (pass|warn|fail), n_fail/n_warn, component_count, PURL/license/hash
  coverage, and the per-check JSONB array. Forward-only.

- tasks/ingest_sbom.py: a 'conformance' stage (progress 20) scores the ORIGINAL
  uploaded bytes and persists the verdict before component persistence. Verdict
  is advisory — a 'fail' is recorded + surfaced but does NOT abort matching.
  Persist is delete-then-insert so a Celery acks_late re-entry replaces the row
  (uq_sbom_conformance_scan_id) — _reset_scan_for_rerun does not touch it.

- GET /v1/projects/{project_id}/scans/{scan_id}/conformance (api/v1/sbom.py) +
  SbomConformanceRead schema. Existence-hide 404 for outsiders; the
  (scan_id, project_id) predicate rejects cross-project reads. OpenAPI snapshot
  updated.

- Tests: pipeline asserts the verdict row (result/coverage/checks) + a forced
  re-entry REPLACES it (no dupe). API tests cover the happy read, cross-team
  404 (permission-before-state), missing-verdict 404, wrong-project 404.

- docs (EN/KO): a 'conformance verdict' section on the SBOM-upload guide —
  endpoint, pass/warn/fail meaning, thresholds, advisory (non-blocking) note.

from alembic import op

revision: str = "0033"
from alembic import op

revision: str = "0033"
down_revision: str | None = "0032"

revision: str = "0033"
down_revision: str | None = "0032"
branch_labels: str | Sequence[str] | None = None
revision: str = "0033"
down_revision: str | None = "0032"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
@haksungjang haksungjang merged commit a658354 into main Jun 14, 2026
23 of 24 checks passed
@haksungjang haksungjang deleted the feat/model3-conformance-wiring branch June 14, 2026 02:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant