RATATOSKRATATOSK
로그인

REST API

이 페이지는 change(데이터 이해하기)를 프로그램에서 직접 조회하는 읽기 전용 공개 API /v1의 사용법을 설명합니다.

사전 준비

  • 필요한 것은 curl 하나뿐입니다. 인증도 API 키도 가입도 필요 없습니다.
  • 제한: IP당 분당 1200회. 초과하면 429가 돌아오고, 몇 초 뒤에 다시 시도하면 되는지 Retry-After 헤더가 알려 줍니다.
  • 모든 시간은 UTC, 응답은 JSON입니다.
  • 전체 명세는 API가 스스로 제공합니다. https://ratatosk.io/v1을 열면 엔드포인트·파라미터·예시가 한 화면에 나옵니다.

change의 생김새

여기서 돌아오는 것은 전부 change입니다. change 하나는 릴리스가 한 일 하나이고, 걸러 내고 판단할 수 있는 축 세 개를 함께 답니다.

무엇에 답하나
family security breaking deprecated 어떤 종류인가 — 사람이 구독할 때 고르는 축
bucket action check plan other 지금 어떻게 행동할 것인가
applies_if 불리언 식 나에게 해당하는가

라우팅의 기준은 bucket입니다. action은 그 버전을 쓰는 모든 설치에 해당합니다. checkapplies_if가 내 설정과 맞을 때만 해당하므로, 무언가를 권하기 전에 그 조건부터 확인해야 합니다. plan은 앞으로 예고된 것이고, other는 전수 기록 — 봇 의존성 범프와 일상적인 줄이라 기본적으로 빠집니다.

bucket웹 화면·주간 메일과 같은 규칙으로 서버가 계산해 실어 보냅니다. 그래서 세 표면이 같은 수를 답합니다. 다른 필드로 다시 계산하지 마세요.

엔드포인트

경로 용도
GET /v1 자기서술 인덱스 — 전체 엔드포인트·파라미터·예시
GET /v1/changes 증분 동기화 피드. project family bucket actionability evaluable since limit 필터. limit은 1~200 (기본 50)
GET /v1/changes/by-entity 역인덱스: 식별자 하나(CVE·CRD·플래그 등)를 건드린 모든 change. 파라미터: name(필수)·kind
GET /v1/matters/{key} 한 사안이 등장한 릴리스 전부, 오래된 것부터. ?include=all이면 note급 기록까지
GET /v1/projects 추적 프로젝트 전목록. 필드는 아래 "프로젝트 메타데이터" 참조
GET /v1/releases/{project}/{version} 릴리스 하나: 봉투 + 그 릴리스의 change 전부. include=raw로 원문(raw_notes) 포함, 잘린 경우 raw_notes_truncated: true. 원문에는 출처 귀속 고지 raw_notes_notice가 함께 옵니다 — 원문을 재게시한다면 그대로 표기하세요
GET /v1/releases/{project} 그 프로젝트의 최신 분석 릴리스 (버전 생략)
GET /v1/releases/{project}?limit=N 최신 릴리스 N개 요약 — 최신순 조회 경로 (1~20, 범위 밖은 조용히 보정)
GET /v1/upgrade/{project}?from=&to= 업그레이드로 떠안는 것 전체. 릴리스 갈래를 가로질러 matter_key 단위로 접습니다. tofrom보다 위여야 함(같거나 아래면 빈 구간 → 400), to 생략 시 최신까지 전부. 버전이 서버로 전송됨 — 아래 "버전 정보 노출 범위 선택" 참조

예시

이 페이지의 응답 예시는 모두 2026-08-10에 실제로 받은 응답을 줄인 것입니다(생략한 자리는 ). 데이터는 계속 늘어나므로 지금 실행하면 건수와 값이 다를 수 있습니다.

모두에게 해당하는 보안 change:

curl "https://ratatosk.io/v1/changes?family=security&bucket=action&limit=2"
{
  "changes": [
    {
      "change_id": "argo:v3.5.0:c140f331",
      "matter_key": "argo/dependency/formidable#value_changed",
      "project": "argo",
      "version": "v3.5.0",
      "version_rank": [3, 5, 0],
      "family": "security",
      "actionability": "act",
      "bucket": "action",
      "kind": "value_changed",
      "applies_if": { "evaluable": false, "mode": "universal", "clauses": [], "raw": null },
      "advisories": [],
      "subjects": [ { "kind": "dependency", "name": "formidable", … } ],
      "quote": "chore(deps): update dependency formidable to v2.1.3 [security]",
      "source_url": "https://github.com/argoproj/argo-cd/releases/tag/v3.5.0",
      "seq": 1415
    },
    … 1건 더 …
  ],
  "next_since": 1421
}

특정 CVE를 다룬 change 찾기 — 한 번의 호출로 전 프로젝트를 가로지릅니다:

curl "https://ratatosk.io/v1/changes/by-entity?name=CVE-2026-41178"
{
  "changes": [
    {
      "change_id": "buildpacks:v0.40.9:83576398",
      "matter_key": "buildpacks/advisory:cve-2026-41178",
      "project": "buildpacks",
      "version": "v0.40.9",
      "family": "security",
      "bucket": "action",
      "advisories": [
        { "id": "CVE-2026-41178", "severity": "medium" },
        { "id": "GO-2026-5158", "severity": "medium" }
      ],
      "subjects": [
        { "kind": "dependency", "name": "go.opentelemetry.io/otel", … },
        { "kind": "cve", "name": "cve-2026-41178", "name_full": "CVE-2026-41178", … }
      ],
      …
    }
  ]
}

이름이 모호하면 kind로 좁힙니다. 값과 뜻은 데이터 이해하기에 있습니다:

curl "https://ratatosk.io/v1/changes/by-entity?name=challenges.acme.cert-manager.io&kind=crd"

최신 릴리스 요약 — 버전마다 층별·가족별 건수가 함께 옵니다:

curl "https://ratatosk.io/v1/releases/istio?limit=3"
{
  "project": "istio",
  "count": 3,
  "releases": [
    {
      "version": "1.29.6",
      "version_rank": [1, 29, 6],
      "released_at": "2026-07-16T16:51:06.000Z",
      "reviewed_at": "2026-08-09T04:33:14.694Z",
      "changes_total": 0,
      "by_bucket": {},
      "by_family": {},
      "max_severity": null,
      "notes_total": 5,
      "api_url": "https://ratatosk.io/v1/releases/istio/1.29.6"
    },
    … 2건 더 …
  ]
}

changes_total: 0인데 notes_total: 5인 것은 감사 가능한 침묵입니다. 릴리스를 읽었고, 다섯 줄을 기록했고, 그중 당신이 할 일은 없다는 뜻입니다. 빈칸이 아니라 답입니다.

업그레이드로 떠안는 것 전부:

curl "https://ratatosk.io/v1/upgrade/istio?from=1.27.0&to=1.27.7"
{
  "project": "istio",
  "from": "1.27.0",
  "to": "1.27.7",
  "releases_covered": ["1.27.6", "1.27.7"],
  "changes_total_before_dedupe": 5,
  "changes": [
    {
      "change_id": "istio:1.27.7:8a66e585",
      "matter_key": "istio/advisory:cve-2025-61732",
      "family": "security",
      "bucket": "action",
      "kind": "defect_corrected",
      "advisories": [ { "id": "CVE-2025-61732", "severity": "high" } ],
      "quote": "- CVE-2025-61732 (CVSS score 8.6, High): A discrepancy between how Go and C/C++ …",
      …
    },
    … action → check → plan 순으로 더 …
  ],
  "privacy": "The versions sent in from/to reach this server (they are not written to access logs — …",
  …
}

한 사안을 릴리스 너머로 추적하기

matter_key는 그 밑에 깔린 사안의 정체성이고, 릴리스와 갈래를 가로질러 유지됩니다. /v1/matters/{key}는 최신 하나가 아니라 등장한 모든 릴리스를 오래된 것부터 돌려줍니다:

