Skip to content

feat(tools): image reference processing and native provider support - #1251

Merged
mrgoonie merged 2 commits into
nextlevelbuilder:devfrom
thotam:feat/image-reference-handling
Jun 21, 2026
Merged

feat(tools): image reference processing and native provider support#1251
mrgoonie merged 2 commits into
nextlevelbuilder:devfrom
thotam:feat/image-reference-handling

Conversation

@thotam

@thotam thotam commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds image-reference processing for image-generation tools and wires native provider support so reference images can drive edits/generation across OpenAI, Gemini, Codex, DashScope, MiniMax and BytePlus.

Type

  • Feature
  • Bug fix
  • Hotfix (targeting main)
  • Refactor
  • Docs
  • CI/CD

Target Branch

dev (feature).

What changed

  • OpenAI image edits via both multipart form-data and JSON payloads
  • Automatically append reference image descriptions to the prompt under a [Reference Image Roles] section
  • Download image URLs for Gemini native image generation
  • Deduplicate reference images to reduce API request size
  • Unit tests for Codex, DashScope, MiniMax, BytePlus, and local/remote path resolution

Checklist

  • go build ./... passes
  • go build -tags sqliteonly ./... passes (if Go changes)
  • go vet ./... passes
  • Tests pass: go test -race ./...
  • Web UI builds: cd ui/web && pnpm build (if UI changes) — n/a, no UI changes
  • No hardcoded secrets or credentials
  • SQL queries use parameterized $1, $2 (no string concat) — n/a, no SQL
  • New user-facing strings added to all 3 locales (en/vi/zh) — n/a, prompt text is LLM-facing only
  • Migration version bumped in internal/upgrade/version.go (if new migration) — n/a, no migration

Test Plan

  • go build ./... and go build -tags sqliteonly ./... pass.
  • go test ./internal/providers passes (includes the new codex_native_image_test.go).
  • New unit tests cover native image path resolution and per-provider request shaping (create_image_native_path_test.go, codex_native_image_test.go).
  • Note: go test ./internal/tools cannot build locally on Windows due to a pre-existing, unrelated issue on devinternal/tools/document_parser_test.go references helpers (waitForRecordedPIDs, findLivePIDs) defined only in shell_abort_test.go which is gated //go:build !windows. This is not introduced by this PR and passes on the Linux CI runners.

🤖 Generated with Claude Code

… support

- Support OpenAI image edits via both Multipart form-data and JSON payloads
- Automatically append reference image descriptions to prompt under [Reference Image Roles]
- Support downloading image URLs for Gemini native image generation
- Deduplicate reference images to optimize API request size
- Add unit tests for Codex, DashScope, MiniMax, BytePlus and local/remote path resolution

@mrgoonie mrgoonie left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary: This is a valuable image-reference direction, but it is not safe to merge as-is. The new reference-image URL path adds server-side HTTP downloads without the repo's SSRF and size-limit protections.

Risk level: High

