배지 정책
README의 동적 배지 소스와 정적 배지 소스를 지정합니다. GitHub 네이티브 워크플로 상태, shields.io 엔드포인트 JSON, 정적 배지 형식을 다룹니다.
이 문서는 README 배지 스트립과, 그 동적 데이터 소스를 게시하는 인프라에 대한 표준 참조입니다. 프로젝트 README의 모든 배지는 여기에서 지정하는 세 가지 형식 중 하나를 통해 해석됩니다. 앞으로 추가되는 새 배지는 같은 형식을 따르며, 그렇지 않으면 검토에서 거부됩니다.
1. 배경
정적 https://img.shields.io/badge/X-Y-Z URL은 스스로 절대 바뀌지 않으므로
프로젝트의 실제 상태와 점점 어긋납니다. release-vN-blue 배지는 vN+1이
배포된 뒤에도 오랫동안 계속 vN을 표시합니다. 그래서 이 정책은 바뀌는 모든
값에 동적 형식을 요구하고, 정적 배지는 거의 바뀌지 않아 정적 형식이 정직한
소수의 값(라이선스, Python 대상 버전)에만 사용합니다.
2. 아키텍처
네 가지 형식이 프로젝트의 모든 배지를 다룹니다.
- GitHub 네이티브 워크플로 상태 배지. 워크플로의 배지 URL은
https://github.com/<owner>/<repo>/actions/workflows/<file>/badge.svg형태이며, 기본 브랜치의 최신 실행을 반영합니다. GitHub는 저장소의 공개 메타데이터로 배지를 제공합니다. - shields.io 엔드포인트 배지. shields.io 엔드포인트 배지는
https://img.shields.io/endpoint?url=<published-json>URL을 해석하며, 이때 JSON은 shields.io 엔드포인트 스키마(schemaVersion,label,message,color)를 따릅니다. 게시된 JSON은apothem.ahmedgad.com/badges/*.json에 있으며, 그 내용은 CI 실행이 성공할 때마다 CI 워크플로가 생성합니다. 엔드포인트 배지는 지표를 서드파티의 변경 가능한 저장소가 아니라 프로젝트가 제어하는 게시 경로에 둡니다. - shields.io 정적 배지. 정적 배지는
https://img.shields.io/badge/<label>-<message>-<color>형태이며, 반응하는 데이터 소스가 없습니다. 실제로 거의 바뀌지 않는 값(라이선스 식별자, Python 대상 버전)에만 사용합니다. - 레지스트리 및 스코어카드 배지. 서드파티가 이미 보유한 공개 데이터로 값을 계산하는 배지입니다. npm 레지스트리(버전과 다운로드 수이며, shields.io가 렌더링)와 OpenSSF Scorecard API가 여기에 해당합니다. 프로젝트는 이 배지들을 위해 아무것도 게시하지 않으며, 서드파티가 소스입니다.
프로젝트 지표를 공개 Gist로 게시하는 방식은 설계상 제외됩니다. 프로젝트가 제어하는 도메인을 통한 shields.io 엔드포인트가 표준 대체 수단입니다.
3. 배지별 사양
이 표는 README 배지 스트립을 순서대로 나열합니다. 마지막 열은 저장소가 공개 상태일 때만 이미지가 렌더링되는 배지를 표시합니다. GitHub는 비공개 저장소의 워크플로 배지를 로그인한 멤버에게만 제공하며, Scorecard는 공개 저장소만 스캔합니다.
| 배지 | 형식 | 소스 | URL 형태 | 공개 저장소 필요 |
|---|---|---|---|---|
| 최신 릴리스 | shields.io 엔드포인트 | badges/release.json | https://img.shields.io/endpoint?url=https%3A%2F%2Fapothem.ahmedgad.com%2Fbadges%2Frelease.json | 아니요 |
| CI 상태 | GitHub 네이티브 | .github/workflows/ci.yml | https://github.com/ahmed-g-gad/apothem/actions/workflows/ci.yml/badge.svg?branch=main | 예 |
| 라이선스 | shields.io 정적 | LICENSE (MIT) | https://img.shields.io/badge/license-MIT-0F172A | 아니요 |
| npm 버전 | 레지스트리 | npm 레지스트리 | https://img.shields.io/npm/v/%40ahmed-g-gad%2Fapothem?color=10B981&label=npm | 아니요 |
| 커버리지 게이트 | shields.io 정적 | pyproject.toml fail_under = 80 | https://img.shields.io/badge/coverage%20gate-%E2%89%A580%25-2563EB | 아니요 |
| OpenSSF Scorecard | 스코어카드 | .github/workflows/scorecard.yml 결과 | https://api.securityscorecards.dev/projects/github.com/ahmed-g-gad/apothem/badge | 예 |
| 피드백 | shields.io 정적 | GitHub Issues | https://img.shields.io/badge/feedback-GitHub%20issues-7C3AED | 아니요 |
| 문서 | shields.io 정적 | 문서 사이트 | https://img.shields.io/badge/docs-Fumadocs-0F172A | 아니요 |
| npm 다운로드 | 레지스트리 | npm 레지스트리 | https://img.shields.io/npm/dm/%40ahmed-g-gad%2Fapothem?color=10B981&label=downloads | 아니요 |
github.com을 가리키는 모든 배지의 링크 대상(릴리스, 워크플로, 라이선스 파일,
이슈)은 저장소가 공개 상태일 때만 열립니다.
배지 워크플로는 향후 배지를 위해 coverage.json, security.json,
supply-chain.json, docs.json 엔드포인트 파일도 게시합니다. 현재 README는
이 파일들을 표시하지 않습니다.
CodeQL은 Python과 Actions 표면을 분석하는 전용
.github/workflows/codeql.yml 워크플로로 실행됩니다. ci.yml의
security-scan 작업은 bandit만 실행하고, CodeQL SARIF 게시는 codeql.yml에
맡깁니다. 보안 배지는 GitHub 네이티브 워크플로 배지 대신 배지 워크플로가
게시하는 엔드포인트 JSON을 사용하므로, 기반 스캐너 구성이 바뀌어도 배지는
안정적으로 유지됩니다.
4. JSON 게시 메커니즘
엔드포인트 JSON은 .github/workflows/badges.yml이 생성합니다. 이 워크플로는
다음을 수행합니다.
ci워크플로가 완료된 뒤workflow_run으로 트리거됩니다(CI 실행 없이 다시 게시하려면 수동workflow_dispatch로도 트리거됩니다).- 전체 이력 체크아웃(
fetch-depth: 0)에서git describe --tags --abbrev=0 --match 'v[0-9]*.[0-9]*.[0-9]*'로 최신 릴리스 태그를 해석하고(깊이 1 체크아웃에서는 태그가 달린 커밋에 도달할 수 없어 배지가unreleased를 표시합니다),workflow_run이벤트에서 상위 CI 결론을 해석합니다. - 출력이 shields.io 엔드포인트 스키마(
schemaVersion: 1과label,message,color)와 엄격하게 일치하도록 각 JSON을jq -n으로 생성합니다. - 업로드 전에 생성된 모든 JSON을
jq -e로 검증합니다. - 디렉터리를
badges라는 이름의 워크플로 아티팩트로 업로드합니다.
아티팩트를 apothem.ahmedgad.com/badges/에 배포하는 작업은
.github/workflows/publish-static-site.yml이 처리합니다. 사이트 빌드 중에 이
워크플로는 성공한 최신 badges 아티팩트를 다운로드하여 site/dist/badges/
아래에 스테이징합니다. 아티팩트가 없거나 만료된 경우에도 사이트는 배포되며,
깨진 JSON을 게시하는 대신 배지 아티팩트 누락을 워크플로 로그에 기록합니다.
5. 유지 관리 프로토콜
새 배지를 추가할 때는 형식부터 정합니다.
- 배지가 CI 워크플로의 실행 상태를 반영한다면 GitHub 네이티브 형식을 우선하세요. 배지의 URL은 워크플로 파일로 고정되며, 게시 인프라가 필요하지 않습니다.
- 배지가 시간에 따라 갱신되는 지표(개수, 백분율, 버전 문자열, 등급 레이블)를
반영한다면 shields.io 엔드포인트 형식을 사용하세요.
.github/workflows/badges.yml에 기존 다섯 개와 나란히 JSON 생성 단계를 추가하고,apothem.ahmedgad.com/badges/<name>.json소비자 URL을 README 배지 스트립에 추가하세요. - 배지가 실제로 거의 바뀌지 않는 값(라이선스, 대상 언어, 거버넌스 모드)을 반영한다면 shields.io 정적 형식을 사용하세요. 배지를 추가할 때 이 파일의 배지별 표에 변경 주기를 문서화하세요.
배지를 폐기할 때는 먼저 README에서 배지를 제거하고, 그다음 배지 워크플로에서 해당 JSON 생성 단계를 제거하고, 마지막으로 위의 배지별 표에서 해당 행을 제거하세요. README가 워크플로가 생성하지 않는 JSON 아티팩트를 절대 참조하지 않도록 삭제를 원자적으로 수행하세요.
6. 상호 참조
- GitHub 네이티브 CI 배지가 실행 상태를 반영하는 CI 워크플로:
.github/workflows/ci.yml. - 엔드포인트 JSON을 게시하는 배지 워크플로:
.github/workflows/badges.yml. - JSON을 제공하는 정적 사이트 도메인:
apothem.ahmedgad.com. - shields.io 엔드포인트 스키마 참조: https://shields.io/badges/endpoint-badge.