외부 리뷰("현재 상태를 유지하기 위한 검증이 너무 많고, 그 검증 자체를
다시 검증하는 구조까지 생겼다")를 설계 문서로 정리하고 코드로 반영한다.
설계·판단 근거는 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>
93 lines
5.0 KiB
Markdown
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.
|