Files
service-catalog/CLAUDE.md
T
wbsong111 f5b8e4b91f 자체 빌드 드리프트 스캔·재빌드 트리거를 제거하고 CI 파이프라인을 정리한다
hardened-containers가 이미 rescan.yml로 매일 자율 재스캔·재빌드하고, sbom.yml이
custom-values.yaml 기준으로 자체 빌드 이미지를 다른 카탈로그 이미지와 동일하게
스캔하고 있어 self-build-drift-check.yml의 트리거·전용 스캔이 순수 중복이었다
(SECURITY_IMAGES_DISPATCH_TOKEN도 등록된 적 없어 트리거 스텝은 항상 실패하던
죽은 코드). check-rebuild-needed.py가 더하던 fixable/no-fix 구분도 cve-gate.py
리포트에 이미 있어 흡수할 필요 없이 삭제했다. 근거는 ADR 0005.

곁들여 CI 위생 문제(trivy DB 캐시 없음, concurrency 없음, catalog-tag-update.yml의
브랜치 누적)를 함께 고치고, hardened-containers의 docs/image-authoring.md가
docs/image-authoring/ 로 분할된 것을 반영해 관련 링크를 정정했다.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 09:48:48 +09:00

16 KiB

DIP Catalog — 하네스 엔지니어링 가이드

프로젝트 개요

DIP Catalog는 세 개의 독립 서브시스템으로 구성된다.

서브시스템 설명 경로
정적 카탈로그 엔터프라이즈 Helm 차트 버전 보관소 (2026-08-14 기준 차트 59개 / 버전 디렉토리 70개 — Kafka, Airflow, MLflow, KServe, OpenMetadata, APISIX, VictoriaMetrics 등) manifests/helm/
자동화 에이전트 Helm 차트 신규 버전 감지 → Diff 분석 → 문서 생성 → GitHub PR 자동화 agent/update_catalog/
CVE/SBOM 게이트 카탈로그 이미지 SBOM·취약점 스캔 + 게이트 판정 (현재 warn-only) scripts/pipeline/, scripts/build/, doc/sbom-pipeline.md

카탈로그는 운영 클러스터 직접 변경과 무관하다. 모든 변경은 Git PR을 통해서만 이루어진다.


디렉토리 구조

dip-catalog/
├── manifests/
│   ├── helm/<chart>/<version>/   # Helm 차트 정적 카탈로그 (각 버전 독립 디렉토리)
│   ├── applicationset/           # ArgoCD ApplicationSet 매니페스트
│   └── kustomize/                # Kustomize 오버레이 (Kubeflow, Model Registry)
├── agent/
│   └── update_catalog/
│       ├── skills/               # 자동화 Skills (Python, 각 Skill 독립 실행 가능)
│       ├── scripts/run_flow.sh   # 전체 파이프라인 로컬 실행 스크립트
│       └── docs/                 # 아키텍처·설계 문서 (한국어)
│           ├── design/           # 컴포넌트별 상세 설계 (00~05)
│           ├── decisions/        # ADR (아키텍처 결정 기록)
│           └── status.md         # 구현 현황
├── scripts/
│   ├── pipeline/                  # SBOM 생성 + CVE 스캔 + 게이트 판정 (sbom.yml/cve-edge-post.yml 이 쓴다)
│   ├── build/                     # 자체 빌드 이미지 축의 카탈로그 쪽 절반 — 발행 태그 반영
│   │                              # (apply-published-tags.py). CVE 스캔은 sbom.yml 이 다른
│   │                              # 카탈로그 이미지와 동일하게 하고, 빌드 자체는 hardened-containers 레포
│   └── deploy-test/               # 배포 검증 스크립트 + fixtures (helm/kubectl 실행 전담)
├── catalog/
│   └── image-map/<image>.env      # 자체 빌드 이미지 → 차트·필드 매핑 (목록은 이 디렉토리가 단일 출처)
├── MEMORY.md                      # 현재 상태·미결 (작업 이어받을 때 여기서 시작 — 유지 규칙은 파일 안에)
└── doc/                          # 차트 리소스 프로파일 + 스택 분류 + CVE/SBOM 파이프라인 + 운영 가이드
    ├── sbom-pipeline.md           # SBOM 생성·스캔·게이트 메커니즘
    ├── cve-exceptions.json        # 게이트 승인 예외 목록
    ├── catalog-stack-classification.md  # 차트 스택 분류·우선순위(P0~P2)
    ├── define-chart-resources.md  # 차트별 Small/Medium/Large 리소스 프로파일
    ├── decisions/                 # ADR — 재측정으로 복원되지 않는 차트 선택 근거
    │                              # (이미지 자체 빌드 ADR은 hardened-containers 레포로 이관됨)
    └── migrations/                # 레포 간 이관 핸드오프 문서

