Files
llm-wiki/raw/branch-notes/feature-build-release-supply-chain-contract.md

75 KiB
Raw Permalink Blame History

title, source_type, status, branch, parent_branch, related_projects, governing_docs, tags, created, updated, target_merge, status_label, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, contract_packet_sha256
title source_type status branch parent_branch related_projects governing_docs tags created updated target_merge status_label id kind project work_item inherits refines overrides depends_on contract_packet contract_packet_sha256
branch / feature-build-release-supply-chain-contract branch-note raw feature-build-release-supply-chain-contract
ca-skeleton
wiki/projects/ca-tmpl/devops-ci-supply-chain-dx
branch
ca-skeleton
ci-cd
gradle
docker
supply-chain
2026-05-22 2026-06-23 review BR-CA-SKELETON-OPERATIONAL-CONTRACT-029 project-work-item ca-skeleton-operational-contract WI-CA-SKELETON-OPERATIONAL-CONTRACT-029
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-STACK-BUILD-001@1
1 2307d3faa4febc43cbbe5f18fae9ae683e96a7b2b9f0fbe86065acf1a767a65b

branch: feature-build-release-supply-chain-contract

Layer: raw/branch-notes/ — artifact, dependency, image, vulnerability, rollback 기준을 정의합니다.

부모 (필수)

ca-skeleton 은 별도 root branch 없이 project-note 가 SSOT 역할. 본 feature branch 는 project-note 의 운영 계약 중 해당 영역 (§<관련 섹션>) 의 결정/근거/금지 사항을 정제한다.

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: Gradle release·SBOM·signature artifact가 생성된다

상속한 프로젝트 결정

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

브랜치 지역 결정

기존 branch-local 결정은 아래 ## Decision Evidence Map / 결정-근거 매핑의 D-row가 소유하며 이 packet에서 복제하지 않는다.

Decision ID Decision Relation Supporting Claims Status

선언한 예외

Override ID Overrides Reason Approval Status

목표

운영 가능한 skeleton은 실행되는 코드만이 아니라 배포 가능한 artifact를 안정적으로 만들어야 합니다. dependency drift, 취약 이미지, rollback 불가 artifact는 도메인과 무관하게 실무 장애가 됩니다.

  • 이슈:
  • PR:

범위

포함 범위

  • dependency version locking.
  • artifact versioning.
  • container image base 기준.
  • non-root runtime 기준.
  • SBOM 생성 기준.
  • vulnerability severity별 release block 기준.
  • rollback 기준.

제외 범위

  • 특정 registry 운영.
  • 조직별 release approval workflow.
  • cloud provider 배포 스크립트.

근거 (필수, 최소 1개+)

본 branch의 결정 근거. 상세 비교는 §외부 근거 / 대안 조사 (있다면) 참조.