curl "https://ratatosk.io/v1/matters/containerd%2Fadvisory%3Acve-2026-47262"

키는 change에서 그대로 복사해 URL 인코딩하세요 — 대소문자를 구분하고 /:를 포함합니다.

왜 전부를 싣는가: 같은 containerd 보안 롤업이 다섯 갈래에 각각 권고 2건·4건· 10건을 달고 착지했습니다. 최신 하나만 보여 주면, 2건짜리 갈래를 쓰는 사람은 자기가 다 덮인 줄 알게 됩니다.

이 change가 나에게 해당하는지 판단하기

applies_if는 문장이 아니라 불리언 식입니다:

"applies_if": {
  "evaluable": true,
  "mode": "any_of",
  "clauses": [
    { "kind": "api", "name": "ScheduleJobAlpha1", "verb": "uses", "polarity": "present" }
  ],
  "raw": null
}

evaluabletrue면 문장을 해석하는 대신 절(clause)을 내 매니페스트와 대조하면 됩니다. modeall_of·any_of·universal(전원 해당)이고, 각 절이 찾아볼 대상을 지목합니다. evaluablefalseraw에 원문 문장이 담깁니다 — 없는 구조를 지어내는 대신 없다고 밝힙니다.

기계로 판정 가능한 것만 보려면 ?evaluable=true로 거르세요.

심각도 판단

심각도는 change가 아니라 인용된 권고에 붙습니다. advisories의 각 항목은 분석 시점에 굳은 값이 아니라 공식 출처에서 다시 읽은 현재 값을 답니다. 릴리스 요약은 그중 최고치를 max_severity로 내보냅니다.

advisories: []는 "등급 없음"이 아니라 릴리스 노트가 권고 식별자를 대지 않았다는 뜻입니다.

증분 조회

/v1/changesseq 오름차순 — 분석이 오래된 것부터입니다. 그래서 첫 페이지는 최신 데이터가 아닙니다. 응답의 next_since를 다음 요청의 since로 넘기면 새로 생긴 것만 받습니다:

# 1회차: 처음부터
curl "https://ratatosk.io/v1/changes?limit=100"
# → { "changes": [ ... ], "next_since": 295 }

# 2회차: 받은 next_since를 since로
curl "https://ratatosk.io/v1/changes?limit=100&since=295"
# → { "changes": [ ... ], "next_since": 398 }

next_since는 그 페이지 마지막 change의 seq입니다 — 개수도 offset도 아닙니다. 시퀀스 번호는 연속하지 않으므로 직접 계산하지 말고 받은 값을 그대로 돌려주세요. next_sincenull로 오면 더 받을 것이 없다는 뜻, 즉 로컬 사본이 최신이라는 뜻입니다. since=null은 보내지 마세요 — 400입니다.

bucket=other 행은 요청하지 않으면 빠집니다. 기록의 대부분이고 대개 의존성 범프입니다.

이 커서는 로컬 사본을 맞춰 두기 위한 것입니다. "X의 최신 릴리스"를 알고 싶다면 /v1/releases/{project}를 쓰세요.

프로젝트 메타데이터

GET /v1/projects의 각 항목은 slug·name·tier·categoryanalyzed_releases(분석된 릴리스 수)를 담고, 여기에 다음 필드가 더해집니다.

  • image_aliases: 이 프로젝트의 컨테이너 이미지가 클러스터에서 쓰는 다른 이름들. 돌고 있는 이미지 이름을 슬러그로 되짚을 때 씁니다.
  • cluster_core: true: 클러스터 자체가 딛고 선 구성요소(컨트롤 플레인· 데이터스토어·DNS·런타임·CNI/데이터플레인) 표시. 내 스택에 없더라도 확인할 가치가 있습니다.
  • visibility: 일부 항목에만 있는 관측 힌트. 그 구성요소가 평범한 조회로는 안 보일 수 있다고 알려 줍니다 — 예컨대 etcd는 쿠버네티스 API 밖에서 돌 수 있습니다.

응답에서는 이렇게 보입니다:

{
  "projects": [
    …
    { "slug": "envoy", "name": "Envoy", "tier": "graduated",
      "category": "networking", "analyzed_releases": 22,
      "image_aliases": ["cilium-envoy"], "cluster_core": true },
    …
  ],
  "count": 76
}

버전 정보 노출 범위 선택

"업그레이드하면 무엇을 떠안는가"에 답하는 길은 하나가 아니고, 내 설정이 서버에 얼마나 닿는지가 다릅니다. 전체 비교는 MCP 서버에 있고, 이 API 안에는 두 가지 선택지가 있습니다.

  • 로컬 구간 비교: change를 받아 version_rank로 직접 비교합니다. 버전이 내 기기를 떠나지 않습니다. version_rank는 표기법에 무관한 정렬용 숫자 배열로, v0.42.0[0, 42, 0]이 됩니다. 규칙은 이렇습니다 — 그 순위가 현재 버전보다 크고 목표 버전 이하이면 그 change는 구간에 듭니다.
  • /v1/upgrade: 서버가 구간을 계산해 줍니다. from/to 버전이 서버에 닿지만 처리 중 메모리만 거치고 접근 로그에는 쓰이지 않습니다 — 쿼리는 로깅 전에 제거되고, 경로는 접두사로 정규화되며, IP는 마스킹됩니다 (개인정보 처리방침). 응답의 privacy 필드가 이 처리를 명시합니다.

손으로 해 보면 이렇습니다:

{ "change_id": "istio:1.27.7:8a66e585", "project": "istio",
  "version": "1.27.7", "version_rank": [1, 27, 7], … }

내 버전이 [1, 27, 0]이고 목표가 [1, 27, 7]이면 [1, 27, 0] < [1, 27, 7] ≤ [1, 27, 7] — 이 change는 구간 안입니다.

프로젝트의 태그를 숫자로 정렬할 수 없으면 version_ranknull입니다 (모노레포 태그 flagd/v0.16.1, 채널 태그 lts-4081.3.8 등). 짐작하는 대신 구간 비교에서 제외합니다.

그 밖의 기계 판독 엔드포인트

  • /md (마크다운 협상): 홈·/releases·릴리스 상세를 Accept: text/markdown 헤더로 요청하면 HTML 대신 마크다운이 옵니다. 에이전트가 파싱하기 쉽습니다.
  • /.well-known/api-catalog: 이 사이트가 제공하는 API의 기계 판독 카탈로그 (RFC 9727).
  • /.well-known/mcp/server-card.json: MCP 서버 카드 — 에이전트가 MCP 서버를 기계적으로 발견할 때 쓰는 표준 문서. MCP 서버 참조.

문제 해결

  • 404 (버전 태그): 프로젝트마다 v 접두사가 다릅니다(envoy는 v1.39.0, istio는 1.28.9). /v1/releases/{project}/{version}은 두 표기를 모두 받지만, 그래도 태그가 틀리면 404 응답 본문에 그 프로젝트의 최근 분석 태그가 담겨 옵니다. 그중 하나를 그대로 다시 쓰세요.
  • 404 (사안 키): matter_key/:를 포함하고 대소문자를 구분합니다. URL 인코딩하고, change에서 그대로 복사하세요.
  • 429: 분당 1200회 제한을 넘겼습니다. Retry-After 헤더의 초만큼 기다렸다가 다시 시도하세요. 요청 수를 줄이려면 next_since 커서로 증분만 받으면 됩니다 — 매번 전체를 다시 받는 것보다 훨씬 적습니다.
  • 모르는 프로젝트 슬러그: 먼저 GET /v1/projects를 확인하세요. 돌고 있는 이미지 이름과 슬러그가 다르면 image_aliases에서 그 이미지 이름을 찾으세요.
  • 결과가 비어 이상해 보일 때: bucket=other는 기본적으로 빠집니다. 전수 기록이 필요하면 actionability=note 또는 bucket=other를 붙이세요.

이용 조건

분석은 AI가 생성하며 무보증으로 제공됩니다. 모든 분석은 근거가 된 출처로 연결됩니다. 이용약관을 참고하세요.