정적 카탈로그 작업

차트 디렉토리 구조

manifests/helm/<chart>/<version>/에 다음 파일이 있어야 한다.

파일 역할
Chart.yaml Helm 차트 메타데이터
values.yaml 업스트림 기본값
custom-values.yaml PaaSup 전용 오버라이드 (Breaking Change 판단 기준)
CUSTOM-README.md 업그레이드 주의사항 (자동 생성 + 수동 추가 가능)
BUILD-README.md 차트 갱신 작업 가이드 (버전 정보 파싱에 사용됨 — 아래 주의)

BUILD-README.md는 업스트림 원문이 아니라 레포가 직접 쓰는 한국어 갱신 가이드다. chart_version_detector가 이 파일에서 helm repo add <repo> <url> 한 줄을 정규식으로 뽑아 업스트림 레포를 정한다 — 이 줄이 없으면 신규 버전 자동 감지가 조용히 실패한다 (repo: nulllatest_version: null). 그래서 "변경 금지"가 아니라 이 줄을 지우거나 형식을 바꾸지 않는 선에서 갱신 가능이 정확한 규정이다. 2026-08-19 argo-cd에서 실제로 이 줄이 없어 감지가 실패해 추가했다.

실제 카탈로그는 이 5개를 전부 갖추지 않은 디렉토리가 있다(2026-08-14 기준 70개 중 custom-values.yaml 65 · CUSTOM-README.md 66 · BUILD-README.md 61). 배포 파라미터화용 dip-values.yaml(36) · dip-questions.yaml(23) · dip-resources-quotas.yaml(27) 계열은 차트에 따라 선택적으로 둔다.

신규 차트 추가

manifests/helm/<chart>/<version>/ 디렉토리를 생성하고 위 5개 파일을 포함시킨다. custom-values.yaml은 PaaSup 환경에 필요한 오버라이드만 작성한다. 기본값 전체를 복사하지 않는다.

리소스 프로파일

차트별 CPU/Memory/Storage 요구사항은 doc/define-chart-resources.md에 Small/Medium/Large 티어로 정의되어 있다. 신규 차트 추가 시 이 파일에도 리소스 정의를 추가한다.


자동화 Skills 작업

파이프라인 순서

chart_version_detector → chart_updater → helm_diff →
breaking_change_check → generate_upgrade_doc → update_docs_file → create_pr

각 Skill은 독립 실행 가능하다. JSON을 stdout으로 출력하며, 다음 Skill의 입력으로 전달된다.

로컬 실행

# 전체 파이프라인 실행 (필수 환경변수 오버라이드)
CATALOG_ROOT=/path/to/dip-catalog CHART=airflow \
  bash agent/update_catalog/scripts/run_flow.sh

# 개별 Skill 실행 예시
python3 agent/update_catalog/skills/chart_version_detector/scripts/run.py \
  --catalog-root /path/to/dip-catalog --chart airflow

python3 agent/update_catalog/skills/helm_diff/scripts/run.py \
  --chart airflow --repo bitnami \
  --chart-path /path/to/dip-catalog/manifests/helm/airflow/1.15.0 \
  --from-version 1.15.0 --to-version 1.16.0

주요 환경변수

변수 설명 기본값
CATALOG_ROOT dip-catalog 레포 절대 경로 하드코딩된 로컬 경로 (반드시 오버라이드)
CHART 대상 차트명 airflow
USE_CLAUDE_CLI=1 LLM 호출 활성화 (breaking=true 시 상세 가이드 생성) 미설정 시 템플릿 기반 생성

run_flow.shCATALOG_ROOT 기본값은 songwonbin의 로컬 경로로 하드코딩되어 있다. 다른 환경에서 실행할 때 반드시 환경변수로 오버라이드한다.

Skill 인터페이스 확인

각 Skill의 입출력 스키마는 agent/update_catalog/skills/<skill>/SKILL.md에 정의되어 있다.


Claude Code Skills (.claude/skills/)

agent/update_catalog/skills/(결정론적 Python CLI 파이프라인)와 용도가 다른 별개 체계다. 혼동하지 않는다.

