Files
koseokmin ad7fccbed1 Tool inputSchema에 참조·정규식 정책을 적용한다
매니페스트가 선언한 inputSchema는 외부가 정하는 입력이다. JSON Schema
검증기는 문서 밖 $ref를 만나면 그 주소로 직접 조회하므로 매니페스트가
서버의 outbound 호출 대상을 정하는 통로가 된다. pattern은 joni와
graal-js가 없어 java.util.regex의 백트래킹 경로로 처리되고, 인증이 없는
경계(ADR-0006)라 호출 빈도를 줄여 주는 계층도 없다.

ToolSchemaReferencePolicy가 문서 밖 참조와 미지원 dialect를 막고,
ToolSchemaPatternPolicy가 정규식 길이·무한 수량자 개수·중첩 반복을
검사하며 pattern을 쓰는 필드에 maxLength를 요구한다. 길이를 묶을 수
없는 patternProperties는 거부한다.

검사는 ToolMetadata의 표준 생성자 한 곳에서만 한다. Portal 매니페스트
파싱, local 파일 로딩, Redis snapshot 역직렬화가 모두 이 생성자를
지나므로 조회 경로가 늘어도 검사 지점은 하나로 남는다. 위반은
IllegalStateException이라 기존 매니페스트 형식 오류와 같게 다뤄지고
bundle 단위 실패 격리가 그대로 적용된다.

근거와 한계는 ADR-0011, ADR-0012에 있다. ADR-0012가 classpath 근거로
인용하는 docs/sbom도 함께 가져온다.

192개 테스트 전부 통과. 기존 169건은 새 검사에 걸리지 않는다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 17:20:50 +09:00
..

SBOM — AXHUB MCP&Tool Service

  • 산출물: AXHUB_MCP_Tool_Service_SBOM_CycloneDX1.5.json (CycloneDX 1.5 정본), AXHUB_MCP_Tool_Service_SBOM_CycloneDX1.5.xlsx (검토용)
  • 대상: AXHUB MCP Server와 Tool Service의 공통 스택 (Java 21 / Spring Boot 3.5.11)
  • 산출 기준 빌드: ax-hub-mcp-server@0.1.0
  • 생성 기준일: 2026-08-18

대상 범위

MCP Server와 Tool Service는 같은 기술 스택과 같은 MCP SDK를 쓰므로 이 SBOM을 공통으로 적용한다. build.gradle이 직접 선언한 오픈소스는 io.modelcontextprotocol.sdk:mcp-json-jackson2:2.0.0 하나이며, 이 SBOM은 그 런타임 전이 의존 전체빌드 환경을 담는다. Spring Boot starter 계열(web / validation / data-redis / actuator)은 glow f/w가 제공하는 플랫폼 구성이라 범위 밖이다.

다만 목록은 MCP Server 빌드(ax-hub-mcp-server@0.1.0) 하나에서 산출했다. Tool Service가 이 스택 밖의 의존(예: DB 드라이버, 연계 라이브러리)을 추가하면 그만큼은 이 SBOM에 없으므로, 해당 빌드에서 다시 산출해 합쳐야 한다.

구분 개수 내용
런타임 의존성 (scope: required) 12 실행 산출물 classpath에 올라가는 라이브러리
빌드 환경 (scope: optional) 2 JDK 21, Gradle 8.14.3
합계 14

라이선스는 Apache-2.0 9건, MIT 3건, MIT-0 1건, GPL-2.0 with Classpath Exception 1건(JDK)이다. 라이브러리 12건은 모두 permissive이고, copyleft는 JDK 하나뿐이다. JDK는 Classpath Exception이 있어 이 JDK로 실행하는 애플리케이션에 소스 공개 의무가 생기지 않는다.

JDK 배포판은 표준가이드가 정한 Eclipse Temurin (openjdk21u-jdk_x64_windows_hotspot_21.0.5)이며, build.gradle의 toolchain에 vendor = JvmVendorSpec.ADOPTIUM으로 고정해 다른 배포판으로 빌드되지 않게 했다. 실행 컨테이너도 같은 계열인 eclipse-temurin:21-jre를 쓴다.

제외 항목

제외 항목과 사유는 엑셀 Exclusions 시트가 정본이다. 요약하면 다음과 같다.

  • test scope와 annotationProcessor — 선언 4건. 산출물에 포함되지 않는다.
    • spring-boot-starter-test, com.squareup.okhttp3:mockwebserver:4.12.0, org.junit.platform:junit-platform-launcher (test scope)
    • org.springframework.boot:spring-boot-configuration-processor (annotationProcessor)
  • joni, graal-js, graal-sdk — json-schema-validator의 optional. ECMA262 정규식 검증을 쓰지 않아 해석되지 않으므로 약 50MB가 빠진다.
  • jakarta.servlet-api:6.1.0 — mcp-core의 provided. 산출물에 포함되지 않고 서블릿 컨테이너가 제공한다.
  • mcp:2.0.0(aggregate), mcp-json-jackson3:2.0.0 — Jackson 3 경로를 쓰지 않아 선언하지 않는다. 자세한 배경은 mcp-java-sdk-adoption.md 참고.

산출 방법과 한계

버전과 해시는 build.gradle 선언에서 출발해 Gradle 로컬 캐시의 실제 pom을 따라가 그래프를 만들고, 캐시된 실제 jar 바이너리에서 SHA-512 / SHA-1을 직접 계산했다. Gradle 배포본의 SHA-256은 wrapper의 distributionSha256Sum 값을 그대로 옮겼다.

gradlew dependencies로 해석 결과를 대조하려 했으나 sandbox에서 gradle daemon이 뜨지 않아 (Unable to establish loopback connection) 실행하지 못했다. 따라서 다음 버전 정렬은 pom과 Spring Boot BOM 판독에 근거한 것이며, 빌드 환경에서 한 번 확인해야 한다.

./gradlew dependencies --configuration runtimeClasspath
컴포넌트 pom 요청 버전 수록 버전 근거
jackson-databind 2.20.1 (mcp-json-jackson2) 2.19.4 Spring Boot 3.5.11 → jackson-bom 2.19.4
jackson-databind 2.18.3 (json-schema-validator) 2.19.4 위와 동일
reactor-core 3.7.0 (mcp-core) 3.7.16 Spring Boot 3.5.11 → reactor-bom 2024.0.15
slf4j-api 2.0.16 (mcp-core) 2.0.17 Spring Boot 3.5.11 관리 버전

가장 확인이 필요한 항목은 jackson-databind다. SDK가 요청한 2.20.1이 io.spring.dependency-management에 의해 2.19.4로 내려가므로, initialize / tools/list / tools/call 직렬화 계약 테스트로 동작을 확인한다.

CycloneDX 1.5 공식 JSON Schema 원본 대조는 폐쇄망이라 수행하지 않았다. 대신 생성 시점에 dependencies의 모든 ref / dependsOn이 실재하는 bom-ref를 가리키는지, 컴포넌트가 빠짐없이 dependencies에 등장하는지 구조 점검을 통과시켰다.