Files
clean-architecture-backend-…/.github/dependency-vulnerability-policy.md
DongHyeonkaandClaude Opus 5 ef947e5bb0 refactor(build,ci): 현재 상태 검증을 걷어내고 불변조건만 남기는 검증 표면 축소
외부 리뷰("현재 상태를 유지하기 위한 검증이 너무 많고, 그 검증 자체를
다시 검증하는 구조까지 생겼다")를 설계 문서로 정리하고 코드로 반영한다.
설계·판단 근거는 docs/superpowers/specs/2026-09-16-verification-surface-reduction-design.md.

삭제
- .github/ci-gate-matrix.yml(1,025줄) + verify-gate-matrix.sh(568줄):
  Gradle task graph와 workflow graph에 이미 있는 정보의 3중 복제
- verify-gradle-wrapper.sh(799줄): workflow 바이트 해시 잠금.
  wrapper 검증은 gradle/actions/wrapper-validation(full SHA 핀)에 위임
- DeveloperExperienceContractTest 등의 CI YAML mutation 테스트:
  애플리케이션 test suite가 GitHub Actions YAML 파서를 검증하던 계층 역전
- 문서 drift 파서: verifyReadmeCommands, verifyRunbookReferences,
  verifyDocumentedLeafCount, verifyTestSourceSetRegistry
- 빈 레지스트리를 지키던 커스텀 YAML 파서: verifyTrivyignore,
  verifyQuarantineSunset, flaky-quarantine.yaml
- verifyConfigurationPropertiesProcessor, verifyOneTypePerFile:
  각각 ca.spring-config convention과 Checkstyle OneTopLevelClass가 대체
- 정상 입력으로도 성공할 수 없던 messaging always-fail task
- ModuleRegistry의 JSON 필드 집합 정확 일치, sample-portfolio negative guard

이동
- java/quality/spring 공통 설정을 configure(subprojects) 블록에서
  ca.java-conventions / ca.quality-conventions / ca.java-library /
  ca.spring-library convention plugin으로
- 아키텍처 검증을 ca.architecture로, JPA·messaging qualification을
  gradle/qualification/ 아래로, verifyEnvKeys를 :app-bootstrap 소유로

완화
- Git revision은 releaseCheck·아카이브 생성에서만 요구. 일반 빌드는 SNAPSHOT
- SpotBugs/FindSecBugs는 로컬 check에서 빼고 qualityCheck 레인으로

task 계층
- leaf check는 그 leaf만. architectureCheck / qualityCheck /
  configContractCheck / integrationCheck / ci / releaseCheck로 이름 분리

CI
- _reusable-gradle.yml 신규. checkout + wrapper validation + JDK/캐시 공통화
- fileserver-release.yml -> fileserver-certification.yml (CD가 아니라 certification)
- GitHub Actions = CI + artifact, Argo CD = CD 경계를 docs/ci-cd/boundary.md로 고정

순증감 +3,274 / -7,483.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 20:33:19 +09:00

93 lines
5.0 KiB
Markdown

# Dependency Vulnerability Policy
This policy is enforced by
[`dependency-vulnerability.yml`](workflows/dependency-vulnerability.yml),
[`dependency-review-config.yml`](dependency-review-config.yml),
[`../.trivyignore.yaml`](../.trivyignore.yaml), CODEOWNERS, and
[`../renovate.json`](../renovate.json).
## Execution and platform boundary
Canonical workflow files live under `.github/workflows`. The current origin is Gitea and
server-side Actions is externally disabled; committing these controls does not enable or prove
remote execution. An administrator must enable Actions, provide compatible runners, configure
required checks, and require code-owner review separately.
External actions execute only by verified full commit SHA; inline comments retain the immutable
release tag for review. GitHub dependency review publishes check output but never writes a PR
summary comment, preserving the workflow-wide `contents: read` permission.
GitHub dependency review and dependency submission depend on GitHub.com APIs. They are guarded by
`github.server_url == 'https://github.com'` and intentionally skip on Gitea. `trivy-fs` is the
platform-neutral release-blocking snapshot and runs for pull requests, `main` pushes, daily
schedule, and manual dispatch.
The later supply-chain slice owns image builds/scans, SBOM, signing, provenance, tag release, and
retention. This policy does not claim those absent jobs.
## Severity and response
| Severity | CI posture | Target remediation |
| --- | --- | --- |
| KEV / Critical | block | 7 days or the CISA due date, whichever is sooner |
| High | block | 30 days |
| Medium | advisory | 90 days |
| Low | advisory | best effort |
High/Critical is the template's release threshold. The exact threshold and remediation targets are
team policy rather than an external mandate and should be reviewed when the template is adopted.
GitHub dependency review applies the same High threshold to newly introduced runtime dependencies.
The Trivy JSON snapshot is also compared with the CISA Known Exploited Vulnerabilities catalog.
Any intersection blocks regardless of Trivy severity. Before intersection, CI requires nonblank
catalog metadata, a positive integral declared count, a non-empty vulnerability array whose length
matches that count, and unique CVE-pattern `cveID` values. A missing, empty, malformed,
count-inconsistent, duplicate, or unreachable KEV feed fails closed; configure the `KEV_FEED_URL`
repository variable to an approved internal mirror when direct CISA access is unavailable.
Candidate extraction also validates Trivy's JSON first: the top level must be an object with a
non-empty `Results` array; each result is an object whose `Vulnerabilities` value is null or an
array; and every listed vulnerability has a nonblank string `VulnerabilityID`. Invalid scanner
output fails closed instead of becoming an empty candidate set.
## Scanner and network requirements
Trivy scans the committed filesystem and Gradle lockfiles. High/Critical findings exit non-zero;
Medium/Low findings are reported with exit zero. Scanner database or tool-download failures remain
failures rather than silently producing an empty result.
Runners need HTTPS egress to:
- the configured Trivy binary source (GitHub Releases by default);
- Trivy vulnerability databases (the scanner defaults, commonly OCI registries);
- jq releases, unless `JQ_DOWNLOAD_BASE_URL` points to an internal mirror;
- the CISA KEV feed, unless `KEV_FEED_URL` points to an internal mirror;
- GitHub action sources when the forge does not mirror actions.
Closed networks must mirror the pinned Trivy/jq artifacts and checksums, set
`TRIVY_DOWNLOAD_BASE_URL` and `JQ_DOWNLOAD_BASE_URL`, configure Trivy's documented database mirror
environment, and set `KEV_FEED_URL`. Mirror availability and freshness are operational
dependencies; stale mirrors can delay detection.
## Suppression governance
The only suppression source is repository-root `.trivyignore.yaml`. Every Trivy scan passes it
explicitly with `--ignorefile .trivyignore.yaml`. Each future entry must contain an identifier, a
non-empty rationale, and a future expiry no more than 90 days away. A CODEOWNERS reviewer validates
the shape and expiry; CODEOWNERS plus branch protection controls who may approve the change.
Neither control substitutes for the other.
Do not use an ad-hoc ignore file or an inline scanner bypass. An expired suppression is removed or
renewed with fresh owner review and current evidence.
## Dependency update policy
Renovate is the checked-in security-update bot configuration. Patch/pin/digest security updates
may auto-merge only after every configured required check succeeds; minor and major updates require
human review. Dependency declarations and all 19 `gradle.lockfile` files must move together, and
`verifyDependencyLocks` remains release-blocking.
Bot alerts are not a transitive-dependency backstop on every forge. Use a Gradle constraint or
resolution rule for a vulnerable transitive dependency, refresh locks deliberately, and retain the
full-snapshot Trivy scan.