Source 정당화하는 결정
raw/official-docs/supply-chain-cosign-keyless-sigstore Sigstore Cosign keyless + Fulcio + Rekor (ca-tmpl baseline
raw/official-docs/supply-chain-slsa-provenance-framework SLSA v1
raw/official-docs/supply-chain-gradle-vs-maven-dependency-locking Gradle dependency-locking vs Maven Enforcer
raw/official-docs/cosign-keyless-identity-verification-policy 참조
raw/official-docs/slsa-v1-provenance-schema 참조
raw/official-docs/vuln-severity-cvss-v31-spec-first-official D2 — high/critical release-blocking 기준: CVSS v3.1 §5 severity bands (C1), optional 선언 (C2), Base Score intrinsic/worst-case 정의 (C3)
raw/official-docs/semver-2-0-0-spec-semver-official D9 — artifact version = SemVer + git sha suffix (1.2.3+a1b2c3d): build metadata(+ suffix)는 precedence에서 무시됨 (SEMVER-C3, SEMVER-C4)
raw/official-docs/trivy-severity-exit-code-gating D2 — severity→release-block 정책의 집행(enforcement) 메커니즘: Trivy --exit-code 1 --severity HIGH,CRITICAL 기본 패턴의 공식 출처 (TRIVY-EG-C1~C3)
raw/official-docs/renovate-gradle-manager-official D3 — Renovate Gradle 지원 범위(파일 패턴, --write-locks lockfile 갱신, Version Catalog), self-hosted allowedUnsafeExecutions: ["gradleWrapper"] supply-chain 보안 제약 (RENOV-GRAD-C1~C4)
raw/official-docs/gradle-reproducible-archives-working-with-files D10 — preserveFileTimestamps=false / reproducibleFileOrder=true 의 Gradle 공식 API 명세 + tasks.withType<AbstractArchiveTask>().configureEach {} 전역 적용 패턴 (GRADLE-RA-C1~C3)
raw/official-docs/dependabot-supported-ecosystems-official D3 — Dependabot Gradle ecosystem 공식 지원 범위: version updates ✓ / security updates ✓(단 dependency submission API 수동 업로드 한정) / Private registries ✓ / Vendoring ✗; 파일 파싱 방식(Gradle 미실행) 공식 확인 (DBOT-ECO-C1~C5)
raw/official-docs/calver-spec-calver-official D9 negative-evidence — CalVer when-to-use 기준(대규모/상시변동 scope, 시간민감)이 library/skeleton에 미해당함을 원문 부재로 뒷받침 (CALVER-C2, C3, C5)
raw/official-docs/reproducible-builds-org-jvm-guide D10 — reproducible builds 공식 정의(cross-ecosystem) + JVM nondeterminism 원인(timestamps/file ordering/locale/umask) + Gradle isPreserveFileTimestamps=false + isReproducibleFileOrder=true 두 설정이 두 주요 원인 제거 근거 (RB-JVM-C1~C6)

외부 근거 / 대안 조사 (2026-05-22 — Group G-E: Build / Release / Supply Chain)

본 branch의 Cosign keyless + SLSA provenance + Gradle dependency-locking + SemVer+sha + reproducibility 결정에 대한 외부 source.

  • 채택 결정 (Cosign keyless + SLSA + Gradle lock):
  • 검토한 대안:
    • 대안 1: GPG signing (legacy) — Cosign 이전 표준
    • 대안 2: Notary v1 (Docker Content Trust) — Cosign으로 대체된 deprecated 경로
    • 대안 3: in-toto attestations — SLSA에 통합되어 별도 도구로는 미채택
    • 대안 4: JFrog Artifactory provenance — vendor 통합 솔루션
  • 비교 핵심: Cosign keyless가 GPG signing 대비 키 관리 부담 제거(Fulcio가 ephemeral cert 발급, Rekor가 transparency log). SLSA Build L3 도달은 hermetic build 필요. Maven에는 1급 lockfile 부재(Enforcer는 부분 대응) — Gradle 선택 근거. 보강 후보: Cosign signature 누락만 차단으로 부족 — --certificate-identity + --certificate-oidc-issuer identity 매칭 정책 추가 필요. SLSA v1.0 spec 실제 필드명(buildDefinition.externalParameters 등)과 ca-tmpl 약식 매핑 정정 필요.
  • 후속 보강 (2026-05-22): Cosign signature 존재 검증만으로는 불충분. identity 매칭 정책 추가 필요. raw/official-docs/cosign-keyless-identity-verification-policy 참조.
  • 후속 보강 (2026-05-22): SLSA v1.0 spec 실제 필드명과 약식 매핑 정정 필요. raw/official-docs/slsa-v1-provenance-schema 참조.
  • 자동조사 라운드 (2026-06-15 — /branch-spec): UNSUPPORTED 였던 D2(vuln severity)·D3(dependency bot)·D9(SemVer)·D10(reproducibility) 에 공식 source 8건 아카이브. D9·D10 은 본 branch 소유 영역(artifact versioning·reproducibility) → official-standard/vendor-doc 로 승급. D2·D3 은 정책 single-ownerraw/branch-notes/feature-dependency-vulnerability-management-contract 이므로 본 branch 는 consume 관계 — §Audit & Findings OWNER_RECONCILE 참조.

TODO

TODO drained 2026-05-22 — dependency lock/update, artifact version naming, container base/non-root runtime, SBOM 생성, vulnerability severity 차단, rollback artifact 보관 정책 모두 "결정 사항" / "Supply Chain Defaults" / "테스트 계약"에 반영됨. 잔존 TODO 없음.

진행 중 메모

  • 2026-06-15 /branch-spec 자동조사: 근거 없던 결정 5개(D2/D3/D9/D10/D11) 중 D2/D3/D9/D10 을 공식 source 로 보강(§Sources 하단 8행). D11(rollback 10/90 retention)은 외부 표준 부재 → UNSUPPORTED_DECISION 유지.
  • D2/D3 은 evidence 가 붙었으나 정책 owner 는 별도 branch — 자동 rewrite 하지 않고 §Audit & Findings 에 정합 권고로만 기록(사용자 결정 영역). /sync 가 Single-Owner 정합 수행 예정.
  • 2026-06-20~21 Phase C2 구현 완료. Gradle strict lock, 재현 가능한 archive, traceable version, digest-first image release, SBOM, Cosign keyless, SLSA provenance, High/Critical 차단, rollback retention audit를 코드와 계약 테스트로 배선했다.
  • GitHub-hosted OIDC/Rekor/GHCR와 실제 release 생성은 로컬에서 재현할 수 없어 needs-confirmation; 구현·로컬 검증과 운영 검증 경계를 아래 §구현 결과에 분리했다.

구현 결과

아래 §구현 가이드의 2026-06-15 planned 표시는 구현 전 설계 스냅샷이다. 현재 상태 SSOT는 이 절이며, 실제 코드·테스트가 존재하는 항목만 actually-implemented 또는 locally-verified로 분류한다.

Decision 구현 상태 구현 증거 검증 등급
D1 · D9 src/build.gradle, src/Dockerfile, release manifest에 <SemVer>+<12-char sha>와 source revision 고정 JAR manifest와 OCI label inspect locally-verified
D4 · D6 · D12 digest 대상 Cosign keyless image signature와 SPDX SBOM attestation 생성, exact workflow identity + GitHub issuer 검증 .github/workflows/build-release-supply-chain.yml, .github/supply-chain-policy.json actually-implemented; live OIDC/Rekor는 needs-confirmation
D7 · D13 official SLSA generator provenance와 exact @refs/tags/v2.1.0 builder ID, v1 predicate field 검증 release workflow provenance/verify jobs actually-implemented; live attestation은 needs-confirmation
D8 모든 Gradle project에 LockMode.STRICT, 기본 gradle.lockfile, lock 생성/검증 task 적용 10개 module lockfile, positive/negative strict-lock 실행 locally-verified
D10 archive timestamp/order/mode 정규화, Temurin 21.0.11+10 pin, Docker base digest pin 두 clean build의 JAR SHA-256 일치, zip metadata, Docker build/inspect locally-verified
D2 consume Trivy image scan HIGH,CRITICAL --exit-code 1을 promotion 전 배치 release workflow build job actually-implemented; live scan은 needs-confirmation
D3 consume Renovate-compatible Gradle 기본 lockfile 경로와 갱신 절차 명시 renovate.json, PR template, README actually-implemented; Renovate dry-run은 needs-confirmation
D5 consume digest-pinned Temurin JRE runtime + USER app Docker build 및 image config inspect locally-verified
D11 최근 10개 OR 90일 이내 release의 manifest/SBOM/GHCR digest 일치 daily audit retention workflow/script/positive-negative behavior tests locally-verified (fixture); live registry/release는 needs-confirmation
D14 jq 1.8.1을 job-local 경로에 checksum 검증 후 설치하고 모든 jq 소비 job이 같은 installer를 호출 installer behavior test, workflow YAML parse, 6개 job-level 정적 계약 locally-verified; Gitea/act CI 재실행은 needs-confirmation

변경 파일

  • Build: src/build.gradle, .tool-versions, src/*/gradle.lockfile, src/Dockerfile, docker-compose.local.yml.
  • Release policy/workflows: .github/supply-chain-policy.json, .github/workflows/build-release-supply-chain.yml, .github/workflows/supply-chain-retention-audit.yml.
  • Contract/scripts: .github/scripts/verify-supply-chain-contract.sh, create-release-manifest.sh, verify-reproducible-build.sh, audit-rollback-retention.sh, test-supply-chain-scripts.sh.
  • Gate/docs: .github/ci-gate-matrix.yml, .github/workflows/ci-quality-gates.yml, .github/pull_request_template.md, README.md, src/README.md.
  • 2026-06-23 CI portability repair: .github/scripts/install-jq.sh, .github/scripts/verify-supply-chain-contract.sh, .github/workflows/{ci-quality-gates,build-release-supply-chain,supply-chain-retention-audit,dependency-vulnerability}.yml.
  • 2026-06-23 Bean conflict & cycle resolution & test repair: src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/CaSkeletonApplication.java에서 컴포넌트 스캔 범위를 프로덕션 패키지로 명시화하여 sample-portfoliodomainContextPropagator 빈과의 BeanDefinitionOverrideException 충돌을 해결. src/adapter-persistence-postgresql/src/main/java/dev/caskeleton/adapter/persistence/postgresql/PostgreSqlPersistenceConfig.java에서 postgreSqlFlywayLocationCustomizer() 빈을 static @Bean으로 변경하여 Flyway ↔ EntityManagerFactory 간 초기화 순환 참조 제거. 또한 PiiTokenBodyForbiddenContractTest.java에서 공유 JVM 테스트 환경에 따른 로깅 레벨 오염으로 로그 미캡쳐 현상이 나타나던 것을 테스트 실행 중 로깅 레벨을 INFO로 보장하는 코드로 격리. OutboxEventEntity.java에서 @Lob 대신 @JdbcTypeCode(SqlTypes.LONGVARCHAR)를 사용하여 PostgreSQL oid 캐스팅 경고/오류 및 DDL 불일치를 해결. sample-portfolio 모듈의 application.yml에서 기본 데이터소스 폴백 정보 수정 및 out-of-order: true 활성화로 단독 실행 기동 문제 해결. 추가로 app-bootstrap 모듈의 런타임 기동 마이그레이션(Flyway)을 웹 서버 기동 시 함께 실행할지(In-App) 혹은 별도 원샷 컨테이너/Job으로 격리할지 선택할 수 있도록 ca-skeleton.runtime.migration-on-startup (환경 변수: APP_MIGRATION_ON_STARTUP, 기본값 true) 설정을 도입하고 MigrationStartupRunner, RuntimeSafetySettings, docs/registries/env-keys.yaml을 연동 갱신하여 런타임 운영 유연성을 확보하고 MigrationStartupRunnerTest에 우회(bypass) 검증 시나리오를 추가하여 빌드 검증을 완료함.
  • 2026-06-23 Local environment configuration alignment: docker-compose.local.yml에서 애플리케이션의 등록된 환경 변수(APP_DATASOURCE_*)와 일치하도록 명칭을 수정(기존 SPRING_DATASOURCE_* 제거)하고, 템플릿의 로컬 개발 DB 기본 자격 증명(ca_skeleton)이 fallback 디폴트로 자동 바인딩되도록 개선하여 별도 환경변수 입력이나 보간 오류 없이 로컬 스택이 구동 가능하도록 정합성을 확보함.

검증 증거

  • cd src && ./gradlew resolveAndLockAll --write-locks --no-daemon → 성공, 10개 module lockfile 생성.
  • cd src && ./gradlew check verifyPublicPathSnapshot --no-daemon → 최종 변경 후 성공, 108 tasks(89 executed / 19 up-to-date), public path snapshot unchanged.
  • cd src && ./gradlew verifyDependencyLocks ... → 정상 lock 성공. 격리 사본에서 transitive spring-core entry 제거 후 동일 task → 기대한 non-zero와 not part of the dependency lock state 확인.
  • bash .github/scripts/verify-reproducible-build.sh → 성공, 두 clean build 모두 af5e00540adad76313d778680d2ef20dca241671e08107c0144d3961d721f77d.
  • docker build ... -t ca-tmpl:supply-chain-test src → 최종 strict-lock preflight 포함 성공. USER=app, OCI version/revision/source label 확인.
  • bash -n .github/scripts/*.sh, 공급망 정적 계약, behavior test, gate matrix 검사, yq workflow parse, jq policy parse, git diff --check → 성공.
  • Actionlint pinned container는 2026-06-20 실행에 성공했으나, 2026-06-21 최종 재실행은 private workspace 내용을 third-party image에 노출하는 정책으로 거부됐다. 저장소 mount와 stdin 전달 모두 중단하고 yq + 정적 계약으로 대체했다. 상세: raw/errors/sandbox-build-verification-boundaries-2026-06-21.
  • 2026-06-23 verify-supply-chain-contract.sh RED → installer/6개 job 배선/inline download 금지 15건 실패 확인 후 GREEN. install-jq.sh가 jq 1.8.1 AMD64 공식 asset을 내려받아 SHA-256 검증 후 실행했고, 설치된 바이너리로 test-supply-chain-scripts.sh 양/음수 경로가 성공했다.
  • ./gradlew verifyCleanArchitectureDependencies, :app-bootstrap:test --tests '*CleanArchitectureTest', test, check verifyPublicPathSnapshot 모두 성공. 최종 check는 108 tasks(7 executed / 101 up-to-date), public path snapshot unchanged.
  • 실패 로그와 동일한 node:20-bullseye container 재검증은 private workspace mount 위험으로 실행 승인이 거부되어 중단했다. 실제 Gitea/act 재실행은 needs-confirmation. 상세: raw/errors/gitea-act-missing-jq-job-bootstrap-2026-06-23.
  • 2026-06-23 컴포넌트 스캔 제한, 순환 참조 해결, 로깅 레벨 복구 적용 상태에서 전체 빌드/테스트 및 로컬 기동 검증: cd src && ./gradlew test 빌드가 성공(BUILD SUCCESSFUL)함을 확인하고, 로컬 PostgreSQL 컨테이너(ca-pg)를 기동하여 ./gradlew :app-bootstrap:bootRun을 실행함으로써 Flyway 마이그레이션 적용 및 Started CaSkeletonApplication 기동 성공을 로그로 검증함.

결정 사항

  • 2026-05-22: release 가능한 artifact는 source revision과 version을 추적 가능해야 함.
  • 2026-05-22: high/critical vulnerability는 기본 release-blocking으로 둠.
  • 2026-05-22: dependency upgrade bot은 Renovate 기본, Dependabot은 조직 표준일 때 허용.
  • 2026-05-22: SBOM만으로는 충분하지 않음. image digest는 필수, Cosign signature와 SLSA provenance는 release-blocking 의무. signature 없이 deploy는 forbidden.
  • 2026-05-22: container base image default는 container-runtime branch의 Temurin JRE slim 결정을 소비.
  • 2026-05-22: Cosign keyless signing (sigstore Fulcio) 의무화. release artifact에 signature 누락 시 deploy block.
  • 2026-05-22: SLSA provenance attestation 의무화 (build.config.source, build.invocation, materials 포함). build provenance 검증 실패 시 deploy block.
  • 2026-05-22: dependency lock = Gradle dependency-locking 강제 (gradle/locks/*.lockfile). lock drift 시 build fail.
  • 2026-05-22: artifact version = SemVer + git sha suffix (예: 1.2.3+a1b2c3d). CalVer은 forbidden.
  • 2026-05-22: build reproducibility = archives.preserveFileTimestamps=false, archives.reproducibleFileOrder=true, JDK version pin via .tool-versions 또는 gradle/wrapper/. timestamp/locale entropy 제거.
  • 2026-05-22: rollback artifact 보관 = 최근 10개 release + 90일 (whichever longer).
  • 2026-05-22: Cosign verify는 --certificate-identity=<expected> + --certificate-oidc-issuer=<expected> 필수. signature 존재만 검증하면 fail.
  • 2026-05-22: provenance 생성 시 SLSA v1.0 공식 필드명(buildDefinition.externalParameters, runDetails.builder.id 등) 사용. 약식 명명 forbidden.
  • 2026-06-23: 각 CI job은 격리된 실행 환경이므로 jq 소비 job마다 공통 installer를 호출한다. installer는 jq 1.8.1과 AMD64/ARM64 checksum을 고정하고 RUNNER_TEMP/GITHUB_PATH만 사용한다. apt 설치·workflow별 curl 복제·runner image 사전 설치는 각각 root/배포판 결합, 정책 중복, 숨은 runner 결합 때문에 채택하지 않았다. 근거 raw claim 부재로 D14는 UNSUPPORTED_DECISION이다.

Work Item Contract

각 TODO는 아래 판정 단위로 재작성되어야 canonical 승급 가능합니다. TODO가 단순히 기준 작성으로 남아 있으면 이 branch는 완료로 보지 않습니다.

field required rule
Decision yes 구현자가 선택해야 하는 기본값
Allowed yes 허용되는 예외와 조건
Forbidden yes 절대 금지되는 구현/문서 상태
Required registry update conditional error/env/header/log/metric/capability 변경 시 필수
Required contract test yes 계약 위반 시 실패해야 하는 테스트
Failure condition yes review/build에서 실패로 판정할 상태
Canonical extraction target yes wiki/projects 승급 위치

Supply Chain Defaults

item default failure condition
dependency bot Renovate no upgrade policy
SBOM generated per release release without SBOM
image identity immutable digest tag-only promotion
signature Cosign release-blocking 의무. signature 없이 deploy는 forbidden. no signed artifact plan
provenance SLSA provenance release-blocking 의무. signature 없이 deploy는 forbidden. source revision not traceable
vuln block high/critical block critical vuln warning-only

결정-근거 매핑

각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. Decision ID 는 이 branch-note 안에서 안정적으로 유지.

Decision ID Decision Supporting Claims Evidence Strength Open Risk
D1 release 가능한 artifact 는 source revision 과 version 을 추적 가능해야 함 raw/official-docs/supply-chain-slsa-provenance-framework.md#SLSA-FW-C4 (provenance = where/when/how verifiable info), raw/official-docs/supply-chain-slsa-provenance-framework.md#SLSA-FW-C5 (builder.id + resolvedDependencies) official-standard (SLSA v1.0) provenance 존재만으로 forge 방지 보장 안 됨 (SLSA-FW-C1 L1 한계)
D2 high/critical vulnerability 는 기본 release-blocking raw/official-docs/vuln-severity-cvss-v31-spec-first-official.md#C1 (CVSS v3.1 §5 severity bands: High 7.08.9 / Critical 9.010.0), #C2 (qualitative ratings are optional — 조직이 이를 정책으로 강제 가능), #C3 (Base Score = intrinsic/worst-case, Temporal/Environmental 보완적); 집행 메커니즘 raw/official-docs/trivy-severity-exit-code-gating.md#TRIVY-EG-C2 official-standard (FIRST.org CVSS v3.1) — 단 정책 owner 는 raw/branch-notes/feature-dependency-vulnerability-management-contract; 본 branch 는 consume severity 정책의 single owner = vuln-management branch (§Audit OWNER_RECONCILE). severity 임계값(≥7.0 / ≥9.0)이 "최적"이라는 것은 명세가 증명하지 않음 — 조직 정책 선택
D3 dependency upgrade bot = Renovate 기본, Dependabot 은 조직 표준일 때 허용 raw/official-docs/renovate-gradle-manager-official.md#RENOV-GRAD-C1 (Gradle 파일 패턴 공식 지원), #RENOV-GRAD-C2 (lockfile 유지 via --write-locks), #RENOV-GRAD-C3 (self-hosted allowedUnsafeExecutions: ["gradleWrapper"] 필수); raw/official-docs/dependabot-supported-ecosystems-official.md#DBOT-ECO-C1~C5 (Dependabot Gradle 지원 범위) official-vendor-doc (Renovate + GitHub Dependabot) — 단 update-automation 정책 owner 는 raw/branch-notes/feature-dependency-vulnerability-management-contract; 본 branch 는 consume "Renovate 기본 vs Dependabot 조건부" 우선순위 결정 자체는 owner branch 소유. lockfile 경로 정합 필요 (§Audit LOCKFILE_PATH_DRIFT)
D4 SBOM + image digest 필수, Cosign signature + SLSA provenance release-blocking, signature 없이 deploy 는 forbidden raw/official-docs/supply-chain-cosign-keyless-sigstore.md#COSIGN-C1, raw/official-docs/supply-chain-cosign-keyless-sigstore.md#COSIGN-C4, raw/official-docs/supply-chain-slsa-provenance-framework.md#SLSA-FW-C4 official-vendor-doc (Cosign) + official-standard (SLSA) "signature 누락 시 deploy block" 의 admission controller 구현 (Kyverno/OPA Gatekeeper/sigstore-policy-controller) 별도 — 본 branch 범위 밖(§엣지·실패·의존)
D5 container base image default 는 container-runtime branch 의 Temurin JRE slim 결정 소비 (cross-branch reference) raw/official-docs/container-distroless-google-github.md#CDG-C1, raw/official-docs/container-alpine-java-musl-tradeoffs.md#CAJM-C4 (대안 trade-off — container-runtime branch 가 SSOT) cross-branch-reference raw/branch-notes/feature-container-runtime-contract D3 (base image = Temurin JRE slim) 와 동기화 (§Audit D5_CROSSREF_PRECISION)
D6 Cosign keyless signing (sigstore Fulcio) 의무화, signature 누락 시 deploy block raw/official-docs/supply-chain-cosign-keyless-sigstore.md#COSIGN-C1 (keyless = identity 결합), raw/official-docs/supply-chain-cosign-keyless-sigstore.md#COSIGN-C2 (Fulcio OIDC 검증 + cert 발급), raw/official-docs/supply-chain-cosign-keyless-sigstore.md#COSIGN-C3 (10분 short-lived cert) official-vendor-doc GPG 대비 운영 부담 감소 직접 진술 (COSIGN-C7) 은 needs-confirmation — verbatim 미확보
D7 SLSA provenance attestation 의무화 (build.config.source, build.invocation, materials), 검증 실패 시 deploy block raw/official-docs/supply-chain-slsa-provenance-framework.md#SLSA-FW-C4, raw/official-docs/supply-chain-slsa-provenance-framework.md#SLSA-FW-C5, raw/official-docs/supply-chain-slsa-provenance-framework.md#SLSA-FW-C6 (in-toto Statement) official-standard (SLSA v1.0 + in-toto) ca-tmpl 약식 필드명은 spec 실제 필드명과 불일치 — SLSA-SCH-* claim 으로 보강 (D13 참조)
D8 dependency lock = Gradle dependency-locking (gradle/locks/*.lockfile), lock drift 시 build fail raw/official-docs/supply-chain-gradle-vs-maven-dependency-locking.md#SC-DL-C1~SC-DL-C9 (Gradle dependency-locking vs Maven Enforcer 비교) official-vendor-doc Maven Enforcer 의 1급 lockfile 부재는 SC-DL claim 으로 직접 지지. 선언 경로 gradle/locks/*.lockfile vs Renovate 인식 기본 경로 drift (§Audit LOCKFILE_PATH_DRIFT)
D9 artifact version = SemVer + git sha suffix (1.2.3+a1b2c3d), CalVer forbidden raw/official-docs/semver-2-0-0-spec-semver-official.md#SEMVER-C3 (build metadata + suffix는 precedence에서 무시됨), #SEMVER-C4 (Build metadata does not figure into precedence), #SEMVER-C5 (1.2.3+sha vs 1.2.3-sha 의미 구분), #SEMVER-C1 (MAJOR.MINOR.PATCH 증가 의미론); negative-evidence raw/official-docs/calver-spec-calver-official.md#CALVER-C2/C3/C5 official-standard (SemVer 2.0.0 spec) CalVer forbidden 은 spec 이 직접 금지하는 것이 아님 — 팀 컨벤션; 일부 레지스트리/도구가 + 문자를 tag 에 허용하지 않을 수 있음 (도구 호환성 별도 검증 필요)
D10 build reproducibility = preserveFileTimestamps=false, reproducibleFileOrder=true, JDK pin raw/official-docs/gradle-reproducible-archives-working-with-files.md#GRADLE-RA-C1 (preserveFileTimestamps=false → 기계/JVM/OS 간 타임스탬프 통일), #GRADLE-RA-C2 (reproducibleFileOrder=true → 파일시스템 순서 독립 → byte-for-byte 재현 기여), #GRADLE-RA-C3 (tasks.withType().configureEach {} 전역 적용 패턴); 보조: raw/official-docs/reproducible-builds-org-jvm-guide.md#RB-JVM-C1~RB-JVM-C6 (cross-ecosystem 정의 + JVM nondeterminism 원인 목록) official-vendor-doc (Gradle DSL reference) + official-reference (reproducible-builds.org) JDK pin (.tool-versions/Gradle Toolchains) 은 본 raw source 범위 밖 — UNSUPPORTED_IMPL(§구현 가이드). 두 property 조합만으로 완전한 reproducibility 보장 아님 (C2: "helps")
D11 rollback artifact 보관 = 최근 10개 release + 90일 (whichever longer) UNSUPPORTED_DECISION (외부 source 없음 — 조직 retention 정책; 2026-06-15 자동조사에서도 10/90 정량값을 정의하는 외부 표준 미발견) team-policy 10/90 정량값 외부 표준 부재 — owner=조직 release 정책. trade-off: 보수적 보관(스토리지 비용 ↔ rollback 가용성). 재평가 트리거: 스토리지 비용 임계 초과 또는 rollback 빈도 변화. 자동 강제 = Claims To Verify(registry retention IaC)
D12 Cosign verify 는 --certificate-identity + --certificate-oidc-issuer 필수, signature 존재만 검증하면 fail raw/official-docs/cosign-keyless-identity-verification-policy.md#CSIGN-KL-C1~CSIGN-KL-C4 (identity 매칭 정책) official-vendor-doc admission controller 통합 시 policy DSL 별도
D13 provenance 생성 시 SLSA v1.0 공식 필드명 사용 (buildDefinition.externalParameters, runDetails.builder.id 등), 약식 명명 forbidden raw/official-docs/slsa-v1-provenance-schema.md#SLSA-SCH-C1~SLSA-SCH-C8 (SLSA v1.0 spec 필드명) official-standard D7 의 ca-tmpl 약식 필드명이 본 결정과 충돌 — wiki/projects 추출 시 spec 필드명 채택
D14 jq 1.8.1을 checksum 검증해 job-local 설치하고 jq 소비 job 6개가 공통 installer를 호출 UNSUPPORTED_DECISION — CI 장애 로그와 jq 1.8.1 GitHub release asset metadata를 구현 증거로 사용했으나 raw source Claim ID는 만들지 않음 local-incident + vendor-release-metadata 실제 Gitea/act runner 재실행 전까지 needs-confirmation; GitHub release host egress가 차단된 runner는 내부 mirror 설계가 별도 필요

구현 가이드

결정 이 "무엇" 이면 본 §는 "어디에 어떻게" 의 사전 명세. 다음 구현자가 되묻지 않고 코드를 작성할 수준이 목표.

코드 ground truth (2026-06-15 확인): ca-tmpl src/Dockerfile = 빈 파일, gradle/locks/ 부재, .github/workflows/ 부재, cosign/slsa config 부재 → 본 § 의 모든 detail 은 planned. 어떤 항목도 actually-implemented 아님.

3-rule: 각 sub-section 은 Decision ID + Supporting Claim ID 를 Trace. 근거 raw 가 원칙만 권고하고 detail 을 권고 안 하면 UNSUPPORTED_IMPL_DECISION 라벨 + trade-off 한 줄. branch 결정 범위 밖 cell 은 OUT_OF_BRANCH_SCOPE 로 정제(별도 owner 이관).

1. Dependency version locking + reproducible build (Trace: D8 · SC-DL-C1C9 / D10 · GRADLE-RA-C1C3 · RB-JVM-C3/C4/C6)

Trace: D8(Gradle dependency-locking), D10(reproducible archives). 모두 planned (코드 부재).

  • UNSUPPORTED_IMPL_DECISION: (a) lockfile 경로 — D8 의 gradle/locks/*.lockfile 은 Gradle 기본(gradle.lockfile/*.versions.lock, RENOV-GRAD-C1)과 불일치 → §Audit LOCKFILE_PATH_DRIFT. trade-off: Gradle 기본 경로 채택 = Renovate 호환 우선. (b) dirPermissions/filePermissions 의 정확한 unix 값(755/644)은 RB-JVM-C4 가 원칙만 권고 — 팀 선택. (c) JDK pin 메커니즘(Gradle Toolchains vs .tool-versions/gradle/wrapper/)은 D10 raw 가 명시 안 함 — trade-off: Toolchains = 빌드 자체 강제, .tool-versions = 로컬 개발 동기화.
위치 / 설정 값 (planned) 상태 Trace
build.gradle.kts dependencyLocking dependencyLocking { lockAllConfigurations(); lockMode = LockMode.STRICT } planned D8 / SC-DL
lockfile 경로 Gradle 기본 gradle.lockfile(루트/서브프로젝트) — D8 의 gradle/locks/*.lockfile 와 정합 필요 planned + DRIFT D8 / RENOV-GRAD-C1
reproducible archives tasks.withType<AbstractArchiveTask>().configureEach { isPreserveFileTimestamps = false; isReproducibleFileOrder = true } planned D10 / GRADLE-RA-C3
umask 정규화 dirPermissions { unix("755") }; filePermissions { unix("644") } planned (값=UNSUPPORTED_IMPL) D10 / RB-JVM-C4
JDK pin java { toolchain { languageVersion = JavaLanguageVersion.of(21) } } + 로컬 .tool-versions planned (메커니즘=UNSUPPORTED_IMPL) D10
locale entropy CI JVM args -Dfile.encoding=UTF-8 (Java 17 이하) planned D10 / RB-JVM-C6

2. Artifact versioning (Trace: D9 · SEMVER-C1/C3/C4/C5)

Trace: D9. SemVer 2.0.0 MAJOR.MINOR.PATCH + git short-sha build metadata.

  • UNSUPPORTED_IMPL_DECISION: version bump 자동화 메커니즘(conventional-commits + semantic-release / GitVersion / 수동 tag)은 D9 raw 가 권고 안 함 — trade-off: 자동화 없으면 MAJOR/MINOR/PATCH 의미론이 팀 규율에 의존. (b) + 문자 registry 호환 — OCI tag 규칙이 + 를 거부하면 image-tag 층에서 치환(_ 등) 필요(UNSUPPORTED_IMPL, D9 Open Risk).
항목 명세 (planned) 근거
version 포맷 <MAJOR>.<MINOR>.<PATCH>+<short-sha> (예: 1.2.3+a1b2c3d) SEMVER-C1
+ 의미 build metadata — precedence 에서 무시. 1.2.3+x1.2.3+y 동일 precedence SEMVER-C3/C4
금지 1.2.3-<sha> 형식(= pre-release, precedence 낮춤) 사용 금지; CalVer 금지 SEMVER-C5 / CALVER

3. Artifact signing + provenance (Trace: D4 · COSIGN-C1/C4 · SLSA-FW-C4 / D6 · COSIGN-C1C3 / D7 · SLSA-FW-C4C6 / D12 · CSIGN-KL-C1C4 / D13 · SLSA-SCH-C1C8)

Trace: D4/D6/D7/D12/D13. Cosign keyless 서명 + SLSA v1.0 provenance attestation. 모두 planned.

  • OUT_OF_BRANCH_SCOPE: deploy-time admission 강제(Kyverno / sigstore-policy-controller / OPA Gatekeeper)는 k8s admission/deploy 계약 — 본 branch 는 서명된 artifact + verify 정책 만 생성, 클러스터 게이트 는 별도 owner. §엣지·실패·의존 + Claims To Verify 참조.
항목 명세 (planned) 근거
sign cosign sign --yes <image>@<digest> (keyless, Fulcio OIDC, 10분 cert) D6 / COSIGN-C1~C3
verify cosign verify --certificate-identity=<expected> --certificate-oidc-issuer=<expected> <image> — identity flag 필수, 존재만 검증하면 fail D12 / CSIGN-KL-C1~C4
provenance in-toto Statement, SLSA v1.0 필드명 buildDefinition.externalParameters / runDetails.builder.id 사용; 약식(build.config.source) 금지 D7·D13 / SLSA-SCH

4. Vulnerability severity gating — consume (Trace: D2 → owner raw/branch-notes/feature-dependency-vulnerability-management-contract)

Trace: D2. severity 차단 정책 의 single owner 는 vuln-management branch(§Audit OWNER_RECONCILE). 본 branch 는 release artifact 단계에서 그 정책을 consume — 새 결정을 만들지 않는다.

항목 본 branch 의 consume 지점 (planned) 근거
release-block 신호 "high/critical → release fail" 을 owner 의 CVSS bands(High 7.08.9 / Critical 9.010.0)에 결합 D2 / CVSS C1
집행 vehicle Trivy --severity HIGH,CRITICAL --exit-code 1 (scanner wiring 은 ci-gates/container-runtime 소유) TRIVY-EG-C2
예외 경로 .trivyignore.yaml exp: allowlist — governance 는 owner 소유 TRIVY-EG-C4

5. Dependency update bot — consume (Trace: D3 → owner raw/branch-notes/feature-dependency-vulnerability-management-contract)

Trace: D3. update-automation 정책(Renovate primary / Dependabot 조건부) owner 는 vuln-management. 본 branch 의 직접 관심사는 단 하나 — lockfile(D8)이 선택된 bot 과 호환되어야 함.

  • DRIFT: D8 의 lockfile 경로 vs Renovate 인식 경로 → §Audit LOCKFILE_PATH_DRIFT. bot CHOICE 자체는 owner 결정.
항목 본 branch 의 consume 지점 (planned) 근거
Renovate lockfile 갱신 config:recommended + self-hosted 시 allowedUnsafeExecutions: ["gradleWrapper"] (lockfile --write-locks) RENOV-GRAD-C2/C3
경로 정합 D8 lockfile 경로를 Renovate fileMatch/Gradle 기본과 일치 RENOV-GRAD-C1

6. Rollback artifact retention (Trace: D11 · UNSUPPORTED_DECISION)

Trace: D11. 최근 10개 release + 90일(whichever longer).

  • UNSUPPORTED_IMPL_DECISION: 10/90 정량값 + registry retention 강제 메커니즘(registry retention IaC / 정기 audit cron)은 외부 표준 부재 — 조직 정책. trade-off: 보수적 보관(스토리지 비용 ↔ rollback 가용성). 자동 강제 검증은 Claims To Verify.

엣지·실패·의존

R4 캡처용. 정상 경로 외 구현 중 부딪힐 실패/엣지/다른 계약 의존을 미리 열거.

  • 실패·엣지 경로:
    • lock drift: 선언 dependency ≠ lockfile → build fail (D8). 엣지: transitive-only version 변경도 fail 해야 함(Claims To Verify).
    • reproducibility 부분 보장: 동일 commit 이라도 JDK vendor/version 또는 build cache 차이로 hash 불일치 가능 — GRADLE-RA-C2 는 "helps"(보장 아님). 테스트 계약의 "2회 build hash 일치" 는 동일 toolchain 전제.
    • unfixed CVE: 상위 fix 없는 HIGH CVE → release 무기한 차단; .trivyignore.yaml exp: 예외로 완화(D2 consume). 엣지: 만료된 예외는 다시 fail 로 표면화.
    • SemVer +sha registry 거부: OCI/registry tag 규칙이 + 거부 시 image-tag 층 치환 필요(D9 엣지).
    • signature 강제 누수: cosign 서명은 생성되나 admission controller 미배포 → unsigned image 가 deploy 통과 가능(D4/D6 의 "forbidden" 이 강제 안 됨). 엣지: admission gate 배포 전까지 유효.
    • Renovate lockfile 경로 mismatch: D8 경로와 Renovate 인식 경로 불일치 시 bot 이 lock 갱신을 조용히 실패(§Audit LOCKFILE_PATH_DRIFT).
  • 다른 계약 의존:

테스트 계약

  • artifact에 version/source revision 식별자가 없으면 실패.
  • container가 root user로만 실행 가능하면 실패.
  • release artifact 재생성 없이 rollback할 수 없으면 실패.
  • dependency upgrade policy가 없으면 실패.
  • SBOM은 있으나 image digest/source revision 추적이 없으면 실패.
  • signature 없는 artifact 발견 시 release fail.
  • reproducibility 검증: 동일 commit 2회 build → artifact hash 불일치 시 fail.

검증해야 할 주장

공식 문서나 사례는 근거지만, 내 프로젝트에서의 동작을 자동으로 보장하지 않는다. 구현 전/중/후에 실제로 검증해야 하는 주장을 분리.

Claim Why uncertain How to verify Status
GitHub Actions hosted runner 기반 build 가 SLSA Build L2 도달 SLSA-FW-C2 는 hosted dedicated infrastructure + signed provenance 요구, hosted runner 가 자동 L2 라는 뜻은 아님 slsa-github-generator action 으로 provenance 생성 + slsa-verifier 로 --builder-id / --source-uri 검사 통과 verify actually-implemented; live run needs-confirmation
Cosign --certificate-identity + --certificate-oidc-issuer 매칭이 admission 단계에서 강제 Cosign verify CLI 자체는 검증만, deploy gate 통합은 별도 sigstore-policy-controller 또는 Kyverno policy 작성 → mismatched identity 의 image deploy 실패 verify documented-only; deploy admission은 OUT_OF_BRANCH_SCOPE
Gradle dependency-locking 이 transitive dependency 모두를 lock Gradle 공식 lockfile 의 transitive 포함 여부 확인 필요 lockfile transitive entry 확인; 의도적으로 spring-core entry 제거 후 strict verification non-zero 확인 locally-verified
동일 commit 2회 build → artifact hash 일치 (reproducibility) timestamp/locale entropy 외에 build 환경 차이 (JDK build, dependency cache) 가능 두 clean local build SHA-256 비교; 후속 CI runner와 local 교차 비교 동일 환경 locally-verified; 교차 환경 needs-confirmation
Renovate 가 Gradle 기본 lockfile 경로를 인식·갱신 Renovate 실행 환경과 wrapper 허용 정책에 따라 lock 갱신 실패 가능 gradle.lockfile + renovate.json 배선 후 Renovate dry-run → lock 갱신 PR 생성 여부 verify 경로 actually-implemented; dry-run needs-confirmation
Rekor transparency log entry 가 signing 후 검증 측에서 접근 가능 Rekor public instance (rekor.sigstore.dev) 가용성 SLA 부재 sign 후 cosign verify --rekor-url=... 로 transparency log entry 검증 actually-implemented; live run needs-confirmation
SBOM 생성 도구가 모든 dependency 를 누락 없이 캡처 SBOM 도구의 false negative 가능 SBOM 출력 vs gradle dependencies diff verify; 의도적 dependency 추가 후 SBOM 갱신 verify 생성 gate actually-implemented; 완전성 needs-confirmation
signature 없는 artifact 가 deploy pipeline 의 어느 단계에서도 통과 못 함 admission controller 미배포 시 검증 누수 가능 의도적으로 unsigned image 를 push → deploy gate 에서 block 되는지 verify (다중 환경: dev/staging/prod) release promotion actually-implemented; deploy admission OUT_OF_BRANCH_SCOPE
rollback artifact 10개/90일 retention 정책이 자동 강제 registry retention policy 가 수동 설정 시 drift 가능 scheduled audit + fixture에서 protected manifest/SBOM/GHCR digest 누락·불일치가 실패하는지 검증 fixture locally-verified; live audit needs-confirmation
Gitea/act의 node:20-bullseye job에서 공통 jq installer 이후 공급망 behavior test가 통과 동일 컨테이너 검증은 private workspace mount 위험으로 승인 거부됨 변경 commit으로 ci-quality-gates/gate-matrix-lint 재실행 후 install-jq: jq-1.8.1test-supply-chain-scripts: OK 로그 확인 installer/behavior local locally-verified; Gitea CI needs-confirmation

관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)

/coverage 가 채우는 생성물 — 손으로 유지하지 않는다. governing 문서(wiki/projects/ca-tmpl/devops-ci-supply-chain-dx)가 요구하는 관심사를 이 브랜치가 빠짐없이 덮는지의 결과. 2026-06-15 coverage-auditor 판정: Covered (Blocking 0 / Should-fix 3 → Coverage 섹션 정규화로 해소 / Advisory 1). 상태: covered-here(이 브랜치 결정) / delegated(다른 owner 브랜치) / missing(아무도 안 맡음 → Blocking).

관심사 상태 owner 심각도 근거
Cosign keyless signing (Fulcio + Rekor) 의무화 covered-here D6 (COSIGN-C1~C3)
Cosign verify identity 정책 (--certificate-identity + --certificate-oidc-issuer) covered-here D12 (CSIGN-KL-C1~C4)
SLSA provenance attestation + SLSA v1.0 공식 필드명 강제 covered-here D7 (SLSA-FW-C4C6) + D13 (SLSA-SCH-C1C8)
Gradle dependency-locking (lockMode=STRICT) covered-here D8 (SC-DL-C1~C9)
SemVer + git sha suffix 버전 정책 (CalVer 금지) covered-here D9 (SEMVER-C1/C3/C4/C5 + CALVER negative-evidence)
Build reproducibility (preserveFileTimestamps/reproducibleFileOrder/JDK pin) covered-here D10 (GRADLE-RA-C1C3 + RB-JVM-C1C6)
SBOM 생성 (release per) + image digest 필수 covered-here D4 (COSIGN-C4 + SLSA-FW-C4) + §Supply Chain Defaults
Rollback artifact 보관 (최근 10개 / 90일) covered-here D11 (UNSUPPORTED_DECISION, team-policy)
Container base image (Temurin JRE slim) + non-root runtime delegated raw/branch-notes/feature-container-runtime-contract D3 OK D5 consume; §엣지·실패·의존 cross-link
Vulnerability severity 정책 (high/critical release-blocking, CVSS v3.1) delegated raw/branch-notes/feature-dependency-vulnerability-management-contract OK D2 consume; §Audit OWNER_RECONCILE
Dependency update automation (Renovate primary, Dependabot 조건부) delegated raw/branch-notes/feature-dependency-vulnerability-management-contract OK D3 consume; §Audit OWNER_RECONCILE
GitHub Actions gate model + Trivy scan wiring delegated raw/branch-notes/feature-ci-quality-gates-contract OK §구현 가이드 4 OUT_OF_BRANCH_SCOPE; §엣지·실패·의존 cross-link
OpenAPI snapshot diff / flaky quarantine delegated raw/branch-notes/feature-ci-quality-gates-contract OK governing doc CI 슬라이스 — 본 branch 범위 밖
DX 진입점 (./gradlew bootstrap, .tool-versions, Testcontainers, link-rot) delegated raw/branch-notes/feature-developer-experience-contract Advisory governing doc DX 슬라이스 — 본 branch 범위 밖; D10 JDK pin 은 dx .tool-versions(D6)와 정합

Audit & Findings

2026-06-15 /branch-spec 자동조사 라운드에서 발견한 정합 항목. 자동 rewrite 하지 않고 권고만 기록(사용자 결정 영역). /sync 가 Single-Owner 정합을 수행.

  • OWNER_RECONCILE (Single-Owner, 권고): D2(vuln severity 정책) + D3(dependency update automation 정책)의 정책 single owner 는 raw/branch-notes/feature-dependency-vulnerability-management-contract (그 branch §Audit 가 본 branch 의 D2/D3 UNSUPPORTED_DECISION 스텁을 승계해 owner 선언). 2026-06-15 자동조사가 본 branch D2/D3 에 CVSS/Trivy/Renovate/Dependabot 공식 source 8건 중 일부를 아카이브했고 이 source 들은 owner 정책도 뒷받침한다. 권고: /sync 로 본 branch 의 D2/D3 를 owner 의 Reference-Only 포인터로 정합(RESTATED_FOREIGN_DECISION 방지). 본 branch 의 D2/D3 는 consume 관계(§구현 가이드 4·5)로 유지.
  • CVSS_CLAIM_ANCHOR_FIX (정정 완료): D2 의 CVSS 참조 anchor 를 #CVSS-SRS-C1/2/3#C1/C2/C3 로 정정. 재사용된 기존 파일 raw/official-docs/vuln-severity-cvss-v31-spec-first-official.md 의 실제 claim ID 는 C1~C5.
  • LOCKFILE_PATH_DRIFT (권고): D8 은 gradle/locks/*.lockfile 경로를 선언하나, Gradle 기본/Renovate 인식 경로는 루트 gradle.lockfile + *.versions.lock (RENOV-GRAD-C1). 정합 안 하면 Renovate(D3 owner 영역)가 lock 갱신 실패. 권고: D8 경로를 Gradle 기본으로 정합하거나 Renovate fileMatch override. 실측 = Claims To Verify.
  • D5_CROSSREF_PRECISION (권고): D5 Open Risk 의 cross-branch 동기화 대상은 raw/branch-notes/feature-container-runtime-contractD3(base image = Temurin JRE slim)로 좁히는 것이 정확(기존 "D2~D4" 는 광범위). 비차단 — 사용자 결정 영역, 권고만.

완료 후 wiki 추출 대상

마주친 문제

  • Gradle dependencies report는 strict lock 누락을 FAILED로 표시해도 exit 0으로 끝나 Docker preflight가 fail-open이었다.
    • 원인: dependency report가 진단 task이고 unresolved configuration을 build failure로 전파하지 않음.
    • 해결: 실제 모든 resolvable configuration을 resolve하는 verifyDependencyLocks task를 추가하고 Docker preflight에 연결. transitive lock entry 제거 negative test로 exit 1 확인.
  • sandbox/외부 도구 경계로 Gradle과 Actionlint 재검증이 한때 차단됐다.
  • Gitea/act의 gate-matrix-lint가 정적 계약 통과 뒤 jq: command not found(exit 127)로 실패했다.
    • 원인: ubuntu-latestnode:20-bullseye로 매핑됐지만 jq 소비 job이 runner 기본 도구를 암묵적으로 가정했다.
    • 해결: checksum 검증 공통 installer를 추가하고 직접·간접 jq 소비 job 6곳에 연결했다.
    • 별도 에러 노트: raw/errors/gitea-act-missing-jq-job-bootstrap-2026-06-23.

묶음

본 feature branch 는 leaf — 자식 자료 없음. Phase C2 실 코드 작성 단계에서 errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화.

근거 자료

오류 기록 (본 feature 작업 중 발생)

면접 준비 (이 작업에서 나올 수 있는 면접 질문)

job-posting tie-ins (이 작업에서 파생된 글감)

관련 일일 노트

  • 없음 — 2026-06-23 CI 보완 작업에 대응하는 daily note는 작성되지 않음.

완료 후 정리

머지/종료 시점에 채움.

  • PR 링크:
  • 리뷰 메모: self-review에서 release publication 순서, retention API fail-open, manifest↔GHCR digest 일치, exact SLSA builder ID, Trivy 무권한 설치, Gradle diagnostic task fail-open을 보강. 2026-06-23에는 jq job 격리와 checksum bootstrap 계약을 추가했다.
  • 머지 결과 / 배포 환경: 미머지. local build/test/contract/Docker 검증까지 완료; GitHub OIDC·Rekor·GHCR live release는 미실행.
  • wiki 추출 대상 (verified만, wiki/projects/로만 추출):
    • actually-implemented 항목: Gradle strict locks, SemVer+sha, digest-first release DAG, SPDX SBOM, Cosign identity, SLSA v1 exact builder, High/Critical gate, rollback audit, jq job-local bootstrap wiring.
    • locally-verified 항목: 전체 Gradle check, positive/negative lock drift, 두 clean build hash, Docker non-root/OCI labels, manifest/retention behavior tests, jq 1.8.1 checksum install과 공급망 behavior test.
    • prod-verified 항목: 없음.
  • 추출하지 않을 항목 (planned / documented-only / abandoned): live OIDC/Rekor/GHCR release 결과와 deploy-time admission 강제는 검증 전 canonical 사실로 추출하지 않음.