Files
llm-wiki/raw/branch-notes/feature-dependency-vulnerability-management-contract.md

494 lines
62 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: branch / feature-dependency-vulnerability-management-contract
source_type: branch-note
status: raw
confidence: medium
branch: feature-dependency-vulnerability-management-contract
parent_branch:
related_projects: [ca-skeleton]
governing_docs: [raw/project-notes/ca-skeleton-operational-contract]
tags: [branch, ca-skeleton, security, supply-chain, ci]
created: 2026-06-15
target_merge:
status_label: in-progress
id: BR-CA-SKELETON-OPERATIONAL-CONTRACT-051
kind: project-work-item
project: ca-skeleton-operational-contract
work_item: WI-CA-SKELETON-OPERATIONAL-CONTRACT-051
inherits: [DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1]
refines: []
overrides: []
depends_on: [WI-CA-SKELETON-OPERATIONAL-CONTRACT-028, WI-CA-SKELETON-OPERATIONAL-CONTRACT-030, WI-CA-SKELETON-OPERATIONAL-CONTRACT-029]
contract_packet: 1
contract_packet_sha256: bb574e1b56cc247fc24b861ef1249c28991938b0dab6bab63999d5cf9ffb756b
---
# branch: feature-dependency-vulnerability-management-contract
> Layer: `raw/branch-notes/` — 단일 브랜치의 **TODO·결정·진행 기록**. 머지/종료 후 verified 결과는 `/ingest`로 `wiki/projects/`에 추출. 원본은 raw에 영구 보관.
> `status_label`: `in-progress` | `review` | `merged` | `abandoned`
> **계층 표기**: "root branch" 라는 별도 개념은 없음. project 의 직접 자식 branch 는 `parent_branch:` 를 **비워두고** `related_projects` 만 채움. 다른 branch 의 자식이면 `parent_branch: <부모 branch 이름>` 명시 + `## Parent` 섹션의 부모 wikilink 필수.
<!-- section-id: branch-parent -->
## 부모 (필수)
> 이 branch 가 어느 작업 묶음에 속하는지. 모든 branch 는 예외 없이 upward link 보유.
- **Project 의 직접 자식 branch** (`parent_branch:` 비어있음): [[raw/project-notes/ca-skeleton-operational-contract]]
- 본 branch 는 project-note 의 §18 Control Plane Contract 중 **Build / Release / Supply Chain** (의존성 취약점 차단) + **CI Quality Gates** (vulnerability scan gate) 영역을 정제한다.
형제 branch (같은 부모의 다른 자식 — 본 branch 와 계약 경계를 공유):
- [[raw/branch-notes/feature-build-release-supply-chain-contract]] — SBOM·서명(Cosign/SLSA)·dependency **locking**·artifact versioning 의 owner. 본 branch 는 그 D2(high/critical=release-blocking)·D3(Renovate/Dependabot) 의 `UNSUPPORTED_DECISION` 스텁을 **승계해 정책 owner** 가 된다(아래 §Audit & Findings).
- [[raw/branch-notes/feature-ci-quality-gates-contract]] — CI gate **wiring**(release-blocking vs warning-only) 의 owner. 본 branch 의 severity 정책을 *consume*. 그 D5(Trivy scanner+suppression) `UNSUPPORTED_DECISION` 스텁도 본 branch 가 정책 owner 로 정합.
- [[raw/branch-notes/feature-container-runtime-contract]] — container **image** scan wiring + base image(Temurin JRE slim) owner. 본 branch 의 동일 severity 정책을 *consume*.
<!-- GENERATED: branch-contract:start -->
<!-- section-id: branch-contract-packet -->
## 브랜치 계약 패킷
- **생성 시 프로젝트 개정**: `1`
- **패킷 스키마**: `contract_packet: 1`
- **완료 조건**: scanner·severity·suppression·update·license 정책과 CI failure gate가 명시된다
<!-- section-id: inherited-project-decisions -->
### 상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
| `DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1` | build tool은 Gradle Groovy DSL이다 | Work Item 완료 조건에 적용 | [[raw/project-notes/ca-skeleton-operational-contract]] |
<!-- section-id: branch-local-decisions -->
### 브랜치 지역 결정
> 기존 branch-local 결정은 아래 `## Decision Evidence Map / 결정-근거 매핑`의 D-row가 소유하며 이 packet에서 복제하지 않는다.
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
<!-- section-id: declared-overrides -->
### 선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|---|---|---|---|
<!-- GENERATED: branch-contract:end -->
<!-- section-id: branch-goal -->
## 목표
ca-skeleton 의 §18 Build/Release/Supply Chain 과 CI Quality Gates 에는 "high/critical vulnerability 는 release-blocking" (supply-chain D2) 과 "vulnerability scanner = Trivy + suppression" (ci-gates D5), "dependency upgrade = Renovate/Dependabot" (supply-chain D3) 라는 **정책 의도만 있고 외부 근거 없는 `UNSUPPORTED_DECISION` 스텁**이 세 sibling branch 에 흩어져 있다. 어느 branch 도 *어떤 스캐너 / 어떤 심각도 표준 / 어떤 임계값 / 어떻게 suppress / 얼마나 빨리 고칠지* 를 근거와 함께 정하지 않았다 — 즉 **의존성 취약점 관리 정책의 single owner 가 없다**.
본 branch 는 그 빈 자리를 메우는 **dependency vulnerability *정책* 의 single owner** 다 (§25 SSOT Owner Map 에 해당 owner 부재 확인 → Cross-Branch Conflict Procedure 통과). 정의 대상: SCA 스캐너 선택, CVSS 심각도 표준·차단 임계값, KEV override, 스캐너 소스 우선순위(tie-break), suppression governance(만료·사유·무단변경 차단), 의존성 보안 업데이트 자동화(Renovate/Dependabot), PR-time 보완 게이트(dependency-review-action). gate *wiring* 은 ci-gates 가, image scan *wiring* 은 container-runtime 이, SBOM/서명/locking 은 supply-chain 이 소유하고 — 셋 다 본 branch 의 severity 정책을 *consume* 한다.
- 이슈: (미생성 — Phase C2 실 구현 단계에 연결)
- PR: (미생성)
<!-- section-id: branch-scope -->
## 범위
### 포함 범위
- **SCA 스캐너 선택** — 의존성(라이브러리) CVE 스캔 도구. ci-gates 의 잠정 "Trivy" 를 공식 근거로 승격/검증.
- **심각도 분류 표준 + 차단 임계값** — CVSS 버전, 점수→등급 매핑, 어느 등급부터 release-blocking. supply-chain D2 의 "high/critical=blocking" 에 외부 표준 부여.
- **KEV override** — 실제 악용(exploited in the wild) CVE 는 CVSS 점수 무관 차단.
- **스캐너 심각도 소스 우선순위(tie-break)** — NVD vs GHSA/벤더 점수 충돌 시 규칙.
- **Suppression governance** — `.trivyignore` 포맷 + 만료일 강제 + 사유 기록 + PR 승인 + 무단 변경 차단 정적 게이트(2026-05-25 audit finding 해소).
- **의존성 보안 업데이트 자동화** — Renovate primary / Dependabot 조건부 + patch-level 보안 PR auto-merge 정책. supply-chain D3 정합.
- **PR-time 보완 게이트** — GitHub dependency-review-action 으로 신규 도입 취약 의존성 차단(전체 스냅샷 스캔과 역할 분리).
- **스캔 단계/스코프** — PR 게이트 + 의존성 불변이라도 CVE DB 갱신을 잡는 scheduled 재스캔 + pre-release image scan.
- **의존성 라이선스 준수 스캔(license/NOTICE)** — Trivy 가 이미 `*gradle.lockfile` 의 license 도 스캔(License ✓)하므로 통합. 금지(strong-copyleft) 라이선스 release-blocking + allow-list 정책 + PR-time allow/deny(dependency-review-action). governing §35-E L2052 가 *license scan* 을 본 branch 영역으로 명시.
### 제외 범위
> 의도적으로 제외한 것. 면접 등에서 "이건 범위에 없었습니다"라고 답할 근거.
- **CI gate wiring(release-blocking vs warning-only 판정·`needs:`/`if:` 의존성 구성)** — `feature-ci-quality-gates-contract` owner. 본 branch 는 정책을 제공만.
- **container image scan wiring + base image 선택** — `feature-container-runtime-contract` owner (본 branch severity 정책 consume).
- **SBOM 생성·artifact 서명(Cosign/SLSA)·dependency *version locking*·artifact versioning·rollback** — `feature-build-release-supply-chain-contract` owner.
- **secret scan(gitleaks)** — `feature-secrets-config-source-contract` owner.
- **특정 CI provider(GitHub Actions) workflow YAML 의 실제 구현 세부** — 본 branch 는 계약/정책, 구현은 Phase C2.
## 근거 (필수, 최소 1개+)
> 이 branch의 구현·설계 결정의 **근거가 되는 외부 자료**. 공식 문서·대기업 기술 블로그·강의 등 raw 자료를 인용. 같은 자료가 여러 결정의 근거면 결정 표시와 함께 여러 번 등장 가능.
| Source | 정당화하는 결정 |
|---|---|
| [[raw/official-docs/trivy-action-github-actions]] | D1/게이트 — exit-code+severity 로 release-blocking CI 게이트 구성, trivyignores 파라미터로 suppression 파일 지정 |
| [[raw/official-docs/github-dependency-review-action]] | PR-time 보완 게이트 — 신규 도입 취약 의존성 차단(C1·C2). 단독 릴리즈 게이트 부적합(PR diff 전용, C4). severity 커스터마이즈 가능(C3). |
| [[raw/official-docs/trivy-filtering-suppression-policy]] | suppression governance — `.trivyignore` `exp:YYYY-MM-DD` 만료일(C3), `.trivyignore.yaml` `expired_at` 필드(C4) 로 영구 suppress 방지; `statement` 필드로 사유 기록(C5) |
| [[raw/official-docs/vuln-severity-cisa-kev-catalog-official]] | KEV 목록에 등재된 CVE = CVSS 점수와 무관하게 릴리즈 차단(exploitation-in-the-wild override). `dueDate` 필드 존재는 CISA 자체가 우선 시한을 부여한다는 증거 (CISA-KEV-C3). |
| [[raw/official-docs/vuln-severity-cvss-v31-spec-first-official]] | 릴리즈 차단 심각도 기준 = CVSS v3.1 base score, High(≥7.0)/Critical(≥9.0) 차단. FIRST.org 명세가 정성 등급 구간(Table 14, C1)과 Base Score 정의(C3)의 권위 표준. |
| [[raw/official-docs/dependabot-security-updates-gradle-official]] | Dependabot 조건부 허용 근거 — security updates 정의(C1), security vs version updates 구분(C2), grouped security updates 생태계 단위 묶음(C3·C4), manifest/lock 한정 트리거(C5) |
| [[raw/official-docs/trivy-java-language-coverage]] | D1/SCA 채택 — `*gradle.lockfile` SBOM·Vulnerability·License 공식 지원(C1), 오프라인 스캔 가능(C2), Java 취약점 소스 = GitHub Advisory Database Maven(C5) |
| [[raw/official-docs/renovate-vulnerability-alerts-gradle-official]] | Renovate primary 채택 근거 — `security:only-security-updates` preset이 `osvVulnerabilityAlerts: true` + `vulnerabilityAlerts.enabled: true` + 전체 패키지 기본 비활성화 구성임을 공식 문서로 확인 (C1·C2·C3) |
> **Deferred 아카이브 (후속 `/branch-spec` 재실행 또는 수동 dispatch)** — 아래 자료는 *대안 비교*·*보강 신호* 근거로 `wiki-decision-researcher` 가 URL·핵심 사실을 이미 확보했으나, 본 run 의 archive 예산을 핵심 7건에 집중하느라 raw 미등록. 해당 결정의 Evidence Strength 가 그만큼 낮음을 Decision Evidence Map 에 표기:
> - `https://dependency-check.github.io/DependencyCheck/dependency-check-gradle/index.html` — OWASP Dependency-Check (D1 대안: 멀티모듈 `dependencyCheckAggregate` + `failBuildOnCVSS`, NVD API 키 필요)
> - `https://github.com/anchore/grype` — Grype (D1 대안: false-positive 최저 + KEV/EPSS 내장, 단 gradle.lockfile 공식 지원 불명확)
> - `https://nvd.nist.gov/vuln-metrics/cvss` — NVD severity bands (D2 보강: CVSS v3.x/v4.0 밴드 corroboration)
> - `https://www.first.org/epss/` — FIRST EPSS (D8 보강: EPSS ≥ 0.1 escalation 신호 근거)
> - `https://trivy.dev/docs/latest/scanner/vulnerability/` — Trivy 소스 우선순위(언어 패키지 GHSA>NVD) (D4 보강 — coverage 페이지엔 OS 패키지만 명시됨)
> - `https://www.cisa.gov/news-events/directives/bod-26-04-prioritizing-security-updates-based-risk` — CISA BOD 26-04 (D3 보강: KEV=독립 우선순위 인자; CISA HTML 403 으로 본 run 미확보)
## TODO
각 항목 옆에 증거 등급 표기: `actually-implemented` | `locally-verified` | `prod-verified` | `documented-only` | `planned` | `needs-confirmation`
> ca-tmpl ground truth(2026-06-15 확인): `.github/workflows/` 없음, `gradle/locks/` 없음, Renovate/Dependabot/Trivy config 없음 → 본 branch 전 항목 `planned` (코드 미존재). `actually-implemented` 승급은 Phase C2 실 구현 + `src/`/CI grep 확인 후.
- [x] Trivy fs scan CI job (`aquasecurity/trivy-action`, `scan-type: fs`, `exit-code: 1`, `severity: CRITICAL,HIGH`, `TRIVY_FILE_PATTERNS` 멀티모듈 workaround) — 등급: `actually-implemented` (`.github/workflows/dependency-vulnerability.yml` `trivy-fs` 잡, YAML valid; 실제 CI 실행은 `needs-confirmation`) (D1)
- [x] `dependency-review-action` required check (`fail-on-severity: high`) — 등급: `actually-implemented` (`.github/dependency-review-config.yml` + workflow `dependency-review` 잡; graph 제출은 `dependency-submission` 잡으로 보강) (D7)
- [x] severity 정책 문서화: CVSS v3.1 밴드 + ≥High 차단 + KEV override + EPSS escalation — 등급: `actually-implemented` (`.github/dependency-vulnerability-policy.md` §2/§3/§4, 모든 team-policy 값 `UNSUPPORTED_IMPL_DECISION` 라벨) (D2/D3/D8)
- [x] `.trivyignore.yaml` suppression 정책 + 만료일 강제 + 무단변경 차단 정적 게이트 — 등급: `locally-verified` (`verifyTrivyignore` Gradle gate: 6-케이스 pass/fail 검증 + `./gradlew check` green; `.trivyignore.yaml` 빈 seed + `.github/CODEOWNERS` merge-gate) (D5)
- [x] Renovate `security:only-security-updates` 설정 + patch 보안 PR auto-merge 정책 — 등급: `actually-implemented` (`renovate.json`, JSON valid; Renovate 봇 실행은 `needs-confirmation`) (D6)
- [x] scheduled 재스캔 job(CVE DB 갱신 캡처) + pre-release `trivy image` scan — 등급: `actually-implemented` (workflow `schedule` daily cron + `trivy-image` release 잡, `vars.RELEASE_IMAGE_REF` 게이팅으로 container-runtime wiring seam) (D1/구현가이드 §1)
- [x] 의존성 라이선스 스캔: Trivy license(gradle.lockfile) + dependency-review-action `deny-licenses` + 금지 SPDX 목록 정의 — 등급: `actually-implemented` (`scanners: vuln,license` + GPL/AGPL deny-list; 목록은 `UNSUPPORTED_IMPL_DECISION` team-policy) (D10)
- [ ] sibling 역참조 정합: supply-chain D2/D3, ci-gates D5 의 `UNSUPPORTED`/`OWNER_AMBIGUITY` → 본 branch 위임으로 갱신 (§Audit & Findings, 비차단) — 등급: `planned` (비차단 — 다음 작업자/`/sync`; 본 구현 머지와 독립)
## 진행 중 메모
작업하며 떠오른 메모. 자유 형식.
### 2026-06-20 — Phase C2 구현 (ca-tmpl, branch `feature/dependency-vulnerability-management-contract`)
정책 7건(D1·D2/D3/D8·D5·D6·D7·D10·§1)을 ca-tmpl 의 커밋 가능한 아티팩트로 실 구현. 커밋은 사용자가 직접 수행(working tree 만 변경).
**커밋 대상 파일 (tracked):**
- `.github/workflows/dependency-vulnerability.yml` — D1 `trivy-fs`(PR+daily schedule, `scanners: vuln,license`, `severity: CRITICAL,HIGH`, `exit-code:1`, `trivyignores: .trivyignore.yaml`, `TRIVY_FILE_PATTERNS`) + D7 `dependency-review`(PR) + `dependency-submission`(`gradle/actions/dependency-submission`, graph fail-open 보강) + §1 `trivy-image`(release, `vars.RELEASE_IMAGE_REF` 게이팅 — container-runtime wiring seam).
- `.github/dependency-review-config.yml` — D7 `fail-on-severity: high` + `fail-on-scopes: [runtime]` + D10 `deny-licenses`(GPL/AGPL family) + `comment-summary-in-pr: on-failure`.
- `.trivyignore.yaml` — D5 빈 seed(`vulnerabilities/licenses/misconfigurations/secrets: []`) + 헤더에 `id`/`statement`/`expired_at` 포맷 문서화. repo 루트(Trivy 자동 인식).
- `renovate.json` — D6 `config:recommended` + `security:only-security-updates` + `vulnerabilityAlerts`(stable) + `osvVulnerabilityAlerts`(experimental) + patch auto-merge / minor·major human review packageRules.
- `.github/CODEOWNERS` — D5 §3 ② merge-time 승인(`.trivyignore.yaml`·policy·workflows·`renovate.json``@DongHyeonka` placeholder).
- `.github/dependency-vulnerability-policy.md` — D2/D3/D4/D8/D9/D10 통합 정책 SSOT(committed). 모든 team-policy 수치 `UNSUPPORTED_IMPL_DECISION` 라벨.
- `src/build.gradle` — D5 §3 ① `verifyTrivyignore` Gradle gate(line-based parser, `maxWindowDays=90`), `subprojects { check { dependsOn } }` 배선(기존 `verifyEnvKeys` 패턴).
- `src/README.md`·`README.md` — gate 문서화 + 정책 참조.
**검증(locally-verified):** `verifyTrivyignore` 6-케이스 — 빈 seed pass / 유효+nested paths pass / `expired_at` 누락 fail / `statement` 누락 fail / 이미 만료 fail / 90일 초과 fail, seed 복원 후 재pass. `./gradlew check` = BUILD SUCCESSFUL(106 tasks). 4개 check-wired gate 동시 통과. workflow/dep-review YAML + renovate JSON 구문 유효성 확인. CI 러너에서의 실제 스캔 동작은 `needs-confirmation`(§Claims To Verify 참조).
**UNSUPPORTED_IMPL_DECISION 기본값 선택(스켈레톤 default, fork 가 교체):** scheduled=daily(`0 6 * * *`); 차단=≥High; EPSS=0.1(비차단); suppression 창=90일; patch auto-merge; license=deny-list(GPL/AGPL, LGPL 허용); SLA=KEV/Critical 7d·High 30d·Medium 90d. `verifyPublicPathSnapshot` 의 문서화 방식과 동일.
**경계 준수:** `dependencyLocking`/lockfile 생성 미추가(supply-chain D8 owner) — Trivy fs 는 lockfile 커밋 전까지 Gradle deps no-op, 그 사이 `dependency-submission` graph 가 transitive backstop. image scan **wiring**`vars.RELEASE_IMAGE_REF` seam 으로 container-runtime 에 위임. CI gate `needs:`/`if:` 배선은 ci-gates owner(본 파일은 정책만).
### 2026-06-20 — 코드 리뷰 수정 2건 (workflow correctness)
- **TRIVY_EXIT_CODE 주석 오기 정정 (correctness):** `trivy-fs` 잡의 `TRIVY_EXIT_CODE: "1"``exit-code: "1"` 입력과 동일 knob(취약점 *발견 시* 종료코드)이라 중복이었고, 주석이 이를 "DB fetch 실패 시 fail" 메커니즘으로 *오기*했다. 제거하고, DB-fetch 실패→fail 은 Trivy **기본 동작**(캐시 없으면 DB 다운로드 실패 시 non-zero)이며 설정 플래그가 아님 + 여전히 `needs-confirmation` 임을 정직하게 주석화. §Claims To Verify "스캐너 DB fetch 실패가 silent pass 가 아니라 job fail" 은 **여전히 미검증(`planned`)** — 이전 주석이 충족을 거짓 주장했던 것을 철회. 실검증: CI 에서 DB endpoint 차단 후 non-zero exit 단언.
- **Medium "warn/advisory" 티어 실현:** policy §2 표는 Medium=warn(advisory)/Low=report 인데 두 Trivy 잡이 `severity: CRITICAL,HIGH` 만 스캔해 Medium/Low 를 보고조차 안 했음(정책-구현 gap). `trivy-fs` 에 비차단 advisory step(`severity: MEDIUM,LOW`, `exit-code: "0"`) 추가로 보고만 하고 차단 안 하는 티어 실현. policy §2 운영 구현 줄도 정합.
- **D3 KEV override 실효 강제 (실효 강제 0 → 실제 차단):** severity 필터가 `CRITICAL,HIGH` 라 §2 matrix 의 "KEV 등재 시 모든 밴드 block" 의도가 Low/Medium 에서 미실현이었음(실효 강제 0). `trivy-fs` 에 (1) 전체 밴드 JSON 스캔(`severity: CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN`, `exit-code:0`, `format: json`) + (2) `KEV override gate` run step(CISA KEV JSON feed `curl -fsSL --retry 3``jq`/`comm` 으로 발견 CVE ∩ KEV → 교집합 있으면 `exit 1`) 추가. suppression(`.trivyignore.yaml`)은 그대로 적용 → KEV CVE 는 거버넌스된 suppression 으로만 수용. feed 미가용 = `curl -f` fail-closed(silent pass 금지, §Edge·Failure JSON feed 가용성 충족). policy §3 을 posture→실효 강제로 갱신. **Open Risk(유지):** KEV 등재 지연, feed CI 의존.
- 검증: workflow YAML 재유효성 OK; `TRIVY_EXIT_CODE` 제거 + advisory/KEV step 존재 grep 확인; **KEV cross-check 로직 mock 3-케이스 검증** — KEV 등재 CVE 발견 시 exit1(block), 빈 발견셋(lockfile 부재) pass, 비-KEV CVE pass. (Java/Gradle 코드·게이트 로직 무변경이라 `./gradlew check` 재실행 불요. CI 러너 실제 동작은 `needs-confirmation`.)
### 2026-06-20 — Gitea/act 플랫폼 적응 (CI 실패 1건 해소)
사용자가 commit `cb12207` push 후 self-hosted **Gitea + act_runner**(k8s 내부, `gitea-http.platform.svc.cluster.local`)에서 워크플로 실행 → 2개 잡 실패. 타깃 플랫폼 = Gitea 확정.
- **`dependency-review` 실패 (원인 확정):** `::error::Dependency review could not obtain dependency data...`. dependency-review-action 은 **GitHub Dependency Graph compare API**(GitHub.com/GHES 전용)에 의존 → Gitea 에 API 부재 + `dependency-submission`(graph 제출, push-only)이 PR 이벤트라 skip 돼 graph 도 비어있음. **수정:** `dependency-review`·`dependency-submission` 두 잡에 `&& github.server_url == 'https://github.com'` 가드 추가 → Gitea 에선 skip(실패 아님), GitHub.com 에선 그대로 동작. Gitea 의 PR-time 의존성 검사는 플랫폼 독립적 `trivy-fs`(매 PR)가 커버(D7 단독 게이트 금지 설계가 backstop 제공). policy §8 에 플랫폼 호환성 note 추가.
- **`trivy-fs` 실패 (원인 확정 — egress 가설 철회):** trivy-fs step 로그 입수 → `git clone 'https://github.com/aquasecurity/trivy-action' # ref=0.28.0``Unable to resolve 0.28.0: reference not found`. **egress 문제 아님**(러너가 actions/checkout·trivy-action 을 github.com 에서 정상 clone — github.com·ghcr 접근 가능). 진짜 원인은 **액션 태그 오타**: `aquasecurity/trivy-action` 의 실제 태그는 `v` 접두사(`v0.28.0`)인데 `@0.28.0`(v 없이)로 핀해 404. GitHub API 로 실제 태그 확인(`tags/0.28.0`=404, `tags/v0.28.0`=200; 최신 `v0.36.0`). **수정:** 워크플로 4곳 `@0.28.0``@v0.28.0`(replace_all). 내 1차 "egress 차단" 진단은 4s 빠른 실패만 보고 세운 가설이었고 로그가 반증 — *증거 우선* 위반 사례.
- skip 정상: `dependency-submission`(push-only)·`trivy-image`(release-only)는 PR 이벤트라 의도된 skip(회색).
- 검증: workflow YAML 재유효성 OK, server_url 가드 2건 + trivy-action `@v0.28.0` 4건 grep 확인, GitHub API 로 `v0.28.0` 존재 확인. (YAML 변경만 — `./gradlew` 무관.) **재실행 후 trivy-fs 완전 통과(Trivy DB pull + KEV step cisa.gov curl 포함)는 `needs-confirmation`.**
- **`trivy-fs` 2차 실패 → CLI 전환 (act 의 trivy-action 미지원):** 태그 수정 후 재실행하니 액션 resolve 는 통과했으나 `entrypoint.sh: line 44: trivy: command not found`. `aquasecurity/trivy-action` 은 setup-trivy 서브액션 + DB 캐시로 Trivy 를 설치하는 **composite** 인데 act 가 그 설치 스텝을 안 돌려 바이너리 부재. **수정:** trivy-action 폐기 → **Trivy + jq CLI 정적 바이너리를 github.com 에서 직접 설치**(`trivy v0.71.2`, `jq 1.8.1`, API 로 태그/자산명 사전 확인) 후 `trivy fs`/`trivy image` CLI 직접 호출. `--file-patterns` 제거(`**/*.lockfile` 는 CLI 에서 invalid regex 위험 + 표준 `gradle.lockfile` 명명은 Trivy 기본 탐지로 충분; 비표준 명명만 Claims To Verify). KEV step 에 `KEV_FEED_URL` repo-var override(폐쇄망 미러) + fetch 실패 시 명시적 fail-closed 메시지 추가. CLI 는 GitHub.com·Gitea/act 공통.
- skip 정상: `dependency-submission`(push-only)·`trivy-image`(release-only)는 PR 이벤트라 의도된 skip(회색).
- 검증: workflow YAML 재유효성 OK(CLI 전환 후); `uses: aquasecurity/trivy-action` 제거(주석만 잔존) + `trivy fs`/`trivy image` CLI step grep 확인; GitHub API 로 `trivy v0.71.2`·`jq-1.8.1` 자산 존재 확인; KEV jq/comm 로직 mock 3-케이스 재확인. (YAML 변경만 — `./gradlew` 무관.) **남은 egress 의존(재실행 시 다음 관문): github.com=확인됨, ghcr.io(Trivy DB)·KEV feed 호스트=`needs-confirmation`(폐쇄망이면 `TRIVY_DB_REPOSITORY`/`KEV_FEED_URL` 미러).**
- 파생: [[raw/errors/gitea-act-action-tag-and-dependency-graph-2026-06-20]] (CI 실패 근본원인 + 수정, 2-iteration).
## 결정 사항
> 추후 면접/회고에서 "왜 이렇게 했나" 답할 근거. 대안과 함께 기록. 각 결정의 근거는 위 Sources 또는 새로 추가된 raw 자료를 가리킬 것. 상세 매핑은 아래 Decision Evidence Map.
- 2026-06-15: **SCA 스캐너 = Trivy** (fs 의존성 + image 동일 바이너리, `aquasecurity/trivy-action`). 이유: OSS(Apache 2.0) + gradle.lockfile 공식 지원 + NVD API 키 불필요 + image 동일 도구 + `exit-code`/`severity` 로 release-blocking 즉시 구성. 검토한 대안: OWASP Dependency-Check(멀티모듈 aggregate 성숙하나 NVD 키 필요), Grype(FP 최저·KEV/EPSS 내장하나 gradle.lockfile 지원 불명확), Snyk(상용 — OSS 스켈레톤 부적합 제외), dependency-review-action(PR 보완 전용). 근거: [[raw/official-docs/trivy-java-language-coverage]], [[raw/official-docs/trivy-action-github-actions]]. (ci-gates D5 의 `OWNER_AMBIGUITY`/미결 해소 — D1)
- 2026-06-15: **차단 심각도 = CVSS v3.1 base score, High(≥7.0)·Critical(≥9.0) 차단**, Medium/Low 는 warning-only. 이유: 스캐너·NVD 커버리지 완전 + FIRST.org 권위 표준 밴드 + industry de-facto 임계값. 검토한 대안: CVSS v4.0(스캐너 미성숙 — 2026-12 재평가). 근거: [[raw/official-docs/vuln-severity-cvss-v31-spec-first-official]]. (supply-chain D2 에 외부 표준 부여 — D2)
- 2026-06-15: **KEV override** — CISA KEV 등재 CVE 는 CVSS 점수 무관 차단. 이유: exploited-in-the-wild 는 점수보다 실위험이 큼(CISA `dueDate` 부여). 근거: [[raw/official-docs/vuln-severity-cisa-kev-catalog-official]]. (D3)
- 2026-06-15: **Suppression governance**`.trivyignore(.yaml)` + 만료일 강제 + `statement` 사유 + PR 승인 + 무단변경 차단 정적 게이트. 이유: 만료 없는 영구 ignore 차단(2026-05-25 ca-tmpl audit finding 해소). 근거: [[raw/official-docs/trivy-filtering-suppression-policy]]. (D5)
- 2026-06-15: **의존성 보안 업데이트 = Renovate primary / Dependabot 조건부**. 이유: version-catalog+lockfile 동시 사용 시 Dependabot lockfile 미갱신 버그(#12557)가 supply-chain D8 locking 과 충돌; Renovate 는 security-only preset + patch auto-merge 단순. 검토한 대안: Dependabot(조직 표준/단순 구조 시 허용). 근거: [[raw/official-docs/renovate-vulnerability-alerts-gradle-official]], [[raw/official-docs/dependabot-security-updates-gradle-official]]. (supply-chain D3 정합 — D6)
- 2026-06-15: **PR-time 보완 게이트 = dependency-review-action** (`fail-on-severity: high`, required). 단독 릴리즈 게이트 금지(PR diff 전용). 근거: [[raw/official-docs/github-dependency-review-action]]. (D7)
- 2026-06-15: **의존성 라이선스 준수 스캔 = Trivy license(이미 toolchain) + dependency-review-action allow/deny**. 이유: D1 Trivy 가 `*gradle.lockfile` license 도 스캔하므로 별도 도구 불필요; governing §35-E L2052 가 license scan 을 본 branch 영역으로 명시. 근거: [[raw/official-docs/trivy-java-language-coverage]], [[raw/official-docs/github-dependency-review-action]]. (D10)
## 결정-근거 매핑
> 각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시한다.
> `Decision ID` 는 이 branch-note 안에서 안정적으로 유지한다. 예: `D1`, `D2`.
> `Supporting Claims` 는 `raw/<category>/<slug>.md#C1` 형식으로 연결한다.
> `선택 조건` 열(R2): "이 조건일 때 이 결정, 다른 조건이면 어떤 대안". 분기 없으면 `N/A`.
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | **SCA 스캐너 = Trivy** (fs 의존성 스캔 + image 동일 바이너리, `aquasecurity/trivy-action`, `exit-code:1`+`severity:CRITICAL,HIGH`=release-blocking) | OSS + NVD 키 불필요 + gradle.lockfile 지원 + image 동일 도구 → **Trivy**. 멀티모듈 `dependencyCheckAggregate` 공식 지원 + CVSS 소수점 임계값 제어가 더 중요 → **OWASP Dependency-Check** (NVD API 키+캐싱 감수). FP 최저+EPSS/KEV 내장이 최우선 → **Grype**(단 gradle.lockfile POC 선행) | `raw/official-docs/trivy-java-language-coverage.md#C1` (`*gradle.lockfile` SBOM/Vuln/License ✓), `raw/official-docs/trivy-java-language-coverage.md#C2` (오프라인 스캔), `raw/official-docs/trivy-action-github-actions.md#C1`·`#C2` (exit-code/severity release-blocking), `raw/official-docs/trivy-action-github-actions.md#C4` (`trivyignores`) | `official-vendor-doc` (Aqua Trivy) — 대안(OWASP DC/Grype/Snyk) 비교는 §Sources Deferred 아카이브 | 멀티모듈 lockfile 탐지 버그 → `--file-patterns "gradle-lockfile:*.lockfile"` workaround(공식 문서 미명시, Claims To Verify); Gradle `force=true` 재정의 false positive; **lockfile 생성이 선행조건** → [[raw/branch-notes/feature-build-release-supply-chain-contract]] D8(dependency-locking) 의존 |
| D2 | **차단 심각도 = CVSS v3.1 base score; High(≥7.0)·Critical(≥9.0)=release-blocking**, Medium(4.06.9)/Low(0.13.9)=warning-only(비차단 advisory) | 스캐너 지원·NVD 커버리지 완전 → **v3.1**. 스캐너 v4.0 파싱 안정 + NVD/Vulnrichment v4.0 커버리지 확보 후 → **v4.0**(밴드 수치 동일, 2026-12 재평가) | `raw/official-docs/vuln-severity-cvss-v31-spec-first-official.md#C1` (Table 14 밴드 None/Low/Medium/High/Critical), `raw/official-docs/vuln-severity-cvss-v31-spec-first-official.md#C2` (정성 등급=조직 vuln mgmt 프로세스 입력), `#C3` (base score=intrinsic) | `official-standard` (FIRST.org) — **단 밴드만 표준**; "≥High 차단" 임계값 선택은 industry de-facto(`team-policy`) | "≥High 차단"의 industry de-facto 근거 미아카이브 → `UNSUPPORTED_IMPL_DECISION`(§구현가이드 §2); v3.1 Scope metric 불일치 알려짐; NVD enrichment 정책 변경(2026-04) → 신규 CVE CVSS 공백 가능(Claims To Verify) |
| D3 | **KEV override** — CISA KEV catalog 등재 CVE = CVSS 점수 무관 release-blocking | N/A (항상 적용 — exploited-in-the-wild 가 점수보다 우선) | `raw/official-docs/vuln-severity-cisa-kev-catalog-official.md#CISA-KEV-C1` (catalog 존재), `#CISA-KEV-C3` (`dueDate`=CISA 우선 시한 부여), `#CISA-KEV-C4` (ransomware 연관 식별) | `official-vendor-doc` (CISA JSON feed) — "exploited in the wild" 정의·비연방 권고·BOD 26-04 4-factor 는 CISA HTML **403 으로 미확보**(needs-confirmation, Deferred) | KEV 등재 지연(악용→catalog entry 간격); JSON feed 가용성 CI 의존; BOD rationale 미아카이브 |
| D4 | **소스 우선순위 tie-break**: Java/Gradle 의존성 → GitHub Advisory Database(GHSA) 우선 → NVD fallback | NVD 와 GHSA/벤더 점수 충돌 시 GHSA 우선(Trivy 기본). KEV 등재면 tie-break 무관 차단(D3) | `raw/official-docs/trivy-java-language-coverage.md#C5` (Java 취약점 소스 = GitHub Advisory Database (Maven)) | `official-vendor-doc` (**부분**) — *GHSA 를 소스로 씀* 만 확인; *충돌 시 GHSA 가 NVD override* 명시는 coverage 페이지에 없음(OS 패키지만 명시) → 부분 `UNSUPPORTED_DECISION` | language-package vendor>NVD 우선순위 verbatim 미확보 → Trivy scanner/vulnerability 페이지 보강 필요(Deferred + Claims To Verify) |
| D5 | **Suppression governance**`.trivyignore`/`.trivyignore.yaml` + **만료일 필수**(`exp:YYYY-MM-DD`/`expired_at`) + `statement` 사유 + PR review approval + **무단 `.trivyignore` 변경 차단 정적 CI 게이트** | false-positive/accepted-risk suppress 필요 시 — 만료 없는 영구 ignore 금지 | `raw/official-docs/trivy-filtering-suppression-policy.md#C1` (CVE 한 줄+만료 지원), `#C3` (`exp:YYYY-MM-DD`), `#C4` (`expired_at`, 미지정시 영구유효), `#C5` (`statement`=사유 기록) | `official-vendor-doc` (Trivy filtering) | 만료 기간 길이(예: 90d)·PR 승인 권한(CODEOWNERS)·무단변경 차단 게이트 구현(regex)은 team-policy → `UNSUPPORTED_IMPL_DECISION`(§구현가이드 §3). 2026-05-25 ca-tmpl audit `.trivyignore` 무단 우회 finding 해소 대상 |
| D6 | **의존성 보안 업데이트 = Renovate primary** (`security:only-security-updates` preset → `vulnerabilityAlerts`+`osvVulnerabilityAlerts`), **Dependabot 조건부** | `gradle/libs.versions.toml` version catalog + Gradle lockfile 동시 사용 → **Renovate** (Dependabot #12557 lockfile 미갱신 버그가 supply-chain D8 locking 과 충돌). 조직이 Dependabot 표준 또는 lockfile 미사용 단순 구조 → **Dependabot** 허용 | `raw/official-docs/renovate-vulnerability-alerts-gradle-official.md#C1`·`#C2` (`security:only-security-updates`→osv+vulnerabilityAlerts), `raw/official-docs/dependabot-security-updates-gradle-official.md#C1` (security updates 정의), `#C2` (security vs version 구분), `#C3` (grouped per-ecosystem), `#C5` (manifest/lock 한정 트리거) | `official-vendor-doc` (Renovate + GitHub) | Renovate `osvVulnerabilityAlerts` experimental 상태 + vuln-alert schedule-ignore 는 presets 페이지 **미확인**(needs-confirmation); Dependabot Gradle 지원·#12557·native auto-merge 부재는 researcher finding(이 페이지 미확인); **transitive 취약점은 둘 다 직접 의존성만** → Gradle dependency constraint 수동 override 필요(§구현가이드 §4) |
| D7 | **PR-time 보완 게이트 = GitHub dependency-review-action** (`fail-on-severity: high`, required check) | 모든 PR(feature + 보안 PR). **단독 릴리즈 게이트 금지** — PR diff 전용이라 기존 의존성 전수 스캔 못함, 그건 D1 Trivy fs | `raw/official-docs/github-dependency-review-action.md#C1` (catch before introduce), `#C2` (PR 도입 취약 버전 스캔), `#C3` (default fail + required 시 merge block), `#C4` (REST API base..head diff), `#C5` (severity 커스터마이즈) | `official-vendor-doc` (GitHub) | Gradle dependency graph 가 GitHub 에 제출돼야 diff 유의미(Claims To Verify); `fail-on-severity` 정확 값은 별도 config 페이지(needs-confirmation, Deferred) |
| D8 | **EPSS escalation signal (optional, 비차단)** — EPSS ≥ 0.1 인 Low/Medium CVE → 즉시 review ticket(P1). **하드 차단 아님** | D2 에서 비차단(Low/Medium)인데 EPSS≥0.1 → escalate. High/Critical 은 이미 D2 차단 | `UNSUPPORTED_DECISION` — FIRST EPSS 페이지 미아카이브(Deferred); 0.1 임계값은 FIRST top-decile practitioner 합의일 뿐 공식 차단 mandate 없음 | `team-policy` (외부 reference: FIRST EPSS, deferred) | EPSS=확률 추정 → false positive; 0.1 임계값=조직 정책; 본 결정 자체 optional(미도입 가능) |
| D9 | **Remediation SLA by severity** — KEV/Critical: 즉시(≤Xd), High: ≤Yd, Medium: ≤Zd | 차단/escalation 된 취약점 수정 기한 | `UNSUPPORTED_DECISION` — 비-KEV SLA 수치는 외부 표준 부재(team-policy). KEV 항목만 `raw/official-docs/vuln-severity-cisa-kev-catalog-official.md#CISA-KEV-C3` (`dueDate`) 외부 anchor | `team-policy` (+ KEV 항목 official-vendor-doc anchor) | 정량 일수(X/Y/Z)는 조직 결정 — 임의 trade-off 제시 시 `UNSUPPORTED_IMPL_DECISION` |
| D10 | **의존성 라이선스 준수 스캔(license/NOTICE)** = Trivy license scanner(이미 toolchain) + dependency-review-action allow/deny license list. 금지(strong-copyleft) 라이선스 = release-blocking, allow-list 정책 | Trivy 가 이미 D1 로 채택됐고 `*gradle.lockfile` license 스캔 → **별도 license 도구 불필요**(통합). PR-time 신규 라이선스 도입 차단은 dependency-review-action allow/deny | `raw/official-docs/trivy-java-language-coverage.md#C1` (gradle.lockfile **License ✓**), `raw/official-docs/github-dependency-review-action.md#C6` (allow/deny list for licenses) | `official-vendor-doc` (Trivy + GitHub) | **금지/허용 SPDX 라이선스 목록**(어떤 id 가 release-blocking 인지)은 조직 정책 → `UNSUPPORTED_IMPL_DECISION`(§구현가이드 §5); Trivy license 감지는 Gradle cache 디렉터리(`$GRADLE_USER_HOME/caches`) 의존(`trivy-java-language-coverage` 메모 — dependency-tree EXPERIMENTAL) → Claims To Verify |
## 구현 가이드
> *결정 (Decisions)* 이 "*무엇* 을 할 것인가" 라면, 본 §는 "*어디에 어떻게* 구현될 것인가" 의 사전 명세 — *문서가 모호해서 구현자가 임의로 정해야 했던 결정* 카탈로그. 작성 목표는 다음 구현자가 *되묻지 않아도 코드를 작성할 수 있는 수준*.
>
> **본 §는 일률적 anchor list 를 강제하지 않는다.** branch 마다 구현 내용·범위가 다르므로 sub-section 은 *이 branch 의 결정과 근거에서 도출되는 것만* 작성. 어떤 branch 는 error mapping 표 + 정적 강제 카탈로그, 어떤 branch 는 migration 단계 + wiring, 어떤 branch 는 sequence + state machine. 형식 예시는 [[raw/branch-notes/feature-boundary-validation-mapping-contract]] 의 §구현 가이드 참조.
>
> **3-rule meta principle (필수 준수)**:
>
> 1. **R1. Reference 필수** — 각 sub-section / row / cell 은 본 branch 의 `Decision ID` (예: D1, D2) + 그 결정의 `Supporting Claim ID` (예: `RAW-SLUG-C1`) 를 reference. *근거 없는 결정 금지* — 모든 구현 detail 은 결정 + 근거의 *도출* 이어야 함.
> 2. **R2. UNSUPPORTED_IMPL_DECISION 명시** — 근거 raw 가 *원칙* 만 권고하고 *detail* (메커니즘 선택 / 클래스/rule 명명 / glob 패턴 / algorithm / factory API 모양 등) 은 권고하지 않는 cell 은 `UNSUPPORTED_IMPL_DECISION` 라벨 + 사용자 trade-off 근거 한 줄. 이게 *근거 있는 결정 vs 사용자 임의 trade-off* 의 경계.
> 3. **R3. OUT_OF_BRANCH_SCOPE 정제** — 본 branch 결정 범위 밖 cell 은 §구현 가이드에 *남기지 않음*. 별도 branch 또는 canonical SSOT 로 이관 (이관 history 는 별도 § "Audit & Findings" 등에 보존). 도메인 특화 detail (ca-tmpl skeleton 범위 밖) 도 동일하게 정제.
>
> **각 sub-section 의 권장 헤더 패턴**:
>
> ```markdown
> ### N. <sub-section 제목>
>
> > **Trace**: <In-scope row 들 + Decision ID + Supporting Claim ID 의 매핑 (한 줄/한 단락)>
> >
> > - **UNSUPPORTED_IMPL_DECISION**: <근거 없는 사용자 임의 결정 항목들 + 각각의 trade-off 근거 한 줄>
>
> <표 또는 명확한 구조 — 자유 텍스트 = 모호함 = 되묻기 원인>
> ```
### 1. 스캔 배선 — 단계별 스캐너 실행 (3-stage)
> **Trace**: D1 (`trivy-java-language-coverage#C1`·`#C2`, `trivy-action-github-actions#C1`·`#C2`·`#C3`), D7 (`github-dependency-review-action#C2`·`#C3`). gate 의 *release-blocking 배선*(`needs:`/`if:`) 자체는 [[raw/branch-notes/feature-ci-quality-gates-contract]] owner — 본 §는 *무엇을 어느 단계에서 스캔하는지* 만 정의하고 ci-gates 가 wiring.
>
> - **UNSUPPORTED_IMPL_DECISION**: scheduled 재스캔 **주기**(아래 표의 daily) — Trivy DB 는 ~6h 갱신이나 재스캔 cron 빈도는 외부 표준 없음(team-policy). trade-off: daily = 신규 CVE 노출 ≤24h vs CI 비용. 더 잦으면 noise/비용↑.
> - **UNSUPPORTED_IMPL_DECISION**: 멀티모듈 lockfile `--file-patterns "gradle-lockfile:*.lockfile"` — Trivy 공식 문서 미명시 workaround(GitHub Discussion #9740). trade-off: ca-tmpl 실제 lockfile 명명(`gradle.lockfile` vs `gradle/dependency-locks/*.lockfile`)에 맞춰야 함 → Claims To Verify.
| 단계(stage) | 도구 | scan-type | trigger | severity gate | 잡는 것 |
|---|---|---|---|---|---|
| PR — 신규 도입 차단 | dependency-review-action | (REST API diff) | `pull_request` | `fail-on-severity: high` | PR diff 로 *새로 들어온* 취약 의존성 (D7) |
| PR — 전체 스냅샷 | Trivy | `fs` (lockfile) | `pull_request` | `exit-code:1` + `severity:CRITICAL,HIGH` | 기존+신규 전체 의존성 CVE (D1) |
| scheduled 재스캔 | Trivy | `fs` (lockfile) | `schedule`(daily) | 동일 | 의존성 불변이라도 **새 CVE DB** 로 새로 매치된 취약점 |
| pre-release | Trivy | `image` | release tag | 동일 | 컨테이너 이미지 OS/런타임 패키지 취약점 — *severity 정책만* 본 branch, wiring 은 [[raw/branch-notes/feature-container-runtime-contract]] |
### 2. Severity 판정 매트릭스 (CVSS + KEV + EPSS)
> **Trace**: D2 (`vuln-severity-cvss-v31-spec-first-official#C1`·`#C2`·`#C3`), D3 (`vuln-severity-cisa-kev-catalog-official#CISA-KEV-C1`·`#C3`), D8 (UNSUPPORTED — FIRST EPSS deferred), D4 (`trivy-java-language-coverage#C5`). 이 매트릭스는 ci-gates·container-runtime·supply-chain 이 공유 consume 하는 **단일 severity 표준**.
>
> - **UNSUPPORTED_IMPL_DECISION**: "≥High 차단" 임계값 — FIRST.org 는 밴드(C1)만 표준화하고 *어느 등급부터 차단인지* 는 소비자 책임(C2)으로 명시. ≥High 차단은 industry de-facto(GitHub/Snyk/OSV-Scanner default). trade-off: ≥Medium 차단 시 FP noise 급증; Critical-only 차단 시 exploit code 있는 High 누수.
> - **UNSUPPORTED_IMPL_DECISION**: EPSS 임계값 `0.1` — FIRST top-decile practitioner 합의, 공식 차단 mandate 없음. trade-off: 낮추면 FP↑. (D8 자체가 optional)
| 입력 | None 0.0 | Low 0.13.9 | Medium 4.06.9 | High 7.08.9 | Critical 9.010.0 |
|---|---|---|---|---|---|
| 기본 게이트 결정 | pass | pass(report) | **warn**(advisory) | **block** | **block** |
| KEV 등재 시(D3) | block | block | block | block | block |
| EPSS ≥ 0.1 시(D8) | — | review ticket | review ticket | (이미 block) | (이미 block) |
- **소스 우선순위(D4)**: 동일 CVE 의 점수가 NVD vs GHSA 로 다르면 Java/Gradle 패키지는 GHSA 우선 → NVD fallback. (단 §Open Risk: 언어-패키지 override 명시 verbatim 미확보.)
### 3. Suppression governance
> **Trace**: D5 (`trivy-filtering-suppression-policy#C1`·`#C3`·`#C4`·`#C5`). 2026-05-25 ca-tmpl audit `.trivyignore` 무단 우회 finding 해소.
>
> - **UNSUPPORTED_IMPL_DECISION**: 만료 **기간 상한**(예: 90일)·승인 권한(CODEOWNERS 대상)·무단변경 차단 게이트의 **구현 메커니즘**(CI step regex vs CODEOWNERS protected path) — Trivy 문서는 `expired_at` 필드 *존재*만 보장(C4), 정책 수치는 권고 안 함. trade-off: 짧으면 재검토 부담↑, 길면 사실상 영구 ignore.
| 규칙 | 강제 방법 | 근거 |
|---|---|---|
| suppression 은 `.trivyignore.yaml` 단일 파일 | CI 가 인라인 ignore/CLI `--ignore` 사용 금지 검사 | C2 (구조화 YAML) |
| 각 항목 **만료일 필수** (`expired_at` 누락 금지) | CI 정적 검사: `expired_at` 없는 row fail (C4: 미지정시 영구유효 → 금지) | C4 |
| 각 항목 **`statement` 사유 필수** | CI 정적 검사: `statement` 빈 row fail | C5 |
| `.trivyignore.yaml` 변경은 **PR 승인 필수** | **역할 분리(둘 다 필요)**: ① CODEOWNERS protected path + branch protection = *merge-time* 승인 강제(GitHub native), ② CI step regex = `expired_at`/`statement` 필드 검증(CODEOWNERS 가 못 하는 내용 검증) | audit finding |
> **UNSUPPORTED_IMPL trade-off (위 표 ② 보강)**: 무단 변경 차단의 1차 메커니즘은 **CODEOWNERS protected path**(GitHub-native, merge 차단). 단 CODEOWNERS 는 *파일 변경 승인*만 강제하고 *만료일·사유 누락*은 못 잡으므로 CI regex step 이 병행 필수 — 둘은 대체재가 아니라 보완재.
### 4. 의존성 보안 업데이트 자동화 + transitive 처리
> **Trace**: D6 (`renovate-vulnerability-alerts-gradle-official#C1`·`#C2`, `dependabot-security-updates-gradle-official#C1`·`#C2`·`#C3`·`#C5`). supply-chain D3(Renovate/Dependabot) 정합.
>
> - **UNSUPPORTED_IMPL_DECISION**: patch-level 보안 PR **auto-merge** — Renovate `automerge`+`matchUpdateTypes:["patch"]` 조합은 일반 기능이나, *patch 만 auto-merge / minor·major 는 human review* 경계는 team-policy(이 페이지 미아카이브). trade-off: CI 커버리지 낮으면 취약 patch 자동 merge 위험.
> - **UNSUPPORTED_IMPL_DECISION**: `osvVulnerabilityAlerts` on/off — experimental 상태(needs-confirmation). 기본 `vulnerabilityAlerts`(GitHub Alerts, stable) primary, osv 는 maven 커버리지 검증 후 opt-in.
| 항목 | 정책 | 비고 |
|---|---|---|
| primary 도구 | Renovate `security:only-security-updates` preset | C1 (osv+vulnerabilityAlerts 활성) |
| 조건부 대안 | Dependabot (조직 표준 또는 lockfile 미사용) | #12557 lockfile+catalog 충돌 회피가 Renovate 선택 이유 |
| patch 보안 PR | CI green 시 auto-merge | UNSUPPORTED_IMPL (위) |
| minor/major 보안 PR | human review 필수 | breaking 위험 |
| **transitive 취약점** | Renovate/Dependabot 미커버(직접 의존성만) → Gradle `dependencies { constraints { } }` 또는 `resolutionStrategy.force` 로 수동 override | UNSUPPORTED_IMPL: Gradle 메커니즘 선택. supply-chain D8 locking 과 정합 필요 |
### 5. 의존성 라이선스 준수 스캔 (license/NOTICE)
> **Trace**: D10 (`trivy-java-language-coverage#C1` — `*gradle.lockfile` License ✓; `github-dependency-review-action#C5` — allow/deny license list). governing §35-E L2052 가 license scan 을 본 branch 영역으로 명시.
>
> - **UNSUPPORTED_IMPL_DECISION**: **금지/허용 SPDX 라이선스 목록** — 어떤 라이선스(예: GPL-3.0/AGPL-3.0 strong-copyleft)가 release-blocking 인지는 조직 법무/정책. Trivy/GitHub 문서는 *스캔·allow/deny 메커니즘*만 보장. trade-off: 보수적(allow-list only) = 신규 의존성 마찰↑; 관대(deny-list) = 누락 위험.
| 단계 | 도구 | 동작 | 근거 |
|---|---|---|---|
| PR-time 신규 라이선스 차단 | dependency-review-action | `allow-licenses`/`deny-licenses` 목록으로 PR diff 의 새 의존성 라이선스 검사 | `github-dependency-review-action#C6` |
| 전체 스냅샷 license scan | Trivy (D1 과 동일 fs scan) | `*gradle.lockfile` License 컬럼 — 별도 도구 불필요 | `trivy-java-language-coverage#C1` |
| forbidden 라이선스 발견 | release-blocking | CVE 차단(D2)과 동일 게이트 계열 | 정책(UNSUPPORTED_IMPL: 목록) |
## Audit & Findings — Single-Owner 정합 (cross-branch)
> 본 branch 가 §25 SSOT Owner Map 에 부재하던 **dependency vulnerability *정책* owner** 로 신설되며 해소하는 cross-branch finding. consistency-contract §전파의 *역참조 비차단 알림* 대상(쓰기 시 hook 이 ci-gates:255 → D5 참조를 3회 알림). 아래는 owner 확정 + sibling 갱신 권고(비차단 — 본 branch 머지와 독립).
**1. OWNER 확정 (Cross-Branch Conflict Procedure §25 통과)**
- §25 SSOT Owner Map `contract area` grep: "vulnerability"/"dependency vulnerability" owner **부재** 확인 → 본 branch 가 new owner 자격.
- sibling grep 결과 동일 영역 스텁 3건 발견(모두 UNSUPPORTED, 검증 깊이 0 → 시간순·도메인 우선 원칙상 전용 branch 가 SSOT):
- ci-gates **D5** + §Audit `OWNER_AMBIGUITY`: "scanner *tool 선택* 미결 → dependency-vulnerability 또는 supply-chain 으로 위임" → **본 branch D1 이 Trivy 로 확정**(미결 해소).
- supply-chain **D2** (high/critical=release-blocking, UNSUPPORTED, "CVSS 외부 표준 보강 권고") → **본 branch D2/D3 이 CVSS v3.1 + KEV 표준 부여**.
- supply-chain **D3** (Renovate/Dependabot, ~~UNSUPPORTED~~ → 2026-06-15 `official-vendor-doc` 로 전환: [[raw/official-docs/renovate-gradle-manager-official]] RENOV-GRAD-C1~C4) → **본 branch D6 이 security-update 정책 owner 로 확정** (supply-chain D3 는 Gradle 지원 범위·lockfile·supply-chain 제약 raw 소유).
**2. Sibling 역참조 갱신 권고 (비차단, 다음 작업자/`/sync`)**
| 대상 | 현재 | 갱신 후 |
|---|---|---|
| ci-gates D5 / §Audit OWNER_AMBIGUITY | "scanner tool 선택 미결" | "scanner = [[feature-dependency-vulnerability-management-contract]] D1 (Trivy, 결정 완료)" |
| ci-gates Gate 매트릭스 "vulnerability scan" owner 열 | severity=supply-chain / tool=dependency-vuln(미결) | severity·tool·suppression 정책 = dependency-vuln D1~D5; *gate 배선* 만 ci-gates |
| supply-chain D2 | UNSUPPORTED (severity 표준 보강 권고) | "severity 표준 = dependency-vuln D2(CVSS v3.1)+D3(KEV); 본 D2 는 release-block *시점/posture* 만 소유" |
| supply-chain D3 | ~~UNSUPPORTED~~`official-vendor-doc` 로 갱신됨 (2026-06-15: [[raw/official-docs/renovate-gradle-manager-official]] RENOV-GRAD-C1~C4 등록) | "security-update 정책 owner = dependency-vuln D6; supply-chain D3 는 Gradle 파일 패턴·lockfile 갱신·supply-chain 제약 근거를 소유" |
| **container-runtime (image-scan Decision 부재)** | image scan/Trivy/severity 결정 0건 → 본 branch 의 consumer 링크가 dangling | container-runtime 에 "image vuln scan = Trivy image, severity 정책 = dependency-vuln D2/D3 consume" Decision 신설 권고(없으면 §구현가이드 §1 pre-release row 의 wiring owner 가 미존재) |
| 프로젝트노트 §25 SSOT Owner Map | (row 없음) | 신규 row: `dependency vulnerability policy \| feature-dependency-vulnerability-management-contract \| consumers: ci-gates(gate wiring)·container-runtime(image scan)·supply-chain(release-block posture)`**본 루프에서 프로젝트노트에 직접 추가함**(coverage Should-fix 해소) |
**3. Producer/Consumer 경계 (재진술 금지 — Reference-Only)**
- 본 branch = **producer** of severity 표준 + scanner + suppression + update 정책.
- ci-gates·container-runtime·supply-chain = **consumer** (배선/시점만). 본 branch 는 그들의 wiring 을 재진술하지 않고, 그들은 본 branch 정책을 재진술하지 않고 `[[...]] D<n>` 포인터로만 인용.
**4. OUT_OF_BRANCH_SCOPE (본 branch 로 끌어오지 않음)**
- secret scan(gitleaks) → secrets-config-source. container base image 선택 + image scan *wiring* → container-runtime. CI gate `needs:`/`if:` 배선 → ci-gates. SBOM/서명/version-locking → supply-chain. (본 branch 는 정책만 — 위 항목의 detail 을 §구현가이드에 남기지 않음.)
- **정정(2026-06-15 coverage 루프)**: `license/NOTICE scan` 은 OUT_OF_BRANCH_SCOPE 가 *아님* — governing §35-E L2052 가 본 branch 영역으로 명시했고 supply-chain 은 license 결정 0건이라 delegated owner 부재였음. → **D10 으로 본 branch 가 covered-here**.
## 엣지·실패·의존
> R4(깊이 게이트) 캡처용. 정상 경로 외에 *구현 중 부딪힐* 실패/엣지/다른 계약 의존을 미리 열거.
- **실패·엣지 경로**:
- **스캐너 DB 미가용/네트워크 차단** (CI 러너 air-gap, Trivy DB pull 실패) → 스캔이 silent pass 하면 안 됨. 기대: DB fetch 실패 = job fail (취약점 0 보고와 구분). Trivy `--exit-code` 와 별개로 DB 갱신 실패 fail-fast 검증 필요(Claims To Verify).
- **False positive 차단** (Gradle `force=true` 재정의, backport patch 미인식) → 잘못된 release block. 기대: D5 suppression 으로 만료일+사유 달고 우회, 영구 ignore 금지.
- **Transitive 취약점에 직접 fix 없음** → Renovate/Dependabot PR 생성 실패(직접 의존성만). 기대: Gradle constraint 수동 override (§구현가이드 §4), supply-chain D8 lock 재생성.
- **NVD enrichment 공백** (2026-04 정책 변경, 신규 CVE CVSS 미부여) → severity 미상으로 게이트 통과. 기대: GHSA fallback(D4) + KEV(D3) 가 점수 없는 악용 CVE 를 잡음.
- **Multi-module lockfile 미탐지** → 일부 subproject 스캔 누락(취약점 silent miss). 기대: `--file-patterns` + 각 subproject lockfile 커밋 검증.
- **`.trivyignore` 무단 추가로 긴급 우회** → 2026-05-25 audit finding. 기대: D5 정적 게이트가 무단 변경 차단.
- **dependency-review-action fail-open** (Gradle dependency graph 미제출 → 빈 diff = 0 취약점 pass) → PR 게이트가 거짓 통과. Trivy DB fail-open 과 동일 계열. 기대: graph 제출 검증 step(없으면 fail) + D1 Trivy fs 전체 스캔이 backstop(D7 단독 게이트 금지 이유).
- **다른 계약 의존 (cross-contract)**:
- **소비자 (본 branch 정책을 consume)**: [[raw/branch-notes/feature-ci-quality-gates-contract]] D5(gate wiring — vuln scan 의 release-blocking 배선), [[raw/branch-notes/feature-container-runtime-contract]] (image scan wiring, 동일 severity 정책 consume), [[raw/branch-notes/feature-build-release-supply-chain-contract]] D2(release-block 시점에 본 branch severity 표준 사용).
- **생산자 (본 branch 가 consume)**: [[raw/branch-notes/feature-build-release-supply-chain-contract]] **D8**(Gradle dependency-locking — Trivy `*gradle.lockfile` 스캔의 *선행조건*; lock 없으면 D1 스캔 불가) + **D5**(container base = Temurin JRE slim — image scan 대상). 이 계약이 바뀌면(예: lockfile 명명/위치 변경) 본 branch 의 `--file-patterns` 와 D1 스캔이 영향.
- **owner 정합 필요 (비차단 전파, §Audit)**: supply-chain D2/D3, ci-gates D5 의 `UNSUPPORTED`/`OWNER_AMBIGUITY` 스텁이 본 branch 를 정책 owner 로 가리키도록 갱신돼야 single-owner 완결.
## 검증해야 할 주장
> 공식 문서나 사례는 근거지만, 내 프로젝트에서의 동작을 자동으로 보장하지 않는다.
> 구현 전/중/후에 실제로 검증해야 하는 주장을 분리한다.
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| Trivy `--file-patterns "gradle-lockfile:*.lockfile"` 가 ca-tmpl 실제 lockfile 명명을 탐지 | 공식 문서 미명시 workaround(#9740); ca-tmpl lockfile 명명(`gradle.lockfile` vs `gradle/dependency-locks/*.lockfile`) 미확정 | ca-tmpl 에 `gradle dependencies --write-locks` 실행 → lockfile 생성 후 `trivy fs --file-patterns ...` 가 각 subproject 탐지하는지 verify | `needs-confirmation` |
| Java/Gradle 패키지에서 GHSA 점수가 NVD 점수를 override (D4 tie-break) | coverage 페이지는 OS 패키지만 vendor>NVD 우선 명시; 언어 패키지 override verbatim 미확보 | `trivy.dev/docs/latest/scanner/vulnerability/` 소스 우선순위 페이지 아카이브 + NVD/GHSA 점수 다른 known CVE 로 Trivy 출력 severity 확인 | `needs-confirmation` |
| Renovate `vulnerabilityAlerts` 가 schedule 을 무시하고 즉시 PR + `osvVulnerabilityAlerts` maven 커버 | presets 페이지에서 schedule-ignore·osv experimental·maven datasource 미확인(summarizer 폐기) | `configuration-options#vulnerabilityalerts`·`#osvvulnerabilityalerts` 아카이브 + 실제 repo 에 known-vuln dep 추가 → 즉시 PR 생성 verify | `needs-confirmation` |
| Dependabot Gradle security update 가 `libs.versions.toml`+lockfile 동시 사용 시 lockfile 갱신 (#12557) | about 페이지는 Gradle 지원을 링크로 위임; #12557 미해결(2025-07) | supported-ecosystems 페이지 + #12557 상태 확인; 테스트 repo 로 Dependabot security PR 이 lockfile drift 유발하는지 verify | `needs-confirmation` |
| Dependabot 은 dependabot.yml native auto-merge 없음 → Renovate 대비 복잡 | about 페이지에 `auto-merge` 키워드 0건(summarizer 확인) | `automating-dependabot-with-github-actions` 페이지 아카이브로 auto-merge 가 Actions workflow 필요함 확정 | `needs-confirmation` |
| KEV "exploited in the wild" 정의 + 비연방 권고 + BOD 26-04 4-factor | CISA HTML 403 으로 JSON feed 만 확보(정의·권고 미인용) | CISA 카탈로그 About + BOD 26-04 페이지 접근 가능 시 별도 raw 아카이브(`bod-26-04-...`) | `needs-confirmation` |
| dependency-review-action 이 Gradle 의존성 diff 를 보려면 dependency graph 제출 필요 | Gradle dependency graph 자동 추출 vs submission API 경로 불확실 | GitHub dependency graph 가 Gradle 프로젝트를 인식하는지 + `dependency-submission` action 필요 여부 확인 | `needs-confirmation` |
| 스캐너 DB fetch 실패가 silent pass 가 아니라 job fail | Trivy `--exit-code` 는 취약점 발견용; DB 갱신 실패 시 동작 미확정 | CI 에서 DB endpoint 차단 후 Trivy 실행 → exit code 검사; fail-fast 안 되면 `--exit-on-eol`/DB 검증 step 추가 | `planned` |
| scheduled 재스캔이 의존성 불변 상태에서 신규 CVE 를 실제로 잡음 | CVE DB 갱신만으로 새 매치가 생기는지 실증 필요 | known-clean dep 고정 후 일정 기간 뒤 재스캔 → 그 사이 공개된 CVE 가 잡히는지 verify | `planned` |
| `.trivyignore.yaml` 무단 변경 차단 정적 게이트가 우회 불가 (D5/audit 해소) | 게이트 구현(regex/CODEOWNERS) 미확정 | `.trivyignore.yaml` 에 만료일·사유 없는 row 추가 PR → CI fail + CODEOWNERS 승인 없이 merge 불가 verify | `planned` |
## 관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
> `/coverage` 가 채우는 **생성물** — 손으로 유지하지 않는다. governing 문서(frontmatter `governing_docs`)가 요구하는 관심사를 이 브랜치가 빠짐없이 덮는지의 결과. 기준: `rules/coverage-gate.md`.
> 상태: `covered-here`(이 브랜치 결정) / `delegated`(다른 owner 브랜치) / `missing`(아무도 안 맡음 → Blocking).
> 출처: `/coverage` (coverage-auditor, 2026-06-15, governing = `raw/project-notes/ca-skeleton-operational-contract` §18 + §35-E L2052). 1차 Not-covered(missing 1: license scan) → 본 루프에서 D10 추가로 covered-here 전환 → Covered.
| 관심사 | 상태 | owner | 심각도 | 근거 |
|--------|------|-------|--------|------|
| CVE scan 도구 선택(SCA 스캐너) | covered-here | — | — | D1 (Trivy) |
| severity별 release-block 기준(CVSS 임계값) | covered-here | — | — | D2 (CVSS v3.1 ≥High) |
| KEV override | covered-here | — | — | D3 |
| 소스 우선순위 tie-break(GHSA vs NVD) | covered-here | — | — | D4 |
| Suppression governance | covered-here | — | — | D5 |
| 의존성 보안 업데이트 자동화(Renovate/Dependabot) | covered-here | — | — | D6 |
| PR-time 보완 게이트(dependency-review-action) | covered-here | — | — | D7 |
| EPSS escalation(비차단) | covered-here | — | — | D8 (UNSUPPORTED, optional) |
| Remediation SLA by severity | covered-here | — | — | D9 (UNSUPPORTED, team-policy) |
| **license/NOTICE compliance scan** | covered-here | — | — | **D10** (Trivy license + dep-review allow/deny; governing §35-E L2052) |
| Transitive 취약점 처리 | covered-here | — | — | §구현가이드 §4 (D6 도출) |
| Scheduled re-scan(CVE DB 갱신) | covered-here | — | — | §구현가이드 §1 |
| CI gate wiring(blocking vs warning) | delegated | [[raw/branch-notes/feature-ci-quality-gates-contract]] | OK | Out of scope; ci-gates §Coverage L283 역참조 존재 |
| dependency version locking | delegated | [[raw/branch-notes/feature-build-release-supply-chain-contract]] | OK | supply-chain D8 |
| SBOM·서명(Cosign/SLSA)·versioning·rollback | delegated | [[raw/branch-notes/feature-build-release-supply-chain-contract]] | OK | supply-chain D4/D6/D7/D9/D11 |
| container image scan wiring + base image | delegated | [[raw/branch-notes/feature-container-runtime-contract]] | Should-fix | §Audit — container-runtime 에 image-scan Decision *부재*(dangling consumer link) → 신설 권고 |
| secret scan(gitleaks) | delegated | [[raw/branch-notes/feature-secrets-config-source-contract]] | OK | Out of scope |
## 마주친 문제
> 짧은 메모만. 깊이 있는 트러블슈팅은 `raw/errors/` 로 분리하고 아래 Cluster에 연결.
- 이슈 1
- 원인:
- 시도:
- 해결: (또는 미해결이면 `needs-confirmation`)
- 별도 에러 노트로 분리됨: `[[raw/errors/<...>]]` (생성 시)
## 묶음 (이 branch에서 파생된 자료)
<!-- GENERATED: sources:start -->
- [[raw/official-docs/dependabot-security-updates-gradle-official]]
- [[raw/official-docs/github-dependency-review-action]]
- [[raw/official-docs/renovate-vulnerability-alerts-gradle-official]]
- [[raw/official-docs/trivy-action-github-actions]]
- [[raw/official-docs/trivy-filtering-suppression-policy]]
- [[raw/official-docs/trivy-java-language-coverage]]
- [[raw/official-docs/vuln-severity-cisa-kev-catalog-official]]
- [[raw/official-docs/vuln-severity-cvss-v31-spec-first-official]]
<!-- GENERATED: sources:end -->
<!-- GENERATED: interviews:start -->
- [[raw/interviews/trivy-suppression-dual-control-governance-2026-06-20]]
<!-- GENERATED: interviews:end -->
<!-- GENERATED: errors:start -->
- [[raw/errors/gitea-act-action-tag-and-dependency-graph-2026-06-20]]
<!-- GENERATED: errors:end -->
<!-- GENERATED: blog-topics:start -->
- [[raw/blog-topics/gitea-act-dependency-security-gate-portability-2026-07-02]]
- [[raw/blog-topics/trivy-suppression-governance-static-gate-2026-06-20]]
<!-- GENERATED: blog-topics:end -->
> 이 branch는 단일 노트가 아니라 **작업 묶음의 entry point**. 이 branch에서 파생된 모든 raw 노트를 카테고리별로 명시. 자식 노트가 forward link만 박아도 Obsidian backlink로 자동 발견되지만, 읽기 흐름과 분류를 위해 hub가 명시적으로 그룹화한다.
### Sub-branches (세부 작업)
- 없음 — 단일 branch 로 구현. 세부 작업 분기 불필요.
### 오류 기록 (이 branch 작업 중 발생)
- [[raw/errors/gitea-act-action-tag-and-dependency-graph-2026-06-20]] — commit 후 Gitea/act 첫 실행에서 CI 2개 잡 실패: trivy-action 태그 오타(`@0.28.0``@v0.28.0`) + dependency-review 의 Gitea dependency-graph API 부재(server_url 가드). egress 가설을 로그로 반증한 evidence-first 사례.
- (구현 단계 자체는 blocking 오류 없음 — lockfile 부재로 Trivy fs 가 Gradle deps no-op 인 것은 오류가 아니라 문서화된 cross-contract 선행조건, supply-chain D8.)
### 면접 준비 (이 작업에서 나올 수 있는 면접 질문)
- [[raw/interviews/trivy-suppression-dual-control-governance-2026-06-20]] — suppression 영구 우회 구멍을 CODEOWNERS(merge-gate) + `verifyTrivyignore`(CI field-gate) 이중 통제로 막은 설계, Renovate vs Dependabot 선택 근거.
### 강의 (이 작업을 위해 학습한 강의)
- 없음 — 외부 강의 학습 없이 공식 문서(Trivy/CISA-KEV/FIRST/Renovate/GitHub) 근거로 구현.
### job-posting tie-ins (이 작업에서 파생된 글감)
- [[raw/blog-topics/trivy-suppression-governance-static-gate-2026-06-20]] — Gradle 정적 게이트로 supply-chain suppression 거버넌스(만료일·사유 강제) 강제하기 + audit finding 해소.
- derived blog: 생성 전. 생성 시 `wiki/blog/<slug>-YYYY-MM-DD.md` 후보
## 관련 일일 노트
> 이 브랜치를 작업한 날짜들. 양방향 nav 유지.
- `[[raw/daily-notes/YYYY-MM-DD]]`
- `[[raw/daily-notes/YYYY-MM-DD]]`
## 완료 후 정리
> 머지/종료 시점에 채움. `/ingest`가 이 섹션을 기준으로 wiki/projects/에 추출.
- PR 링크:
- 리뷰 메모:
- 머지 결과 / 배포 환경: (로컬/dev/staging/prod 어디까지 검증됐는지)
- **wiki 추출 대상** (verified만, `wiki/projects/`로만 추출):
- `actually-implemented` 항목:
- `locally-verified` 항목:
- `prod-verified` 항목:
- **추출하지 않을 항목** (planned / documented-only / abandoned):