Files
service-catalog/CLAUDE.md
T
wbsong111 63d25221df MEMORY.md 를 상태 파일로 되돌린다 (264줄 → 64줄)
MEMORY.md 는 3번째 줄에서 "지금 시점의 상태와 다음에 할 일만 담는다" 고 스스로 선언하는데
실제로는 완료 기록이 쌓여 264줄이 됐고, 이슈 참조가 한 건도 없었다. 그 결과:

- SBOM_PIPELINE_IMAGE 재빌드가 파일 안에서 3번 반복된다 (215·234·262줄)
- 게이트 강제력 전환이 2번 반복되고, 그 내용은 이미 이슈 #7 체크리스트와 #19 에 있다
- argo-cd 절 55줄은 커밋 33e91c0 메시지의 요약본이다
- 베이스 OS 정책·"벤더 릴리스 노트 믿지 말 것" 은 본문이 스스로 "이미 image-authoring.md /
  skill 에 있다" 고 밝히면서 중복 서술한다

같은 사실이 여러 곳에 있으면 나중에 어느 쪽이 맞는지가 새 문제가 된다.

성격별로 목적지를 정하고 내보냈다
---------------------------------
  추적이 필요한 미결   →  GitHub 이슈 (#29~#33 발행, MEMORY.md 엔 한 줄 링크)
  재발 방지 교훈       →  .claude/ 문서·skill
  단순 완료 기록       →  삭제 (커밋·PR·images/<image>/README.md 가 권위 있는 기록)

교훈 이관 — 아직 어디에도 없던 것만 옮겼다:

- image-authoring.md: 베이스 OS 를 CVE 수치만으로 고르면 배포에서 죽는다.
  cp --update=none(coreutils 9.3+) 실측과, 차트가 실행하는 명령을 verify.sh 에서
  재현하라는 규칙. 원칙 2 의 "BCI 버전은 실측해서 정한다" 바로 뒤에 붙였다.
- self-build-image skill: 같은 날 재빌드하면 태그가 겹쳐 노드 캐시가 반영을 막는다.
  근본 해결은 #31, 여기엔 우회법만.
- cve-remediation skill: 레버 표를 보기 전에 "이 컴포넌트가 필요하긴 한가" 를 먼저 묻는다.
  dex 가 한 줄로 차단 57건(58%)이었다. 가장 값싼 레버인데 표에 없어서 새 단계로 넣었다.

유지 규칙을 명시했다
--------------------
트리거는 시간이 아니라 상태다 — "1달 지났으니 정리" 는 아무도 시작하지 않고, 날짜로 자르면
오래됐지만 유효한 미결까지 잘린다. 항목이 "다음에 할 일" 이 아니게 되는 순간 내보낸다.
다만 놓친 것을 걷어내기 위해 월 1회 점검하고 파일 상단의 점검 날짜를 갱신한다.

규칙은 MEMORY.md 자체와 CLAUDE.md("작업 기록을 어디에 남기는가") 양쪽에 뒀다.

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

15 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/                     # 자체 빌드 이미지 프레임워크 (build-image.yml 이 쓴다)
│   └── deploy-test/               # 배포 검증 스크립트 + fixtures (helm/kubectl 실행 전담)
├── images/<image>/                # 자체 빌드 하드닝 이미지 정의 (목록은 이 디렉토리가 단일 출처)
├── 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 리소스 프로파일
    └── 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·self-build-image 실행으로 위임
sbom-cve-gate SBOM 생성·CVE 스캔·게이트 판정 실행 및 결과 해석 (scripts/pipeline)
self-build-image 자체 빌드 하드닝 이미지 추가·변경 (scripts/build, images/)

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

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


CVE/SBOM 게이트 작업

manifests/helm/ 카탈로그가 참조하는 컨테이너 이미지의 SBOM·취약점을 스캔하고 게이트로 판정한다. 정적 카탈로그·자동화 에이전트와 독립적으로 동작한다.

extract-helm-images.sh → generate-sbom.sh → scan-sbom.sh → cve-gate.py
(scripts/pipeline/, .github/workflows/sbom.yml·cve-edge-post.yml 이 실행)
  • 현재 warn-only: 게이트가 실패해도 CI/PR 을 막지 않는다. 카탈로그 차트 전체가 이 게이트로 트리아지된 적이 없다.
  • CI 는 전 심각도로 스캔한다 — 게이트가 벤더 하향 등급·NVD 재평가·사각지대 판정에 MEDIUM/LOW 까지 필요로 하기 때문이다. 스크립트 기본값(HIGH,CRITICAL)으로 만든 리포트로 게이트를 돌리면 판정이 달라진다.
  • 자체 빌드 프레임워크(scripts/build/, .github/workflows/build-image.yml)로 images/<image>/ 아래에 자체 빌드 이미지를 둔다(목록은 그 디렉토리가 단일 출처). 최종 런타임 베이스 OS 는 SUSE BCI 로 통일하되 버전은 이미지마다 실측해서 고른다. push·카탈로그 반영을 동반하는 빌드는 workflow_dispatch 수동 실행뿐이고(images/** PR 은 검증 전용, schedule 없음), sbom.yml 의 게이트가 이 워크플로를 자동 호출하지 않는다 — 자체 빌드로 갈지는 사람이 판단한다. 2026-08-04 에 etcd·cloudnative-pg 로 빌드→게이트→push→카탈로그 브랜치 push 까지 실제 CI 에서 검증됐다. 게이트가 상위 태그·베이스 OS 교체로 해소 안 되는 차단 CVE 를 찾으면 이 프레임워크로 자체 빌드를 검토한다 — 절차는 .claude/image-authoring.md.
  • 상세: doc/sbom-pipeline.md · 승인 예외: doc/cve-exceptions.json · 현재 미결 사항: MEMORY.md

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

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

성격 목적지
무엇을 왜 바꿨나 (완료된 작업의 경위) 커밋 메시지 · PR 설명 · images/<image>/README.md
다시 밟지 말아야 할 함정 .claude/pitfalls.md · .claude/image-authoring.md · 해당 Skill
추적·논의·배정이 필요한 미결 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 스캔·게이트 파이프라인 상세