Mandatory gates:

  • Duplicate/prior implementation: clear. I found prior native image-generation work (#1002/#1006/#1021) and read_image URL support (#1191), but no duplicate PR for create_image reference-image handling.
  • Project standards: issue found — new outbound URL fetches should follow the existing SSRF-safe client / bounded-download patterns used elsewhere in the repo.
  • Strategic necessity: clear value. Reference images for create_image are a useful product capability across native and API-key-backed image providers.
  • CI/checks: currently incomplete/in progress at review time (go check still running; release-versioning/web green).

Findings:

  • Critical: internal/tools/create_image.go adds downloadImageBytes, which fetches user/agent-supplied ref_images[].url with a plain http.Client{Timeout: 30 * time.Second} and io.ReadAll with no SSRF validation, no redirect policy, and no response size cap. That path is used by the OpenAI/DALL-E multipart edit branch when the reference is a URL. This bypasses the existing outbound-fetch hardening in internal/security/ssrf.go / internal/tools/web_shared.go and can dial loopback, metadata, private networks, or arbitrarily large responses from the gateway process. Please validate URLs with the shared SSRF guard or internal/security.NewSafeClient/pinned-IP workflow, refuse unsafe redirects, and use a bounded read like limitedReadAll with an image-specific max. Add regression tests for blocked loopback/private/metadata URLs and oversized responses.
  • Important: provider-specific reference URL handling is inconsistent. OpenAI multipart downloads the URL server-side, while JSON/OpenRouter/Codex paths forward external URLs downstream. That may be acceptable, but the trust boundary should be explicit in code/tests/docs: local gateway downloads must be SSRF-safe; provider-forwarded URLs must remain HTTP(S) only and should not silently become gateway-side fetches later.

Verdict: REQUEST_CHANGES

Next step: harden the gateway-side URL download path first, then re-run the provider/tool tests and wait for normal CI to finish before merge.

@mrgoonie mrgoonie added status:blocked Blocked by external dependency or decision agent:github-maintain Processed by github-maintain automation maintain:triaged Triaged by maintain workflow labels Jun 21, 2026
downloadImageBytes fetched caller-supplied ref_images[].url with a plain
http.Client and unbounded io.ReadAll — no SSRF validation, redirect
policy, or size cap, letting the gateway dial loopback/private/metadata
hosts or read arbitrarily large responses.

- Validate the URL via security.Validate and pin the resolved IP, then
  download through security.NewSafeClient (pinned dial, no redirects).
- Cap the response with a bounded read (refImageMaxBytes, 20 MB).
- Reject non-HTTP(S) reference URLs up front (file://, data:, gopher://)
  so provider-forwarded URLs stay HTTP(S)-only; document the trust
  boundary between gateway-side fetch and provider-forwarded URLs.
- Add regression tests: blocked loopback/private/metadata, unfollowed
  redirect, oversized response, and non-http(s) scheme rejection.
@thotam

thotam commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

@mrgoonie Thanks for the SSRF catch — hardened in 0711196e.

Critical (SSRF in downloadImageBytes) — fixed. The gateway-side reference-image fetch now:

  • validates the URL with security.Validate and pins the resolved IP, then downloads via security.NewSafeClient (dials only the pinned IP, never follows redirects — a 3xx is returned and rejected by the status check), matching the existing read_video_resolve.go / read_image.go hardening pattern from feat(multimodal): support analyzing images and videos via URLs & streaming upload for Gemini #1191's 1dea4a21;
  • caps the body with a bounded read (io.LimitReader, refImageMaxBytes = 20 MB) instead of unbounded io.ReadAll.

Important (trust boundary) — made explicit:

  • reference URLs are now rejected up front unless they are http(s) (blocks file://, data:, gopher://), so provider-forwarded URLs stay HTTP(S)-only;
  • added a code comment at the JSON/forward path documenting that the gateway does not dial those URLs, and that any future gateway-side fetch must route through the SSRF-guarded downloadImageBytes.

Regression tests (create_image_ssrf_test.go): blocked loopback / private / link-local metadata (169.254.169.254), unfollowed redirect → rejected, oversized response → rejected, and non-http(s) scheme → rejected. All pass locally, plus go build ./... and -tags sqliteonly green.

(Local note: the internal/tools test binary can't compile on Windows due to a pre-existing document_parser_test.go helper gated //go:build !windows; I verified the new tests by temporarily isolating that file. CI on Linux runs them normally.)

@mrgoonie mrgoonie left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary: Re-reviewed 0711196e after the SSRF hardening update. The previous Critical finding is addressed: gateway-side reference image downloads now validate through the shared SSRF guard, pin the resolved IP, use security.NewSafeClient with redirects disabled, and read with a bounded refImageMaxBytes cap.

Risk level: Medium

Mandatory gates:

  • Duplicate/prior implementation: clear. Prior native image-generation and read_image URL hardening work exists, but no duplicate PR for create_image reference-image handling.
  • Project standards: passed after the SSRF fix. The gateway-side fetch path now follows the repo's safe outbound-fetch pattern.
  • Strategic necessity: clear value. Reference images are a useful capability for image edits/generation across native and API-key-backed providers.
  • CI/checks: green (go, web, release-versioning).

Verification:

  • go test ./internal/tools ./internal/providers
  • Checked internal/tools/create_image.go for downloadImageBytes, HTTP(S)-only URL validation, SSRF guard usage, redirect rejection, and bounded reads.
  • Checked internal/tools/create_image_ssrf_test.go for loopback/private/link-local metadata blocking, redirect rejection, oversized response rejection, happy path, and non-http(s) rejection.

Findings:

  • No Critical or Important findings remain from the previous SSRF/trust-boundary review.

Verdict: APPROVE

@mrgoonie
mrgoonie merged commit a5a853f into nextlevelbuilder:dev Jun 21, 2026
3 checks passed
@thotam
thotam deleted the feat/image-reference-handling branch June 22, 2026 07:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent:github-maintain Processed by github-maintain automation maintain:triaged Triaged by maintain workflow status:blocked Blocked by external dependency or decision

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants