mirror of
https://github.com/openhop-dev/openhop_repeater.git
synced 2026-10-24 05:52:59 +00:00
61 lines
2.5 KiB
Python
61 lines
2.5 KiB
Python
"""Public plugin serving must never expose manager/runtime release files."""
|
|
|
|
from types import SimpleNamespace
|
|
|
|
import cherrypy
|
|
import pytest
|
|
|
|
from repeater.plugins.storage import PluginStorage
|
|
from repeater.web.http_server import StatsApp
|
|
|
|
|
|
@pytest.fixture
|
|
def plugin_ui(tmp_path, monkeypatch):
|
|
storage = PluginStorage(tmp_path / "plugins")
|
|
paths = storage.ensure_plugin_layout("audit.ui", "1.0.0")
|
|
release = paths.release_dir("1.0.0")
|
|
storage.set_current("audit.ui", "1.0.0")
|
|
storage.write_state("audit.ui", {"version": "1.0.0", "enabled": True})
|
|
(release / "config.default.json").write_text("PRIVATE-DEFAULT-FIXTURE")
|
|
(release / "venv").mkdir()
|
|
(release / "venv" / "pyvenv.cfg").write_text("PRIVATE-RUNTIME-FIXTURE")
|
|
manifest = SimpleNamespace(ui=SimpleNamespace(entry="ui/index.html"))
|
|
# Exercise serving's own boundary independently of manifest validation.
|
|
monkeypatch.setattr(PluginStorage, "load_current_manifest", lambda *_: manifest)
|
|
monkeypatch.setattr(cherrypy, "response", SimpleNamespace(headers={}))
|
|
app = object.__new__(StatsApp)
|
|
app.config = {"plugins": {"root": str(storage.root)}}
|
|
return app, release, manifest
|
|
|
|
|
|
@pytest.mark.parametrize("entry", ["index.html", "./index.html", "venv/index.html"])
|
|
def test_public_plugin_rejects_release_or_runtime_document_root(plugin_ui, entry):
|
|
app, _, manifest = plugin_ui
|
|
manifest.ui.entry = entry
|
|
requested = "pyvenv.cfg" if entry.startswith("venv/") else "config.default.json"
|
|
with pytest.raises(cherrypy.HTTPError) as exc:
|
|
app._serve_plugin_ui("audit.ui", (requested,))
|
|
assert exc.value.status == 404
|
|
|
|
|
|
def test_public_plugin_rejects_ui_symlink_to_runtime(plugin_ui):
|
|
app, release, _ = plugin_ui
|
|
(release / "ui").symlink_to("venv", target_is_directory=True)
|
|
with pytest.raises(cherrypy.HTTPError) as exc:
|
|
app._serve_plugin_ui("audit.ui", ("pyvenv.cfg",))
|
|
assert exc.value.status == 404
|
|
|
|
|
|
def test_public_plugin_keeps_assets_and_spa_fallback(plugin_ui):
|
|
app, release, _ = plugin_ui
|
|
ui = release / "ui"
|
|
ui.mkdir()
|
|
(ui / "index.html").write_text("PUBLIC-INDEX")
|
|
(ui / "app.js").write_text("PUBLIC-SCRIPT")
|
|
assert app._serve_plugin_ui("audit.ui", ("app.js",)) == b"PUBLIC-SCRIPT"
|
|
assert app._serve_plugin_ui("audit.ui", ("client-route",)) == b"PUBLIC-INDEX"
|
|
assert app._serve_plugin_ui("audit.ui", ("config.default.json",)) == b"PUBLIC-INDEX"
|
|
with pytest.raises(cherrypy.HTTPError) as exc:
|
|
app._serve_plugin_ui("audit.ui", ("..", "config.default.json"))
|
|
assert exc.value.status == 400
|