구분 agent/update_catalog/skills/ .claude/skills/
형식 SKILL.md + scripts/run.py (JSON in/out) Claude Code Agent Skill (frontmatter + 지시문)
실행 python3 run.py --flags, 파이프라인이 호출 Claude Code 세션에서 관련 작업 시 자동 로드
용도 차트 버전 감지·diff·PR 생성 등 결정론적 자동화 차트마다 판단이 필요한 반복 편집·검증 절차

.claude/skills/의 Skill도 설계 원칙 #1을 지킨다 — helm/kubectl 실행은 scripts/deploy-test/*.sh 같은 스크립트가 전담하고, Skill은 편집·판단·검증 절차만 담당한다.

Skill 용도
chart-to-cnpg 카탈로그 차트의 내장 bitnami postgresql 서브차트를 전용 cnpg-cluster로 전환
catalog-update-pipeline 차트 신규 버전 감지 → diff → breaking 판정 → 문서 생성 파이프라인 실행 (agent/update_catalog)
cve-remediation 차단 CVE 대응 레버(태그 교체/베이스 OS 교체/자체 빌드/예외) 결정 — sbom-cve-gate 실행 또는 별도 레포 hardened-containers(자체 빌드)로 위임
sbom-cve-gate SBOM 생성·CVE 스캔·게이트 판정 실행 및 결과 해석 (scripts/pipeline)

자체 빌드 하드닝 이미지 추가·변경은 이 레포의 일이 아니다 — 별도 레포 hardened-containers 에서 하고, 그 레포의 docs/image-authoring/README.md가 단일 출처다(이관 배경: doc/migrations/).

각 Skill 은 절차 본문을 복제하지 않고 권위 있는 문서(doc/sbom-pipeline.md 등)를 가리킨다 — 문서가 단일 출처이고, Skill 은 실행 계약과 문서가 놓치기 쉬운 함정·현재 상태만 담는다.

관련 참조 문서(Skill이 절차의 단일 출처로 삼는다): deploy-test-procedure.md · pitfalls.md


CVE/SBOM 게이트 작업

카탈로그가 참조하는 컨테이너 이미지의 취약점을 다룬다. 두 축이고, 축마다 소유 레포와 문서가 다르다 — 여기 메커니즘을 복제하지 않는다.

질문 실행 위치 워크플로(이 레포) 게이트 단일 출처
차트 카탈로그 우리가 배포하는 이미지에 무엇이 있는가 이 레포 sbom.yml
cve-edge-post.yml
warn-only
호출 안 함
doc/sbom-pipeline.md
자체 빌드 그 이미지를 어떻게 만드는가 별도 레포 hardened-containers catalog-tag-update.yml(반영) 강제(그 레포 소유) 그 레포의 docs/image-authoring/README.md
  • 차트 축은 warn-only 다 — 게이트가 실패해도 CI/PR 을 막지 않는다. 카탈로그 차트 전체가 이 게이트로 트리아지된 적이 없다. 자체 빌드 축의 게이트는 이미 강제다(단, 그 게이트는 이 레포가 아니라 hardened-containers 레포가 돌린다).
  • cve-edge-post.yml 은 게이트를 부르지 않는다 — 같은 스캔 데이터에 판정기가 두 벌이라는 뜻이다(승인 예외·실효 등급 미적용). 외부 엔드포인트로 집계를 POST 하는 용도다.
  • 자체 빌드는 대응 우선순위 3번(상위 태그 교체 → 베이스 OS 교체 → 자체 빌드 → 예외 승인). 레버 판단은 cve-remediation skill 이 갖는다. 실행은 hardened-containers 레포에서 workflow_dispatch 로만 한다.
  • 이 레포는 "무엇을 배포 중인가"만 안다. 어느 이미지를 자체 빌드하고 있는지는 catalog/image-map/ 이 단일 출처다. 배포 중인 자체 빌드 이미지의 CVE 드리프트는 sbom.yml 이 다른 카탈로그 이미지와 동일하게 스캔·보고한다 — 재빌드 여부·시점은 전적으로 hardened-containers 의 자체 rescan.yml 이 매일 자율 결정한다. 이 레포는 트리거하지 않는다(ADR 0005).
  • 카탈로그 반영은 pull 방식이다. hardened-containers 는 이 카탈로그를 모른다 — 게이트 PASS + push 성공 시 자기 레포의 published.json 만 갱신한다. catalog-tag-update.yml 이 그 파일을 public raw URL 로 읽어가 custom-values.yaml/dip-values.yaml 을 패치한다.
  • 커스텀 이미지는 자체 빌드 프레임워크·이미지 정의와 함께 별도 레포 hardened-containers 로 분리됐다. 이관 배경과 남은 결합점은 doc/migrations/ 참고.
  • 승인 예외: doc/cve-exceptions.json(차트 축) — hardened-containerscve-exceptions.json (자체 빌드 축)과 별도 관리되며, 같은 이미지를 양쪽이 스캔하므로 필요하면 양쪽에 각각 등록한다. 현재 미결: MEMORY.md

