Files
llm-wiki/wiki/concepts/devops-ci-supply-chain-dx.md
T

16 KiB

title, source_type, status, confidence, tags, related_projects, last_reviewed
title source_type status confidence tags related_projects last_reviewed
DevOps Baseline (CI + Supply chain + DX) llm-generated draft medium
devops
ci-cd
supply-chain
sigstore
developer-experience
ca-skeleton
2026-05-22

DevOps Baseline (CI + Supply chain + DX)

Layer: wiki/concepts/ — 일반 개념. 내 프로젝트 사실은 project-template / project 문서 사용.

Summary

운영 가능한 백엔드 skeleton의 DevOps baseline은 세 축으로 구성된다. (1) CI quality gate — GitHub Actions needs: + if: success()로 contract test ↔ release-blocking 의존성을 단일 yaml에서 강제하고, flaky test는 14일 sunset 기한이 붙은 quarantine bucket으로 분리한다. (2) Build / release supply chain — Cosign keyless signing (Sigstore Fulcio + Rekor transparency log)으로 artifact를 서명하고, SLSA provenance attestation으로 build 출처를 검증하며, Gradle dependency-locking으로 transitive 버전 drift를 차단한다. (3) Developer experience./gradlew bootstrap 같은 단일 진입점 + Testcontainers @ServiceConnection 기반 integration test + .tool-versions로 핀된 JDK LTS로 새 개발자가 clean clone 직후 smoke까지 5단계로 도달한다.

Standard (공식 정의)

CI quality gate

  • GitHub Actions (docs.github.com/en/actions/): YAML workflow의 jobs.<id>.needs 의존성과 if: success() | failure() 조건으로 단계별 gate를 표현. job status가 failure이면 workflow status도 failure.
  • GitLab CI/CD (docs.gitlab.com/ee/ci/pipelines/): stages + jobs + needs: + rules: 키워드로 같은 모델을 구성. parallel: matrix: 키워드로 matrix job.
  • Jenkins Declarative Pipeline (jenkins.io/doc/book/pipeline/syntax/): agent 디렉티브 + post { failure { ... } } block으로 실패 처리.
  • CircleCI configuration reference (circleci.com/docs/configuration-reference/): orbs + workflow + job 모델.
  • Tekton Pipelines (tekton.dev/docs/pipelines/): Pipeline = Tasks의 모음, 각 Task는 Kubernetes Pod로 실행.

Supply chain

  • Sigstore Cosign (docs.sigstore.dev/cosign/signing/overview/): OIDC identity token으로 Fulcio가 단명(10분) 서명 cert 발급, 서명 직후 private key 파기. 서명 이벤트는 Rekor transparency log에 immutable 기록. 검증 측은 cosign verify --certificate-identity=... --certificate-oidc-issuer=...로 issuer와 identity를 함께 강제.
  • SLSA v1.0 spec (slsa.dev/spec/v1.0/): "Supply-chain Levels for Software Artifacts". provenance는 build platform, top-level build invocation, materials(sources + dependencies)를 최소 식별. Build L1 = provenance 존재, L2 = hosted build platform, L3 = hardened/hermetic build.
  • in-toto attestation (github.com/in-toto/attestation): 인증된 statement = subject(artifact digest 목록) + predicate(예: SLSA Provenance). DSSE envelope으로 서명되며 Cosign이 같은 envelope을 서명한다.
  • Gradle dependency locking (docs.gradle.org/current/userguide/dependency_locking.html): dependencyLocking { lockAllConfigurations() } + --write-locks로 lockfile 생성. lockMode = STRICT일 때 lock state와 다른 해석은 build fail.
  • Maven Enforcer Plugin dependencyConvergence 룰: transitive lockfile은 부재. 부분 대응만 가능.

