diff --git a/ssrf-guard-demo/README.ko.md b/ssrf-guard-demo/README.ko.md index 2d7d959..b557e07 100644 --- a/ssrf-guard-demo/README.ko.md +++ b/ssrf-guard-demo/README.ko.md @@ -6,9 +6,9 @@ 하나의 Spring Boot 앱에 **3종 Spring HTTP 클라이언트**가 모두 동일 `UrlPolicy`를 통해 wiring됨: -- `RestClient` (Spring 6.1+) — 메타 아티팩트 `kr.devslab:ssrf-guard:3.1.0` -- `RestTemplate` — `kr.devslab:ssrf-guard-resttemplate:3.1.0` -- `WebClient` (WebFlux) — `kr.devslab:ssrf-guard-webclient:3.1.0` +- `RestClient` (Spring 6.1+) — 메타 아티팩트 `kr.devslab:ssrf-guard:3.1.1` +- `RestTemplate` — `kr.devslab:ssrf-guard-resttemplate:3.1.1` +- `WebClient` (WebFlux) — `kr.devslab:ssrf-guard-webclient:3.1.1` 추가로 `/attacks` 엔드포인트는 가드가 차단하는 모든 SSRF 우회 패턴 목록을 각 모듈별 curl 예제와 함께 제공합니다. @@ -146,7 +146,7 @@ curl -s http://localhost:8080/actuator/prometheus | grep ssrf_guard | 파일 | 왜 | | --- | --- | -| `build.gradle.kts` | 표준 스타터 외 의존성은 `kr.devslab:ssrf-guard:3.1.0`, `:ssrf-guard-resttemplate:3.1.0`, `:ssrf-guard-webclient:3.1.0` 셋뿐 — 별도 configuration 클래스 불필요 | +| `build.gradle.kts` | 표준 스타터 외 의존성은 `kr.devslab:ssrf-guard:3.1.1`, `:ssrf-guard-resttemplate:3.1.1`, `:ssrf-guard-webclient:3.1.1` 셋뿐 — 별도 configuration 클래스 불필요 | | `application.yml` | 모든 `ssrf.guard.*` 옵션이 한 곳에 주석과 함께 | | `web/FetchController.java` | RestClient 전체 — 3줄 setup, 가드는 보이지 않게 실행 | | `web/FetchResttemplateController.java` | RestTemplate 동일 — 레거시 코드 마이그레이션 불필요 | diff --git a/ssrf-guard-demo/README.md b/ssrf-guard-demo/README.md index 55d343b..a6d135d 100644 --- a/ssrf-guard-demo/README.md +++ b/ssrf-guard-demo/README.md @@ -6,9 +6,9 @@ Runnable example for [`ssrf-guard`](https://github.com/devslab-kr/ssrf-guard) One Spring Boot app shows **all three Spring HTTP clients** wired through the same `UrlPolicy`: -- `RestClient` (Spring 6.1+) via the meta `kr.devslab:ssrf-guard:3.1.0` artifact -- `RestTemplate` via `kr.devslab:ssrf-guard-resttemplate:3.1.0` -- `WebClient` (WebFlux) via `kr.devslab:ssrf-guard-webclient:3.1.0` +- `RestClient` (Spring 6.1+) via the meta `kr.devslab:ssrf-guard:3.1.1` artifact +- `RestTemplate` via `kr.devslab:ssrf-guard-resttemplate:3.1.1` +- `WebClient` (WebFlux) via `kr.devslab:ssrf-guard-webclient:3.1.1` Plus a `/attacks` endpoint that lists every SSRF bypass pattern the guard catches, with copy-paste curls for each. @@ -147,7 +147,7 @@ You'll see counters per `reason` tag (`blocked_host`, `blocked_ip_literal`, `blo | File | Why | | --- | --- | -| `build.gradle.kts` | The only dependencies beyond the standard starters are `kr.devslab:ssrf-guard:3.1.0`, `kr.devslab:ssrf-guard-resttemplate:3.1.0`, `kr.devslab:ssrf-guard-webclient:3.1.0` — no manual configuration class needed | +| `build.gradle.kts` | The only dependencies beyond the standard starters are `kr.devslab:ssrf-guard:3.1.1`, `kr.devslab:ssrf-guard-resttemplate:3.1.1`, `kr.devslab:ssrf-guard-webclient:3.1.1` — no manual configuration class needed | | `application.yml` | Every `ssrf.guard.*` knob in one place with comments | | `web/FetchController.java` | The whole RestClient story — three lines of setup, the guard runs invisibly | | `web/FetchResttemplateController.java` | Same shape for RestTemplate — no migration needed for legacy code | diff --git a/ssrf-guard-demo/build.gradle.kts b/ssrf-guard-demo/build.gradle.kts index d08ee23..18a0f35 100644 --- a/ssrf-guard-demo/build.gradle.kts +++ b/ssrf-guard-demo/build.gradle.kts @@ -26,9 +26,9 @@ dependencies { // The meta `ssrf-guard` artifact transitively pulls in `-core`, `-httpclient5`, // and `-restclient`. The `-resttemplate` and `-webclient` modules are // additive and reuse the same UrlPolicy / SsrfGuardMetrics beans. - implementation("kr.devslab:ssrf-guard:3.1.0") - implementation("kr.devslab:ssrf-guard-resttemplate:3.1.0") - implementation("kr.devslab:ssrf-guard-webclient:3.1.0") + implementation("kr.devslab:ssrf-guard:3.1.1") + implementation("kr.devslab:ssrf-guard-resttemplate:3.1.1") + implementation("kr.devslab:ssrf-guard-webclient:3.1.1") // Micrometer Prometheus registry — turns SSRF Guard's counters into // /actuator/prometheus output so you can curl the metrics in the demo. diff --git a/ssrf-guard-feign-demo/README.ko.md b/ssrf-guard-feign-demo/README.ko.md index 9cde78c..c69aade 100644 --- a/ssrf-guard-feign-demo/README.ko.md +++ b/ssrf-guard-feign-demo/README.ko.md @@ -52,12 +52,12 @@ curl http://localhost:8080/feign/evil | jq | 파일 | 왜 | | --- | --- | -| `build.gradle.kts` | `kr.devslab:ssrf-guard-feign:3.1.0` + `spring-cloud-starter-openfeign` | +| `build.gradle.kts` | `kr.devslab:ssrf-guard-feign:3.1.1` + `spring-cloud-starter-openfeign` | | `HttpBinClient.java` / `EvilClient.java` | 평범한 `@FeignClient` 인터페이스 2개 — 가드 코드 없음 | | `FeignDemoController.java` | `SsrfGuardException` catch (Feign이 한 단계 wrap — 컨트롤러가 unwrap) | | `application.yml` | `ssrf.guard.exact-hosts: [httpbin.org]` — 그 한 줄이 화이트리스트 | -Feign 인터셉터는 자동 등록됨 — `ssrf-guard-feign-3.1.0`이 Spring 자동설정으로 `feign.RequestInterceptor` 빈을 publish하고, Spring Cloud OpenFeign이 모든 `@FeignClient`에 적용. +Feign 인터셉터는 자동 등록됨 — `ssrf-guard-feign-3.1.1`이 Spring 자동설정으로 `feign.RequestInterceptor` 빈을 publish하고, Spring Cloud OpenFeign이 모든 `@FeignClient`에 적용. ## 빌드 검증 diff --git a/ssrf-guard-feign-demo/README.md b/ssrf-guard-feign-demo/README.md index 7469c74..7b4a8f7 100644 --- a/ssrf-guard-feign-demo/README.md +++ b/ssrf-guard-feign-demo/README.md @@ -52,12 +52,12 @@ curl http://localhost:8080/feign/evil | jq | File | Why | | --- | --- | -| `build.gradle.kts` | `kr.devslab:ssrf-guard-feign:3.1.0` + `spring-cloud-starter-openfeign` | +| `build.gradle.kts` | `kr.devslab:ssrf-guard-feign:3.1.1` + `spring-cloud-starter-openfeign` | | `HttpBinClient.java` / `EvilClient.java` | Two normal `@FeignClient` interfaces — no guard code | | `FeignDemoController.java` | Catches `SsrfGuardException` (wrapped one level deep by Feign — the controller unwraps) | | `application.yml` | `ssrf.guard.exact-hosts: [httpbin.org]` — that one line is the whitelist | -The Feign interceptor registers itself automatically — `ssrf-guard-feign-3.1.0` provides a Spring autoconfig that publishes a `feign.RequestInterceptor` bean, which Spring Cloud OpenFeign then applies to every `@FeignClient`. +The Feign interceptor registers itself automatically — `ssrf-guard-feign-3.1.1` provides a Spring autoconfig that publishes a `feign.RequestInterceptor` bean, which Spring Cloud OpenFeign then applies to every `@FeignClient`. ## Verify the build diff --git a/ssrf-guard-feign-demo/build.gradle.kts b/ssrf-guard-feign-demo/build.gradle.kts index da899bc..6aed779 100644 --- a/ssrf-guard-feign-demo/build.gradle.kts +++ b/ssrf-guard-feign-demo/build.gradle.kts @@ -26,7 +26,7 @@ dependencies { implementation("org.springframework.cloud:spring-cloud-starter-openfeign") // The library this demo showcases. Pulls in ssrf-guard-core transitively. - implementation("kr.devslab:ssrf-guard-feign:3.1.0") + implementation("kr.devslab:ssrf-guard-feign:3.1.1") testImplementation("org.springframework.boot:spring-boot-starter-test") testRuntimeOnly("org.junit.platform:junit-platform-launcher") diff --git a/ssrf-guard-httpclient5-demo/README.ko.md b/ssrf-guard-httpclient5-demo/README.ko.md index 74a090e..c98506f 100644 --- a/ssrf-guard-httpclient5-demo/README.ko.md +++ b/ssrf-guard-httpclient5-demo/README.ko.md @@ -82,7 +82,7 @@ curl 'http://localhost:8080/fetch?url=https://evil.com/' | jq | 파일 | 왜 | | --- | --- | -| `build.gradle.kts` | 의존성 둘: `kr.devslab:ssrf-guard-httpclient5:3.1.0` + `org.apache.httpcomponents.client5:httpclient5:5.4.1` | +| `build.gradle.kts` | 의존성 둘: `kr.devslab:ssrf-guard-httpclient5:3.1.1` + `org.apache.httpcomponents.client5:httpclient5:5.4.1` | | `SsrfGuardHttpClient5DemoApplication.java` | `@SpringBootApplication`만. 모듈의 자동 설정이 가드된 `CloseableHttpClient` 빈을 wire — **wiring 코드 0줄**. | | `HttpClient5DemoController.java` | 표준 `client.execute(get, handler)` 호출 — 가드 참조 0 | | `application.yml` | `ssrf.guard.*` 키: 화이트리스트, `block-private-networks`, `follow-redirects`, `allowed-schemes` | diff --git a/ssrf-guard-httpclient5-demo/README.md b/ssrf-guard-httpclient5-demo/README.md index 4f6fae3..60a8d4f 100644 --- a/ssrf-guard-httpclient5-demo/README.md +++ b/ssrf-guard-httpclient5-demo/README.md @@ -82,7 +82,7 @@ Blocked responses look like: | File | Why | | --- | --- | -| `build.gradle.kts` | Two deps: `kr.devslab:ssrf-guard-httpclient5:3.1.0` + `org.apache.httpcomponents.client5:httpclient5:5.4.1` | +| `build.gradle.kts` | Two deps: `kr.devslab:ssrf-guard-httpclient5:3.1.1` + `org.apache.httpcomponents.client5:httpclient5:5.4.1` | | `SsrfGuardHttpClient5DemoApplication.java` | Just `@SpringBootApplication`. The module's autoconfig wires the guarded `CloseableHttpClient` bean — **zero lines of wiring code**. | | `HttpClient5DemoController.java` | Standard `client.execute(get, handler)` call — no reference to the guard at all | | `application.yml` | `ssrf.guard.*` keys: whitelist, `block-private-networks`, `follow-redirects`, `allowed-schemes` | diff --git a/ssrf-guard-httpclient5-demo/build.gradle.kts b/ssrf-guard-httpclient5-demo/build.gradle.kts index 3515281..88d20e5 100644 --- a/ssrf-guard-httpclient5-demo/build.gradle.kts +++ b/ssrf-guard-httpclient5-demo/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { // constructed by hand — see the README's "Without Spring" section. implementation("org.springframework.boot:spring-boot-starter-web") - implementation("kr.devslab:ssrf-guard-httpclient5:3.1.0") + implementation("kr.devslab:ssrf-guard-httpclient5:3.1.1") // The Apache HttpClient 5 runtime. Versions 5.3+ ship the // DnsResolver / RedirectStrategy interfaces the module plugs into. implementation("org.apache.httpcomponents.client5:httpclient5:5.4.1") diff --git a/ssrf-guard-jdkhttp-demo/README.ko.md b/ssrf-guard-jdkhttp-demo/README.ko.md index d95e3f7..fbf2fc6 100644 --- a/ssrf-guard-jdkhttp-demo/README.ko.md +++ b/ssrf-guard-jdkhttp-demo/README.ko.md @@ -55,7 +55,7 @@ curl 'http://localhost:8080/fetch?url=https://evil.com/' | jq | 파일 | 왜 | | --- | --- | -| `build.gradle.kts` | 의존성 하나: `kr.devslab:ssrf-guard-jdkhttp:3.1.0` | +| `build.gradle.kts` | 의존성 하나: `kr.devslab:ssrf-guard-jdkhttp:3.1.1` | | `SsrfGuardJdkHttpDemoApplication.java` | 전체 스토리: `HostPolicy` → `UrlPolicy` → `HttpClient` wrap | | `JdkHttpDemoController.java` | 평범한 `client.send(req, ...)` — 호출부에서 wrap은 보이지 않음 | diff --git a/ssrf-guard-jdkhttp-demo/README.md b/ssrf-guard-jdkhttp-demo/README.md index de8df45..cb4dcba 100644 --- a/ssrf-guard-jdkhttp-demo/README.md +++ b/ssrf-guard-jdkhttp-demo/README.md @@ -55,7 +55,7 @@ curl 'http://localhost:8080/fetch?url=https://evil.com/' | jq | File | Why | | --- | --- | -| `build.gradle.kts` | One dep: `kr.devslab:ssrf-guard-jdkhttp:3.1.0` | +| `build.gradle.kts` | One dep: `kr.devslab:ssrf-guard-jdkhttp:3.1.1` | | `SsrfGuardJdkHttpDemoApplication.java` | The whole story: build `HostPolicy` → `UrlPolicy` → wrap `HttpClient` | | `JdkHttpDemoController.java` | Calls `client.send(req, ...)` like any other HttpClient — the wrap is invisible at the call site | diff --git a/ssrf-guard-jdkhttp-demo/build.gradle.kts b/ssrf-guard-jdkhttp-demo/build.gradle.kts index a8563b1..8386b90 100644 --- a/ssrf-guard-jdkhttp-demo/build.gradle.kts +++ b/ssrf-guard-jdkhttp-demo/build.gradle.kts @@ -23,7 +23,7 @@ dependencies { // dependency itself; the Spring Boot framing is just the demo's UX. implementation("org.springframework.boot:spring-boot-starter-web") - implementation("kr.devslab:ssrf-guard-jdkhttp:3.1.0") + implementation("kr.devslab:ssrf-guard-jdkhttp:3.1.1") // ssrf-guard-core's @ConfigurationProperties pulls in spring-boot // (transitively from -jdkhttp's API), so we get the SsrfGuardProperties // binding for free. diff --git a/ssrf-guard-langchain4j-demo/README.ko.md b/ssrf-guard-langchain4j-demo/README.ko.md index 33c199e..558c279 100644 --- a/ssrf-guard-langchain4j-demo/README.ko.md +++ b/ssrf-guard-langchain4j-demo/README.ko.md @@ -118,7 +118,7 @@ curl -X POST http://localhost:8080/agent/chat \ | 파일 | 왜 | | --- | --- | -| `build.gradle.kts` | 의존성 — `kr.devslab:ssrf-guard-langchain4j:3.1.0` + `dev.langchain4j:langchain4j:1.15.0`. 끝 | +| `build.gradle.kts` | 의존성 — `kr.devslab:ssrf-guard-langchain4j:3.1.1` + `dev.langchain4j:langchain4j:1.15.0`. 끝 | | `application.yml` | `ssrf.guard.langchain4j.wrap-tool-executors=true` — 마스터 스위치 (기본 true, 명시적 표기) | | `agent/FetchUrlTool.java` | 원시 executor — **보안 코드 0줄**. wrap은 빈 후처리 시점에 일어남 | | `agent/FakeLlmService.java` | 가짜 LLM 드라이버. 프로덕션에선 `AiServices` 어시스턴트. 교체, 재컴파일, 끝 | diff --git a/ssrf-guard-langchain4j-demo/README.md b/ssrf-guard-langchain4j-demo/README.md index 62baaaa..7df378a 100644 --- a/ssrf-guard-langchain4j-demo/README.md +++ b/ssrf-guard-langchain4j-demo/README.md @@ -118,7 +118,7 @@ curl -X POST http://localhost:8080/agent/chat \ | File | Why | | --- | --- | -| `build.gradle.kts` | The dependencies — `kr.devslab:ssrf-guard-langchain4j:3.1.0` + `dev.langchain4j:langchain4j:1.15.0`. That's it | +| `build.gradle.kts` | The dependencies — `kr.devslab:ssrf-guard-langchain4j:3.1.1` + `dev.langchain4j:langchain4j:1.15.0`. That's it | | `application.yml` | `ssrf.guard.langchain4j.wrap-tool-executors=true` — the master switch (default true, shown for clarity) | | `agent/FetchUrlTool.java` | The raw executor — note there's **zero** security code here. The wrap happens at bean post-processing time | | `agent/FakeLlmService.java` | The fake-LLM driver. In production this is an `AiServices`-built assistant. Swap, recompile, done | diff --git a/ssrf-guard-langchain4j-demo/build.gradle.kts b/ssrf-guard-langchain4j-demo/build.gradle.kts index 8da7486..78cd209 100644 --- a/ssrf-guard-langchain4j-demo/build.gradle.kts +++ b/ssrf-guard-langchain4j-demo/build.gradle.kts @@ -26,8 +26,8 @@ dependencies { // - ssrf-guard-langchain4j: registers a BeanPostProcessor that wraps every // ToolExecutor bean automatically — the "secure-by-default" pitch // mirrored from ssrf-guard-springai, just for the LangChain4j community. - implementation("kr.devslab:ssrf-guard:3.1.0") - implementation("kr.devslab:ssrf-guard-langchain4j:3.1.0") + implementation("kr.devslab:ssrf-guard:3.1.1") + implementation("kr.devslab:ssrf-guard-langchain4j:3.1.1") // LangChain4j 1.x. We don't actually call an LLM in this demo — the // FakeLlmService stands in for one — but we pull the API in so the diff --git a/ssrf-guard-native-image-demo/README.ko.md b/ssrf-guard-native-image-demo/README.ko.md index db50c08..088a7cb 100644 --- a/ssrf-guard-native-image-demo/README.ko.md +++ b/ssrf-guard-native-image-demo/README.ko.md @@ -2,11 +2,11 @@ [English](README.md) · **한국어** -[`ssrf-guard 3.1.0`](https://github.com/devslab-kr/ssrf-guard)의 **GraalVM 네이티브 이미지 힌트**가 동작함을 end-to-end로 증명 — Spring Boot 앱에 라이브러리 drop, `./gradlew nativeCompile`, 나온 네이티브 바이너리가 JVM 빌드와 동일한 게이트에서 SSRF 시도를 차단. +[`ssrf-guard 3.1.1`](https://github.com/devslab-kr/ssrf-guard)의 **GraalVM 네이티브 이미지 힌트**가 동작함을 end-to-end로 증명 — Spring Boot 앱에 라이브러리 drop, `./gradlew nativeCompile`, 나온 네이티브 바이너리가 JVM 빌드와 동일한 게이트에서 SSRF 시도를 차단. ## 이 데모가 증명하는 것 -ssrf-guard 3.1.0은 각 모듈에서 `META-INF/spring/aot.factories`로 `RuntimeHintsRegistrar` 엔트리를 발행합니다. 커버 범위: +ssrf-guard 3.1.1은 각 모듈에서 `META-INF/spring/aot.factories`로 `RuntimeHintsRegistrar` 엔트리를 발행합니다. 커버 범위: | 타입 | 힌트가 필요한 이유 | | --- | --- | @@ -127,7 +127,7 @@ find build/generated -name 'reflect-config.json' -exec head -30 {} \; | 파일 | 왜 | | --- | --- | -| `build.gradle.kts` | 2줄 셋업: `kr.devslab:ssrf-guard:3.1.0` + `org.graalvm.buildtools.native` plugin | +| `build.gradle.kts` | 2줄 셋업: `kr.devslab:ssrf-guard:3.1.1` + `org.graalvm.buildtools.native` plugin | | `SsrfGuardNativeImageDemoApplication.java` | `@SpringBootApplication` + `RestClient` bean만 — 나머지는 자동 설정 처리 | | `NativeImageDemoController.java` | `/fetch` + `/attacks` — `runtime` 필드 (jvm vs graalvm-native)로 시각적 확인 | | `application.yml` | `ssrf.guard.*` 키 — `@ConfigurationProperties` 바인딩 경로가 AOT 힌트가 필요한 그 경로 | @@ -145,4 +145,4 @@ GraalVM 네이티브 이미지는 JVM cold-start 비용 문제의 답: - Kubernetes pod scale-to-zero - 100 ms 미만 시작 필요한 CLI 도구 -라이브러리 측 힌트 없으면 사용자가 끌어오는 모든 의존성이 네이티브 이미지 지뢰. ssrf-guard 3.1.0은 힌트를 ship해서 사용자가 우리 타입에 대한 `reflect-config.json` 안 쓰고도 `nativeCompile` 가능. +라이브러리 측 힌트 없으면 사용자가 끌어오는 모든 의존성이 네이티브 이미지 지뢰. ssrf-guard 3.1.1은 힌트를 ship해서 사용자가 우리 타입에 대한 `reflect-config.json` 안 쓰고도 `nativeCompile` 가능. diff --git a/ssrf-guard-native-image-demo/README.md b/ssrf-guard-native-image-demo/README.md index 204a9f0..54edf36 100644 --- a/ssrf-guard-native-image-demo/README.md +++ b/ssrf-guard-native-image-demo/README.md @@ -2,11 +2,11 @@ **English** · [한국어](README.ko.md) -End-to-end proof that [`ssrf-guard 3.1.0`](https://github.com/devslab-kr/ssrf-guard)'s **GraalVM native-image hints** work — drop the library into a Spring Boot app, run `./gradlew nativeCompile`, and the resulting native binary blocks SSRF attempts at the same gates the JVM build does. +End-to-end proof that [`ssrf-guard 3.1.1`](https://github.com/devslab-kr/ssrf-guard)'s **GraalVM native-image hints** work — drop the library into a Spring Boot app, run `./gradlew nativeCompile`, and the resulting native binary blocks SSRF attempts at the same gates the JVM build does. ## What this demo proves -ssrf-guard 3.1.0 ships `RuntimeHintsRegistrar` entries through `META-INF/spring/aot.factories` in each module. The hints cover: +ssrf-guard 3.1.1 ships `RuntimeHintsRegistrar` entries through `META-INF/spring/aot.factories` in each module. The hints cover: | Type | Why it needs a hint | | --- | --- | @@ -127,7 +127,7 @@ You should see entries for `UrlPolicy`, `HostPolicy`, `SsrfBlockPayload`, `Block | File | Why | | --- | --- | -| `build.gradle.kts` | The two-line setup: `kr.devslab:ssrf-guard:3.1.0` + `org.graalvm.buildtools.native` plugin | +| `build.gradle.kts` | The two-line setup: `kr.devslab:ssrf-guard:3.1.1` + `org.graalvm.buildtools.native` plugin | | `SsrfGuardNativeImageDemoApplication.java` | Just `@SpringBootApplication` + a `RestClient` bean — autoconfig handles the rest | | `NativeImageDemoController.java` | `/fetch` + `/attacks` — surfaces `runtime` (jvm vs graalvm-native) for visual confirmation | | `application.yml` | `ssrf.guard.*` keys — bound via `@ConfigurationProperties`, which is the path that needs the AOT hints | @@ -145,4 +145,4 @@ GraalVM native images are the answer to JVM cold-start cost in: - Kubernetes pods that scale to zero - CLI tools that need to start in <100 ms -Without library-side hints, every dependency the consumer pulls in is a potential native-image landmine. ssrf-guard 3.1.0 ships the hints so consumers can `nativeCompile` without writing `reflect-config.json` for our types. +Without library-side hints, every dependency the consumer pulls in is a potential native-image landmine. ssrf-guard 3.1.1 ships the hints so consumers can `nativeCompile` without writing `reflect-config.json` for our types. diff --git a/ssrf-guard-native-image-demo/build.gradle.kts b/ssrf-guard-native-image-demo/build.gradle.kts index d5507ce..c2f82bb 100644 --- a/ssrf-guard-native-image-demo/build.gradle.kts +++ b/ssrf-guard-native-image-demo/build.gradle.kts @@ -4,7 +4,7 @@ plugins { id("io.spring.dependency-management") version "1.1.7" // GraalVM Native Image — provides `nativeCompile` + `nativeRun` tasks, // and the `processAot` task that exercises every RuntimeHintsRegistrar - // contributed by libraries on the classpath. ssrf-guard 3.1.0 ships + // contributed by libraries on the classpath. ssrf-guard 3.1.1 ships // hints for UrlPolicy / HostPolicy / SsrfBlockPayload / BlockReason // + the LLM JSON-walking path + Micrometer reflective bean; this demo // is the end-to-end proof those hints actually let a native image @@ -32,7 +32,7 @@ dependencies { // hints transitively. Everything ssrf-guard contributes to the native // image (reflection / proxies / resources) flows through this single // dep. - implementation("kr.devslab:ssrf-guard:3.1.0") + implementation("kr.devslab:ssrf-guard:3.1.1") testImplementation("org.springframework.boot:spring-boot-starter-test") testRuntimeOnly("org.junit.platform:junit-platform-launcher") diff --git a/ssrf-guard-okhttp-demo/README.ko.md b/ssrf-guard-okhttp-demo/README.ko.md index 7991e17..c06d405 100644 --- a/ssrf-guard-okhttp-demo/README.ko.md +++ b/ssrf-guard-okhttp-demo/README.ko.md @@ -48,7 +48,7 @@ curl 'http://localhost:8080/fetch?url=https://evil.com/' | jq | 파일 | 왜 | | --- | --- | -| `build.gradle.kts` | `kr.devslab:ssrf-guard-okhttp:3.1.0` + `com.squareup.okhttp3:okhttp:4.12.0` | +| `build.gradle.kts` | `kr.devslab:ssrf-guard-okhttp:3.1.1` + `com.squareup.okhttp3:okhttp:4.12.0` | | `SsrfGuardOkHttpDemoApplication.java` | OkHttp 빌더에 3줄 — `.addInterceptor(...)`, `.dns(...)`, `.followRedirects(...)` | | `OkHttpDemoController.java` | 표준 OkHttp `newCall().execute()` — 호출부에서 wrap은 보이지 않음 | diff --git a/ssrf-guard-okhttp-demo/README.md b/ssrf-guard-okhttp-demo/README.md index 426dbbb..fcec044 100644 --- a/ssrf-guard-okhttp-demo/README.md +++ b/ssrf-guard-okhttp-demo/README.md @@ -48,7 +48,7 @@ curl 'http://localhost:8080/fetch?url=https://evil.com/' | jq | File | Why | | --- | --- | -| `build.gradle.kts` | `kr.devslab:ssrf-guard-okhttp:3.1.0` + `com.squareup.okhttp3:okhttp:4.12.0` | +| `build.gradle.kts` | `kr.devslab:ssrf-guard-okhttp:3.1.1` + `com.squareup.okhttp3:okhttp:4.12.0` | | `SsrfGuardOkHttpDemoApplication.java` | Three lines on the OkHttp builder — `.addInterceptor(...)`, `.dns(...)`, `.followRedirects(...)` | | `OkHttpDemoController.java` | Standard OkHttp `newCall().execute()` — the wrap is invisible at the call site | diff --git a/ssrf-guard-okhttp-demo/build.gradle.kts b/ssrf-guard-okhttp-demo/build.gradle.kts index 53ef3b2..e0ef298 100644 --- a/ssrf-guard-okhttp-demo/build.gradle.kts +++ b/ssrf-guard-okhttp-demo/build.gradle.kts @@ -22,7 +22,7 @@ dependencies { // (ssrf-guard-okhttp) has no Spring dependency. implementation("org.springframework.boot:spring-boot-starter-web") - implementation("kr.devslab:ssrf-guard-okhttp:3.1.0") + implementation("kr.devslab:ssrf-guard-okhttp:3.1.1") implementation("com.squareup.okhttp3:okhttp:4.12.0") testImplementation("org.springframework.boot:spring-boot-starter-test") diff --git a/ssrf-guard-springai-demo/README.ko.md b/ssrf-guard-springai-demo/README.ko.md index cc98b60..eb18cbf 100644 --- a/ssrf-guard-springai-demo/README.ko.md +++ b/ssrf-guard-springai-demo/README.ko.md @@ -113,7 +113,7 @@ curl -X POST http://localhost:8080/agent/chat \ | 파일 | 왜 | | --- | --- | -| `build.gradle.kts` | 의존성 — `kr.devslab:ssrf-guard-springai:3.1.0` + `org.springframework.ai:spring-ai-model:1.0.7`. 끝 | +| `build.gradle.kts` | 의존성 — `kr.devslab:ssrf-guard-springai:3.1.1` + `org.springframework.ai:spring-ai-model:1.0.7`. 끝 | | `application.yml` | `ssrf.guard.springai.wrap-tool-callbacks=true` — 마스터 스위치 (기본 true, 명시적 표기) | | `agent/FetchUrlTool.java` | 원시 툴 — **보안 코드 0줄**. wrap은 빈 후처리 시점에 일어남 | | `agent/FakeLlmService.java` | 가짜 LLM 드라이버. 프로덕션에선 `ChatClient`. 교체, 재컴파일, 끝 | diff --git a/ssrf-guard-springai-demo/README.md b/ssrf-guard-springai-demo/README.md index c5c1c52..e75a219 100644 --- a/ssrf-guard-springai-demo/README.md +++ b/ssrf-guard-springai-demo/README.md @@ -113,7 +113,7 @@ curl -X POST http://localhost:8080/agent/chat \ | File | Why | | --- | --- | -| `build.gradle.kts` | The dependencies — `kr.devslab:ssrf-guard-springai:3.1.0` + `org.springframework.ai:spring-ai-model:1.0.7`. That's it | +| `build.gradle.kts` | The dependencies — `kr.devslab:ssrf-guard-springai:3.1.1` + `org.springframework.ai:spring-ai-model:1.0.7`. That's it | | `application.yml` | `ssrf.guard.springai.wrap-tool-callbacks=true` — the master switch (default true, shown for clarity) | | `agent/FetchUrlTool.java` | The raw tool — note there's **zero** security code here. The wrap happens at bean post-processing time | | `agent/FakeLlmService.java` | The fake-LLM driver. In production this is a `ChatClient`. Swap, recompile, done | diff --git a/ssrf-guard-springai-demo/build.gradle.kts b/ssrf-guard-springai-demo/build.gradle.kts index 188798a..3d61ee2 100644 --- a/ssrf-guard-springai-demo/build.gradle.kts +++ b/ssrf-guard-springai-demo/build.gradle.kts @@ -25,8 +25,8 @@ dependencies { // the RestClient against the wrapped tool's "remote" target. // - ssrf-guard-springai: wraps every ToolCallback bean automatically via // a BeanPostProcessor — that's the whole "secure-by-default" pitch. - implementation("kr.devslab:ssrf-guard:3.1.0") - implementation("kr.devslab:ssrf-guard-springai:3.1.0") + implementation("kr.devslab:ssrf-guard:3.1.1") + implementation("kr.devslab:ssrf-guard-springai:3.1.1") // Spring AI 1.0 GA. We don't actually call an LLM in this demo — the // FakeLlmService stands in for one — but we pull the API in so the