Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions plugins/image_gen/openai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,16 @@ def _load_image_bytes(ref: str) -> Tuple[bytes, str]:
ext = header.split("image/", 1)[1].split(";", 1)[0] or "png"
return base64.b64decode(b64), f"image.{ext}"
# Local file path.
try:
from agent.file_safety import get_read_block_error

blocked = get_read_block_error(ref)
if blocked:
raise ValueError(blocked)
except ValueError:
raise
except Exception as exc: # noqa: BLE001 - preserve existing local-file behavior
logger.debug("OpenAI image input read guard unavailable: %s", exc)
with open(ref, "rb") as fh:
data = fh.read()
name = os.path.basename(ref) or "image.png"
Expand Down
10 changes: 10 additions & 0 deletions plugins/image_gen/openrouter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ def _to_image_url_part(ref: str) -> Optional[str]:
if ref.startswith(("http://", "https://", "data:")):
return ref
path = Path(ref)
try:
from agent.file_safety import get_read_block_error

blocked = get_read_block_error(ref)
if blocked:
raise ValueError(blocked)
except ValueError:
raise
except Exception as exc: # noqa: BLE001 - keep local image refs best-effort
logger.debug("OpenRouter image input read guard unavailable: %s", exc)
try:
raw = path.read_bytes()
except OSError as exc:
Expand Down
12 changes: 12 additions & 0 deletions tests/plugins/image_gen/test_openai_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,18 @@ def test_config_top_level_model(self, tmp_path):
# ── Generate ────────────────────────────────────────────────────────────────


class TestSourceImageLoading:
def test_load_image_bytes_blocks_credential_store(self, tmp_path, monkeypatch):
hermes_home = tmp_path / ".hermes"
hermes_home.mkdir()
auth_json = hermes_home / "auth.json"
auth_json.write_text('{"api_key":"sk-secret"}', encoding="utf-8")
monkeypatch.setenv("HERMES_HOME", str(hermes_home))

with pytest.raises(ValueError, match="credential store"):
openai_plugin._load_image_bytes(str(auth_json))


class TestGenerate:
def test_empty_prompt_rejected(self, provider):
result = provider.generate("", aspect_ratio="square")
Expand Down
12 changes: 12 additions & 0 deletions tests/plugins/image_gen/test_openrouter_compat_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,18 @@ def test_to_image_url_part_missing_file(self):

assert _to_image_url_part("/no/such/file.png") is None

def test_to_image_url_part_blocks_credential_store(self, tmp_path, monkeypatch):
from plugins.image_gen.openrouter import _to_image_url_part

hermes_home = tmp_path / ".hermes"
hermes_home.mkdir()
auth_json = hermes_home / "auth.json"
auth_json.write_text('{"api_key":"sk-secret"}', encoding="utf-8")
monkeypatch.setenv("HERMES_HOME", str(hermes_home))

with pytest.raises(ValueError, match="credential store"):
_to_image_url_part(str(auth_json))

def test_extract_images(self):
from plugins.image_gen.openrouter import _extract_images

Expand Down
Loading