Developer experience

  • Testcontainers for Java (java.testcontainers.org/): Docker container 기반 throwaway dependency. Spring Boot 3.1+ @ServiceConnection annotation으로 JDBC URL, credentials, host, port가 ApplicationContext에 자동 주입. reuse 옵션은 CI 금지, 로컬만.
  • Devcontainer spec (containers.dev/implementors/spec/): .devcontainer/devcontainer.json이 VSCode/Codespaces용 dev container 정의. tool version과 OS-level dep을 통일하지만 첫 진입점/smoke/migration 순서는 별도 필요.
  • mise / asdf (mise.jdx.dev/, asdf-vm.com/) — .tool-versions 형식이 사실상 표준. SDKMAN! (sdkman.io/)은 별도 .sdkmanrc 사용.
  • Eclipse Temurin 21 LTS (adoptium.net/temurin/releases/?version=21): 2028-09까지 무료 LTS 보안 패치.

한계 / 주의점

CI

  • GitHub Actions는 vendor lock-in(workflow yaml 문법, OIDC issuer URL, marketplace action 등)과 hosted runner 비용 모델이 다른 provider와 다르다. provider-agnostic하게 gate를 정의하지 않으면 이식 비용이 크다.
  • Jenkins / Tekton은 인프라(k8s cluster, plugin ecosystem)에 대한 의존도가 커서 skeleton 단계에서는 과한 선택일 수 있다.
  • Flaky test quarantine은 Spotify/Google/Microsoft가 운영 도구로 인정한 반면 Martin Fowler는 *"Eradicating Non-Determinism in Tests"*에서 quarantine 자체를 anti-pattern으로 본다. "Spotify가 한다 = 공식 best practice"로 표현 금지. 14일 sunset 같은 절충은 어느 한쪽도 공식이 아니라는 인정이다.
  • OpenAPI snapshot diff (springdoc + openapi-diff/oasdiff)는 controller annotation을 정적 추출하므로 dynamic routing(예: webflux functional routes)이 있으면 누락된다. "ground truth"는 이 범위 안에서만 참.

