from flask import Flask import auth from routes import system_public_routes as routes def _make_app(monkeypatch): app = Flask(__name__) app.secret_key = "test-secret" app.register_blueprint(routes.system_public_bp) monkeypatch.setattr(auth, "DISABLE_LOGIN", True) return app def test_webcrumbs_host_data_api_blocks_when_login_disabled_without_internal_key(monkeypatch): app = _make_app(monkeypatch) monkeypatch.setenv("INTERNAL_API_KEY", "test-internal-key") called = {"value": False} def fail_if_called(limit=5): called["value"] = True return {} monkeypatch.setattr(routes, "build_webcrumbs_seed_data", fail_if_called) response = app.test_client().get("/api/webcrumbs/marketplace-host-data") assert response.status_code == 401 payload = response.get_json() assert payload["success"] is False assert payload["error"] == "auth_required" assert payload["boundary"]["auth_required"] is True assert payload["boundary"]["writes_database"] is False assert payload["boundary"]["calls_llm"] is False assert payload["boundary"]["fetches_external"] is False assert called["value"] is False def test_webcrumbs_host_data_api_allows_internal_key_when_login_disabled(monkeypatch): app = _make_app(monkeypatch) monkeypatch.setenv("INTERNAL_API_KEY", "test-internal-key") seed_payload = { "marketSnapshot": [ { "name": "SKU-1 exact price alert", "price": 250, "change_pct": 12.5, "freshness_status": "price_alert_exact", } ], "aiCandidate": { "ticker": "SKU-1", "name": "exact alert", "thesis": "MOMO NT$300 vs PChome NT$250", }, "metadata": { "source": "competitor_intel_repository", "matched_count": 88, "fresh_match_count": 70, "fresh_match_rate": 79.5, "decision_support_count": 105, "decision_support_rate": 14.7, "catalog_comparable_count": 12, "catalog_variant_review_count": 7, "catalog_unit_review_count": 3, "catalog_identity_review_count": 2, "catalog_review_plan": { "variant_review": 7, "unit_review": 3, "identity_review": 2, "total": 12, }, "unit_comparable_count": 23, "stale_match_count": 18, "pending_match_count": 612, "writes_database": False, "calls_llm": False, "fetches_external": False, }, } captured = {} def fake_build_webcrumbs_seed_data(limit=5): captured["limit"] = limit return seed_payload monkeypatch.setattr(routes, "build_webcrumbs_seed_data", fake_build_webcrumbs_seed_data) response = app.test_client().get( "/api/webcrumbs/marketplace-host-data?limit=99", headers={"X-Internal-Key": "test-internal-key"}, ) assert response.status_code == 200 payload = response.get_json() assert captured["limit"] == 8 assert payload["success"] is True assert payload["data"] == seed_payload assert payload["metadata"]["source"] == "competitor_intel_repository" assert payload["metadata"]["fresh_match_count"] == 70 assert payload["metadata"]["fresh_match_rate"] == 79.5 assert payload["metadata"]["decision_support_count"] == 105 assert payload["metadata"]["decision_support_rate"] == 14.7 assert payload["metadata"]["catalog_comparable_count"] == 12 assert payload["metadata"]["catalog_variant_review_count"] == 7 assert payload["metadata"]["catalog_unit_review_count"] == 3 assert payload["metadata"]["catalog_identity_review_count"] == 2 assert payload["metadata"]["catalog_review_plan"]["total"] == 12 assert payload["metadata"]["unit_comparable_count"] == 23 assert payload["metadata"]["stale_match_count"] == 18 assert payload["metadata"]["pending_match_count"] == 612 assert payload["boundary"]["auth_required"] is True assert payload["boundary"]["writes_database"] is False assert payload["boundary"]["calls_llm"] is False assert payload["boundary"]["fetches_external"] is False def test_webcrumbs_page_uses_auth_required_seed_when_login_disabled_without_sensitive_access(monkeypatch): app = _make_app(monkeypatch) monkeypatch.setenv("INTERNAL_API_KEY", "test-internal-key") captured = {} def fake_build_external_tool_payload(kind, include_host_data=True): captured["kind"] = kind captured["include_host_data"] = include_host_data return { "key": kind, "plugin_seed_data": { "marketSnapshot": [ { "name": "MOMO/PChome host data requires authentication", "freshness_status": "auth_required", } ], "aiCandidate": { "name": "MOMO/PChome host data locked", "release_status": "blocked", }, }, } def fake_render_template(template_name, **context): return str(context["tool"]["plugin_seed_data"]) monkeypatch.setattr(routes, "build_external_tool_payload", fake_build_external_tool_payload) monkeypatch.setattr(routes, "render_template", fake_render_template) response = app.test_client().get("/webcrumbs") body = response.get_data(as_text=True) assert response.status_code == 200 assert captured == {"kind": "webcrumbs", "include_host_data": False} assert "auth_required" in body assert "MOMO NT$" not in body assert "PChome NT$" not in body def test_webcrumbs_page_allows_sensitive_seed_for_logged_in_session(monkeypatch): app = _make_app(monkeypatch) captured = {} def fake_build_external_tool_payload(kind, include_host_data=True): captured["kind"] = kind captured["include_host_data"] = include_host_data return {"key": kind, "plugin_seed_data": {"release_status": "review_required"}} monkeypatch.setattr(routes, "build_external_tool_payload", fake_build_external_tool_payload) monkeypatch.setattr(routes, "render_template", lambda template_name, **context: "ok") client = app.test_client() with client.session_transaction() as session: session["logged_in"] = True response = client.get("/webcrumbs") assert response.status_code == 200 assert captured == {"kind": "webcrumbs", "include_host_data": True}