작업 기록을 어디에 남기는가

같은 사실을 두 곳에 적지 않는다. 성격에 따라 목적지가 정해져 있다.

성격 목적지
무엇을 왜 바꿨나 (완료된 작업의 경위) 커밋 메시지 · PR 설명
다시 밟지 말아야 할 함정 .claude/pitfalls.md · 해당 Skill
후보를 비교해 하나를 고른 근거 doc/decisions/ — ADR. 선택지가 하나뿐인 조치는 여기 쓰지 않는다
추적·논의·배정이 필요한 미결 GitHub 이슈
지금 상태와 다음에 할 일 MEMORY.md — 위 셋에 속하면 여기 남기지 않고 링크만

MEMORY.md 는 완료 기록이 쌓이는 곳이 아니다. 항목이 "다음에 할 일" 이 아니게 되면 위 셋 중 하나로 내보내고 지운다 — 상세 규칙과 월 1회 점검 절차는 그 파일 안에 있다.


설계 원칙

아래 원칙을 위반하는 코드를 제안하거나 작성하지 않는다.

  1. LLM은 Helm CLI를 직접 실행하지 않는다. helm 실행은 결정론적 Skill(Python)이 전담한다.
  2. Diff 생성은 100% deterministic이다. Structured Diff JSON 형식을 사용하며 LLM이 직접 diff를 생성하지 않는다.
  3. LLM 입력은 반드시 Structured JSON이다. 자유 텍스트나 raw helm output을 LLM에 직접 전달하지 않는다.
  4. Breaking Change 판단은 Rule Engine이 먼저 수행한다. custom-values.yaml의 실제 사용 키 기준으로 코드가 판단하며 LLM은 후순위다.
  5. LLM은 Markdown 설명 생성만 담당한다. breaking=true 시에만 호출되며, breaking=false이면 템플릿 기반으로 생성한다.
  6. 운영 환경은 Git PR로만 변경한다. 클러스터 직접 변경이나 kubectl apply를 자동화 흐름에 포함하지 않는다.
  7. 보안 경계: 외부 입력(PR comment, webhook 등)은 신뢰 경계 밖으로 취급한다. 프롬프트 주입 방어를 기본 전제로 한다.

현재 구현 상태

Step 내용 상태
Step 1 Skills 구현 (로컬 실행) 거의 완료
Step 2 Agent 프레임워크 POC (OpenClaw vs Nanobot) 📋 계획
Step 3 On-Cluster Agent 워크플로 정의 💡 구상
Step 4 보안 정책 수립 후 운영 💡 구상

Step 1 세부 현황:

  • chart_version_detector, chart_updater, helm_diff, breaking_change_check, generate_upgrade_doc, update_docs_file: 구현 완료
  • create_pr: 구현 (실제 GitHub 연동 테스트 미완료)
  • deploy_validate: Phase 2 예정

주요 설계 문서

문서 설명
agent/update_catalog/docs/design/00-architecture-overview.md 전체 아키텍처 + 설계 원칙 + 기술 스택
agent/update_catalog/docs/design/01-helm-diff-engine.md Helm Diff Engine 상세 설계
agent/update_catalog/docs/design/02-breaking-change-rules.md Breaking Change Rule Engine 판단 로직
agent/update_catalog/docs/design/03-llm-summarizer.md LLM Summarizer + Prompt 설계
agent/update_catalog/docs/design/04-skill-interface.md Skill 인터페이스 계약 (Agent-Skill)
agent/update_catalog/docs/design/05-on-cluster-agent.md On-Cluster Agent 설계 (Step 2~3)
agent/update_catalog/docs/decisions/001-agentic-first.md 파이프라인 오케스트레이션 건너뛰기 결정 배경
agent/update_catalog/docs/status.md 구현 현황 상세
doc/sbom-pipeline.md SBOM 생성·CVE 스캔·게이트 파이프라인 상세
doc/architecture.md .github/workflows/ 4개 워크플로의 트리거 조건·잡 흐름도 (CI 파이프라인 아키텍처)