Supply chain

  • Cosign keyless의 "signature 누락 시 deploy block"만으로는 부족하다. --certificate-identity + --certificate-oidc-issueridentity 매칭 정책을 별도로 명시해야 임의의 OIDC identity가 만든 서명도 통과되는 사고를 막을 수 있다. Sigstore 공식은 키리스 모드에서 두 flag를 검증 진입 전제 조건으로 강제하며(--certificate-identity ... is required for verification in keyless mode), GitHub Actions OIDC 환경의 expected identity는 https://github.com/<ORG>/<REPO>/.github/workflows/<file>@refs/heads/<branch> 형식, issuer는 https://token.actions.githubusercontent.com이다. 클러스터 측 강제는 policy-controller / Kyverno verifyImages 등 admission controller에서 expected identity/issuer를 정책으로 선언. — needs-confirmation: 정책 표현 형식은 조직별로 다름.
  • SLSA v1.0 spec의 실제 필드명은 두 최상위 객체로 구성된다. buildDefinition.{buildType, externalParameters, internalParameters, resolvedDependencies} + runDetails.{builder.id, builder.version, builder.builderDependencies, metadata.invocationId, metadata.startedOn, metadata.finishedOn, byproducts}. in-toto Statement 래퍼는 _type(https://in-toto.io/Statement/v1) + subject[*].digest + predicateType(https://slsa.dev/provenance/v1) + predicate. 약식 표현(build.config.source, build.invocation, materials)은 spec 필드명과 다르므로 slsa-verifier가 --builder-idrunDetails.builder.id 등의 필드를 찾지 못해 검증이 실패한다. provenance 생성 단계에서 spec 필드명을 그대로 사용해야 한다. — 출처: raw/official-docs/slsa-v1-provenance-schema.
  • SLSA Build L3 (hardened build, hermetic, tamper-resistant builder)는 GitHub Actions hosted runner만으로는 도달 불가. 실무적으로는 L2(hosted build platform)가 현실적 목표지점.
  • Gradle dependency-locking이 있어도 plugin 버전과 toolchain(JDK)은 별도 핀이 필요. .tool-versions / gradle/wrapper/gradle-wrapper.properties 핀과 함께 봐야 reproducible build가 완성된다.
  • Maven에는 transitive lockfile이 1급 시민으로 존재하지 않는다. Maven 기반 프로젝트에서 같은 수준의 reproducibility를 요구하면 추가 도구가 필요.

Developer experience

  • .tool-versions(asdf/mise) vs .sdkmanrc(SDKMAN) 포맷 차이. 두 파일을 동시에 두면 drift 위험. 단일 source로 좁히는 편이 안전하다.
  • Devcontainer는 VSCode/Codespaces에 의존한다. IntelliJ + 로컬 JDK 사용자에게는 중복 환경이 되며 bootstrap 단일 진입점/smoke는 devcontainer 안에서도 별도로 정의되어야 한다.
  • Testcontainers는 Apple Silicon(arm64) 환경에서 일부 image가 emulation(amd64) 위에서 동작해 bootstrap 시간이 늘어날 수 있다.
  • Testcontainers reuse 옵션은 CI에서는 반드시 비활성화. test 간 isolation을 깬다.
  • Bootstrap 한 줄 명령은 ergonomic 강점이 있으나 단계가 합쳐져 있어 어느 단계에서 실패했는지 추적이 어려울 수 있다. 실패 단계별 exit code 또는 step 출력 분리가 필요.

Project Application

Interview Questions

  • "CI에서 Gate ↔ Branch Contract Test 소유권 매트릭스란 무엇이고 왜 필요한가? 누가 어떤 gate를 깨질 때 책임지는지 어떻게 표현하는가?"
  • "Flaky test quarantine bucket에 sunset deadline을 14일로 두는 근거는 무엇인가? quarantine 자체를 반대하는 입장(Fowler)과 어떻게 절충하는가?"
  • "Cosign keyless signing이 GPG signing과 비교해 어떤 운영 비용을 제거하고, 어떤 새 의존성(OIDC IdP, Rekor 가용성)을 추가하는가?"
  • "SLSA build level L1/L2/L3가 각각 무엇을 보장하는가? skeleton 단계에서 현실적으로 도달 가능한 level은 어디까지인가?"
  • "Gradle dependency-locking이 필요한 이유는 무엇이고, Maven에는 왜 같은 수준의 lockfile이 없으며 어떻게 대체하는가?"
  • "Integration test backend로 Testcontainers를 H2 같은 in-memory DB 대신 선택하는 이유는 무엇인가? 그 비용은 무엇인가?"

Do Not Overclaim

  • "Cosign signature 누락만 차단하면 supply chain이 안전하다"고 단정 금지. identity 매칭 정책(--certificate-identity + --certificate-oidc-issuer)이 없으면 임의 OIDC identity가 만든 서명도 통과될 수 있다.
  • "SLSA Build L3를 달성했다"고 단정 금지. ca-skeleton 단계에서 L3는 hermetic build / tamper-resistant builder를 요구하며 GitHub Actions hosted runner만으로는 도달 어렵다. branch note의 약식 매핑(build.config.source 등)은 spec 실제 필드명(buildDefinition.externalParameters)과 다르므로 정정 필요.
  • "Google/Spotify/Microsoft가 flaky test quarantine을 운영하므로 공식 best practice다"라고 표현 금지. 이들은 company-tech-blog 등급이며 Fowler의 반대 입장이 함께 존재한다.
  • "GitHub Actions가 CI provider의 정답이다"로 단정 금지. ca-skeleton은 needs: + if: success() 모델이 contract gate에 맞물려 채택된 것이며, gate 정의 자체는 provider-agnostic하게 작성되어야 이식 가능하다.
  • "./gradlew bootstrap 한 줄이 끝났다 = 모든 게 정상이다"로 표현 금지. 5단계(compileTestJava → docker compose up → Flyway migrate → sample profile seed → smoke) 중 어디서 실패했는지 step 단위 검증이 필요.
  • "Devcontainer가 있으면 bootstrap이 필요 없다"로 표현 금지. devcontainer는 tool version과 OS-level dep만 통일하며, 진입점/smoke/migration 순서는 별도로 정의되어야 한다.
  • LLM 생성 문서이므로 본 concept 문서의 모든 진술은 confidence: medium. 검증 전 high confidence로 분류 금지.

Sources

공식 문서 / spec

Raw 원본 (저장소 내 발췌)

Canonical 참조