From 01ec67ae1f6e12de08b6a920594ceb1a58ddee4f Mon Sep 17 00:00:00 2001 From: wbsong111 Date: Wed, 5 Aug 2026 15:37:57 +0900 Subject: [PATCH] =?UTF-8?q?=ED=8C=8C=EC=9D=B4=ED=94=84=EB=9D=BC=EC=9D=B8?= =?UTF-8?q?=20=EC=8B=A4=ED=96=89=20=EC=A0=88=EC=B0=A8=EB=A5=BC=20Claude=20?= =?UTF-8?q?Code=20Skill=203=EC=A2=85=EC=9C=BC=EB=A1=9C=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 세 파이프라인의 실행법이 문서에만 있어 "그 문서를 읽어야만" 알 수 있었다. 관련 작업 시 자동 로드되도록 Skill 로 등록한다. - catalog-update-pipeline: agent/update_catalog 파이프라인. CATALOG_ROOT 가 개인 로컬 경로로 하드코딩돼 있어 오버라이드 필수라는 점, create_pr 단계가 주석 처리돼 PR 이 생성되지 않는다는 점을 명시했다. - sbom-cve-gate: SBOM·스캔·게이트. CoverageProbe(ok/none/n-a) 해석과 게이트가 현재 warn-only 라는 점을 명시했다. - self-build-image: 자체 빌드. 오케스트레이터는 하나뿐이라는 원칙과 전역 ARG 선언, 게이트 PASS 가 동작을 보장하지 않는다는 점을 명시했다. Skill 은 절차 본문을 복제하지 않고 권위 문서를 가리킨다 — 문서가 단일 출처이고 Skill 은 실행 계약과 함정·현재 상태만 담는다. 함께 고친 stale 문서(image-authoring.md): - "images/ 디렉토리 자체가 없다" → 실제로는 이미지 3종이 있고 push 까지 됐다 - "자동화된 배포 테스트 절차는 아직 없다" → deploy-test-procedure.md 와 전용 스크립트가 있다 Co-Authored-By: Claude Opus 5 (1M context) --- .claude/image-authoring.md | 13 ++-- .../skills/catalog-update-pipeline/SKILL.md | 68 +++++++++++++++++++ .claude/skills/sbom-cve-gate/SKILL.md | 66 ++++++++++++++++++ .claude/skills/self-build-image/SKILL.md | 50 ++++++++++++++ CLAUDE.md | 7 ++ 5 files changed, 198 insertions(+), 6 deletions(-) create mode 100644 .claude/skills/catalog-update-pipeline/SKILL.md create mode 100644 .claude/skills/sbom-cve-gate/SKILL.md create mode 100644 .claude/skills/self-build-image/SKILL.md diff --git a/.claude/image-authoring.md b/.claude/image-authoring.md index e7b4ad2..9150599 100644 --- a/.claude/image-authoring.md +++ b/.claude/image-authoring.md @@ -3,9 +3,10 @@ [CLAUDE.md](../CLAUDE.md) 에서 분리했다. 새 자체 빌드 이미지를 추가하거나(CVE 게이트 대응 우선순위 중 "자체 빌드") 기존 이미지의 빌드 정의를 바꿀 때만 참고한다. -security-catalog 레포에서 검증한 자체 빌드 프레임워크를 포팅했다. **이 시점에는 아직 -이 레포에 도입된 자체 빌드 이미지가 없다** — `images/` 디렉토리 자체가 없다. 아래는 -프레임워크가 어떻게 동작하는지와, 첫 이미지를 추가할 때 지켜야 할 규칙이다. +security-catalog 레포에서 검증한 자체 빌드 프레임워크를 포팅했다. 현재 +`images/` 에 이미지 3종(`cloudnative-pg`, `cnpg-postgresql`, `etcd`)이 있고 +`docker.io/paasup` 에 push 되어 카탈로그 values 가 이 태그를 참조한다. 아래는 +프레임워크가 어떻게 동작하는지와, 이미지를 추가·변경할 때 지켜야 할 규칙이다. ## 원칙 1 — 오케스트레이션은 항상 하나, 이미지 종류는 몰라도 된다 @@ -92,9 +93,9 @@ security-catalog 는 자체 빌드 이미지의 최종 런타임 베이스로 SU 없다는 뜻이므로 게이트가 차단한다(`doc/sbom-pipeline.md` 참고) 5. **게이트 PASS 는 "동작한다" 를 증명하지 않는다.** CVE 스캐너는 CVE 와 무관한 런타임 요구사항(예: 오퍼레이터가 자신의 파일 레이아웃에 의존하는 것)을 전혀 보지 못한다. - 실제 배포 검증을 반드시 한다 — 자동화된 배포 테스트 절차는 아직 없으므로 해당 차트를 - dev 클러스터에 배포해 수동으로 기능을 확인한다. 업스트림과 다르게 만든 부분은 전부 - 이유를 확인하고 남긴다. + 실제 배포 검증을 반드시 한다 — 절차와 스크립트는 + [deploy-test-procedure.md](deploy-test-procedure.md) 에 있다(cnpg·etcd 는 전용 스크립트, + 그 외는 수동 절차). 업스트림과 다르게 만든 부분은 전부 이유를 확인하고 남긴다. 6. 카탈로그 values(`custom-values.yaml`/`dip-values.yaml` 등) 갱신, 조사·결정 근거를 PR 설명과 `MEMORY.md`에 기록. `images/**`+`manifests/helm/**` 는 PR 로. 7. CI 자동화: `build-image.yml` 은 이미 `image` 입력으로 파라미터화돼 있다 — diff --git a/.claude/skills/catalog-update-pipeline/SKILL.md b/.claude/skills/catalog-update-pipeline/SKILL.md new file mode 100644 index 0000000..fe2ba0a --- /dev/null +++ b/.claude/skills/catalog-update-pipeline/SKILL.md @@ -0,0 +1,68 @@ +--- +name: catalog-update-pipeline +description: Helm 차트 신규 버전 감지 → diff → breaking change 판정 → 업그레이드 문서 생성 파이프라인(agent/update_catalog)을 실행할 때 사용한다. "차트 새 버전 확인해줘", "업그레이드 문서 생성", "run_flow.sh 돌려줘", "helm diff 내줘", "breaking change 확인" 같은 요청이 해당한다. 개별 Skill(chart_version_detector, helm_diff, breaking_change_check 등) 단독 실행에도 적용된다. +--- + +# 카탈로그 업데이트 파이프라인 실행 + +`agent/update_catalog/`의 결정론적 Python Skill 7개를 `run_flow.sh`가 순서대로 체이닝한다. +각 Skill은 stdout으로 JSON을 내고 다음 Skill의 입력이 된다. + +``` +chart_version_detector → chart_updater → helm_diff → breaking_change_check + → generate_upgrade_doc → update_docs_file → create_pr +``` + +## 실행 전 반드시 확인할 것 + +**`CATALOG_ROOT`를 오버라이드하지 않으면 엉뚱한 경로를 본다.** 기본값이 +`/Users/songwonbin/openclaw-workspace/dip-catalog`로 하드코딩돼 있다(개인 로컬 경로). + +```sh +CATALOG_ROOT=/path/to/dip-catalog CHART=airflow \ + bash agent/update_catalog/scripts/run_flow.sh +``` + +| 환경변수 | 의미 | 기본값 | +|---|---|---| +| `CATALOG_ROOT` | dip-catalog 절대 경로 | **하드코딩된 개인 경로 — 반드시 오버라이드** | +| `CHART` | 대상 차트명 | `airflow` | +| `OUT_DIR` | 중간 JSON 산출물 | `$(pwd)/update_catalog` (차트별 하위 디렉토리로 격리) | +| `DEFAULT_BRANCH` | 분기 기준 브랜치 | `main` | +| `USE_CLAUDE_CLI=1` | `breaking=true` 시 LLM 상세 가이드 생성 | 미설정 시 템플릿 기반 | + +## 알려진 미완 상태 + +**`create_pr`(6단계)은 `run_flow.sh`에서 통째로 주석 처리돼 있다** — 파이프라인이 끝까지 +돌아도 **브랜치·커밋·PR이 생성되지 않는다.** 문서 생성까지가 실제 동작 범위다. +PR이 필요하면 결과물을 보고 직접 만들거나, 주석을 해제하기 전에 `create_pr` Skill의 +동작을 먼저 검증한다(CLAUDE.md 기준 "실제 GitHub 연동 테스트 미완료"). + +`deploy_validate`는 SKILL.md만 있고 구현이 없다(Phase 2 예정). + +## 개별 Skill 단독 실행 + +파이프라인 전체가 아니라 한 단계만 필요할 때가 많다. 입출력 스키마는 +`agent/update_catalog/skills//SKILL.md`에 있다. + +```sh +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 +``` + +## 지켜야 할 설계 원칙 + +CLAUDE.md "설계 원칙"이 이 파이프라인을 직접 구속한다. 특히: + +- **helm 실행은 Python Skill이 전담한다** — LLM이 helm CLI를 직접 돌려 diff를 만들지 않는다. +- **LLM 입력은 Structured JSON만** — raw helm output이나 자유 텍스트를 넘기지 않는다. +- **Breaking change는 Rule Engine이 먼저 판단한다**(`custom-values.yaml`의 실제 사용 키 기준). + LLM은 `breaking=true`일 때 Markdown 설명 생성만 담당한다. + +## 참고 + +- CLAUDE.md "자동화 Skills 작업" — 파이프라인 개요·환경변수 +- `agent/update_catalog/docs/design/` — 컴포넌트별 상세 설계(00~05) +- `agent/update_catalog/docs/status.md` — 구현 현황 diff --git a/.claude/skills/sbom-cve-gate/SKILL.md b/.claude/skills/sbom-cve-gate/SKILL.md new file mode 100644 index 0000000..dcb6e83 --- /dev/null +++ b/.claude/skills/sbom-cve-gate/SKILL.md @@ -0,0 +1,66 @@ +--- +name: sbom-cve-gate +description: 카탈로그 이미지의 SBOM 생성·CVE 스캔·게이트 판정을 실행하거나 결과를 해석할 때 사용한다. "SBOM 만들어줘", "취약점 스캔 돌려줘", "CVE 게이트 확인", "이 이미지 CRITICAL 몇 개야", "예외 등록" 같은 요청이 해당한다. scripts/pipeline/(extract-helm-images.sh, generate-sbom.sh, scan-sbom.sh, cve-gate.py)과 sbom.yml 워크플로를 다룬다. +--- + +# SBOM·CVE 게이트 실행 + +``` +extract-helm-images.sh → generate-sbom.sh → scan-sbom.sh(+CoverageProbe) → cve-gate.py +``` + +## 실행 경로 2가지 + +**기본은 GitHub 워크플로다** — 파이프라인은 도구가 설치된 컨테이너(`vars.SBOM_PIPELINE_IMAGE`) +안에서 돈다. + +```sh +gh workflow run helm-catalog-sbom --repo /dip-catalog -f limit=3 # 빠른 검증 +gh workflow run helm-catalog-sbom --repo /dip-catalog # 전체(limit=0) +gh run watch --repo /dip-catalog +``` + +로컬에서 돌릴 때도 같은 컨테이너를 쓴다(정확한 `docker run` 명령은 +[doc/sbom-pipeline.md](../../../doc/sbom-pipeline.md) "로컬/컨테이너 실행" 참고). +레지스트리 인증이 필요하다 — `TRIVY_USERNAME`/`TRIVY_PASSWORD`(단일) 또는 `DOCKER_CONFIG`(다중). +빠른 검증은 generate 단계에 `LIMIT=3`. + +## 결과 해석 시 반드시 볼 것 + +**`CoverageProbe`를 먼저 본다.** findings 0건이 "진짜 0건"인지 "스캐너가 그 배포판을 모르는 +것"인지 구분하는 유일한 수단이다. + +| 값 | 의미 | +|---|---| +| `ok` | 데이터 있음 — 0건은 진짜 0건 | +| `none` | 데이터 없음 → **게이트가 차단한다**(거짓 clean) | +| `n/a` | OS 패키지 없음(distroless 등) | + +게이트는 고유 CVE 단위로 집계하고 **`max(벤더 등급, NVD 등급)`** 를 실효 등급으로 쓴다 — +벤더가 하향 평가한 CVE를 놓치지 않기 위함이다(`.claude/pitfalls.md` "스캐너 결과를 그대로 +믿지 말 것"). 승인 예외는 `doc/cve-exceptions.json`(근거·만료일 필수, `.trivyignore` 안 씀). + +## 현재 상태 — 게이트는 warn-only다 + +`sbom.yml`은 `cve-gate.py`를 `--warn-only`로 호출한다. **게이트가 실패해도 워크플로/PR을 +막지 않는다.** 45+ 카탈로그 차트가 아직 이 게이트로 트리아지된 적이 없어, 강제 전환 전에 +전체 스캔 1회로 현황 파악이 선행돼야 한다. + +최신 미결 사항·전환 판단 근거는 [MEMORY.md](../../../MEMORY.md)를 본다 — 이 skill에 +중복 기록하지 않는다. + +## 차단 CVE 대응 우선순위 + +``` +상위 태그 교체 → 베이스 OS 교체 → 자체 빌드 → 예외 승인 +``` + +자체 빌드로 가야 한다면 `self-build-image` skill과 +[.claude/image-authoring.md](../../image-authoring.md)를 따른다. 판정 로직 상세는 +`scripts/pipeline/cve-gate.py`의 모듈 docstring을 1차 출처로 본다. + +## 참고 + +- [doc/sbom-pipeline.md](../../../doc/sbom-pipeline.md) — 파이프라인 상세(단계별 입출력, 실행 이미지) +- `doc/cve-exceptions.json` — 승인 예외 +- [.claude/pitfalls.md](../../pitfalls.md) — 스캐너 신뢰 관련 실측 함정 diff --git a/.claude/skills/self-build-image/SKILL.md b/.claude/skills/self-build-image/SKILL.md new file mode 100644 index 0000000..5936ea1 --- /dev/null +++ b/.claude/skills/self-build-image/SKILL.md @@ -0,0 +1,50 @@ +--- +name: self-build-image +description: 자체 빌드 하드닝 이미지를 추가하거나 기존 빌드 정의를 변경할 때 사용한다. "이미지 자체 빌드해줘", "하드닝 이미지 추가", "차단 CVE를 자체 빌드로 해소", "build-hardened-image.sh 실행", "images/ 아래 새 이미지" 같은 요청이 해당한다. 현재 cloudnative-pg, cnpg-postgresql, etcd 3종이 있다. +--- + +# 자체 빌드 하드닝 이미지 + +CVE 게이트 대응 우선순위(상위 태그 교체 → 베이스 OS 교체 → **자체 빌드** → 예외 승인)에서 +앞의 두 단계로 해소가 안 될 때만 온다. + +## 원칙 — 오케스트레이션은 항상 하나다 + +**`scripts/build/build-hardened-image.sh` 하나가 모든 자체 빌드 이미지를 빌드한다.** +OS 패키지 재설치든 소스 컴파일이든 스크립트는 같고, 차이는 전부 `images//` 안에 있다. + +**"이 이미지는 성격이 다르다"는 이유로 새 오케스트레이션 스크립트를 만들지 않는다** — +절차(빌드 → 기능검증 → SBOM → 스캔 → 게이트 → push)는 이미지 종류와 무관하게 동일하다. +SBOM·스캔·게이트도 다시 만들지 않는다 — `build-hardened-image.sh`가 이미 +`scan-sbom.sh`/`cve-gate.py`를 호출한다. + +## 실행 + +```sh +IMAGE= BASE_OS= bash scripts/build/build-hardened-image.sh /tmp/out +``` + +`images//.build.env`가 계약(`DOCKERFILE`, `TARGET`, `BUILD_ARGS` 등)을 +선언하면 스크립트는 이미지 종류를 몰라도 된다. 전체 계약표와 신규 이미지 추가 7단계 절차는 +[.claude/image-authoring.md](../../image-authoring.md)에 있다 — 여기 복제하지 않는다. + +CI는 `build-image.yml`이 `image` 입력으로 이미 파라미터화돼 있다. `images//catalog.env`만 +추가하면 워크플로 수정 없이 태울 수 있다. + +## 실측된 함정 + +- **`FROM`에 쓰는 `ARG`는 첫 `FROM` 이전(전역 스코프)에 선언한다.** 스테이지 내부에 선언하면 + 그 스테이지 지역 변수가 되어 이후 `FROM`의 이미지명 해석에 쓰이지 않고 빈 이미지명 에러가 난다. +- **게이트 PASS는 "동작한다"를 증명하지 않는다.** CVE 스캐너는 런타임 요구사항(오퍼레이터가 + 자신의 파일 레이아웃에 의존하는 것 등)을 전혀 보지 못한다. 배포 검증을 반드시 한다 — + 절차는 [.claude/deploy-test-procedure.md](../../deploy-test-procedure.md). +- **`CoverageProbe`가 `ok`인지 확인한다.** `none`이면 findings 0건이 진짜 0건이 아니라 + 스캐너에 그 배포판 데이터가 없다는 뜻이다(`sbom-cve-gate` skill 참고). +- **롤링 태그를 쓰지 않는다.** 같은 앱 버전이라도 베이스 업데이트 결과가 시점마다 달라 + 태그에 빌드일을 포함한다(예: `1.30.0-security-hardened-20260804`). + +## 마무리 + +카탈로그 values(`custom-values.yaml`/`dip-values.yaml`) 태그 갱신은 +`scripts/build/patch-catalog-tag.py`가 한다. 조사·결정 근거는 PR 설명과 +[MEMORY.md](../../../MEMORY.md)에 남긴다. `images/**`+`manifests/helm/**` 변경은 PR로만 반영한다. diff --git a/CLAUDE.md b/CLAUDE.md index dd44d28..77367ba 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -126,6 +126,13 @@ python3 agent/update_catalog/skills/helm_diff/scripts/run.py \ | Skill | 용도 | |-------|------| | [chart-to-cnpg](.claude/skills/chart-to-cnpg/SKILL.md) | 카탈로그 차트의 내장 bitnami postgresql 서브차트를 전용 cnpg-cluster로 전환 | +| [catalog-update-pipeline](.claude/skills/catalog-update-pipeline/SKILL.md) | 차트 신규 버전 감지 → diff → breaking 판정 → 문서 생성 파이프라인 실행 (`agent/update_catalog`) | +| [sbom-cve-gate](.claude/skills/sbom-cve-gate/SKILL.md) | SBOM 생성·CVE 스캔·게이트 판정 실행 및 결과 해석 (`scripts/pipeline`) | +| [self-build-image](.claude/skills/self-build-image/SKILL.md) | 자체 빌드 하드닝 이미지 추가·변경 (`scripts/build`, `images/`) | + +각 Skill 은 절차 본문을 복제하지 않고 권위 있는 문서(`doc/sbom-pipeline.md`, +`.claude/image-authoring.md` 등)를 가리킨다 — 문서가 단일 출처이고, Skill 은 **실행 계약과 +문서가 놓치기 쉬운 함정·현재 상태**만 담는다. 관련 참조 문서(Skill이 절차의 단일 출처로 삼는다): [deploy-test-procedure.md](.claude/deploy-test-procedure.md) ·