Skip to content

Add failing tests for #652: purchase CORS violation & mock API in production#666

Draft
prompt-driven-github[bot] wants to merge 1 commit intomainfrom
fix/issue-652
Draft

Add failing tests for #652: purchase CORS violation & mock API in production#666
prompt-driven-github[bot] wants to merge 1 commit intomainfrom
fix/issue-652

Conversation

@prompt-driven-github
Copy link
Copy Markdown
Contributor

Summary

Adds failing tests that detect the bug reported in promptdriven/pdd_cloud#678 — purchase in settings dashboard fails with CORS violation and mock API handlers active in production.

Test Files

  • Unit tests: tests/server/test_security.py, tests/core/test_cloud.py
  • E2E test: tests/test_e2e_issue_652_purchase_cors.py

What This PR Contains

  • 5 failing tests that reproduce the reported bug:
    • 2 CORS failures: configure_cors() only allows localhost origins, missing https://promptdriven.ai
    • 3 endpoint registry failures: CLOUD_ENDPOINTS missing processPddcPurchase entry
  • 4 passing guardrails: localhost origins preserved, unknown origins rejected, env defaults to prod, existing endpoints registered
  • Tests are verified to fail on current code and will pass once the bug is fixed

Root Cause

Two independent bugs in the web application:

  1. CORS: configure_cors() in pdd/server/security.py only configures localhost origins, missing production origin https://promptdriven.ai
  2. Mock API in production: CLOUD_ENDPOINTS in pdd/core/cloud.py is missing processPddcPurchase, causing fallback to mock handlers

Next Steps

  1. Implement the fix at the identified locations
  2. Verify the unit tests pass
  3. Verify the E2E tests pass
  4. Run full test suite
  5. Mark PR as ready for review

Fixes promptdriven/pdd_cloud#678


Generated by PDD agentic bug workflow

…ion (#652)

Tests detect two root causes of the purchase failure:
- CORS: configure_cors() only allows localhost origins, missing https://promptdriven.ai
- Endpoint registry: CLOUD_ENDPOINTS missing processPddcPurchase entry

5 tests fail on current code, 4 pass as guardrails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
"""
url = CloudConfig.get_endpoint_url("processPddcPurchase")

assert "us-central1-prompt-driven-development.cloudfunctions.net" in url, (

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization High test

The string
us-central1-prompt-driven-development.cloudfunctions.net
may be at an arbitrary position in the sanitized URL.

Copilot Autofix

AI about 1 month ago

General fix: instead of checking that the production hostname appears as a substring of the full URL, parse the URL and assert on its hostname (and, if desired, scheme/path). This follows the guidance to operate on structured URL components rather than raw substrings.

Best concrete fix here:

  • In tests/core/test_cloud.py, import urlparse (from urllib.parse) alongside existing imports.
  • In test_purchase_endpoint_url_resolves_to_production, after obtaining url, parse it with urlparse(url) and assert that parsed.hostname equals the expected production hostname.
  • Optionally, we can also assert that the scheme is https to preserve the intent that this is a production Cloud Functions URL, but the minimal change needed to address the CodeQL warning is to replace the substring check with a hostname equality check using urlparse.

Specific changes:

  1. Add from urllib.parse import urlparse after the other imports at the top of tests/core/test_cloud.py.

  2. Replace:

    url = CloudConfig.get_endpoint_url("processPddcPurchase")
    
    assert "us-central1-prompt-driven-development.cloudfunctions.net" in url, (
        f"Purchase endpoint must resolve to production cloud functions URL. Got: {url}"
    )

    with:

    url = CloudConfig.get_endpoint_url("processPddcPurchase")
    parsed = urlparse(url)
    
    assert parsed.hostname == "us-central1-prompt-driven-development.cloudfunctions.net", (
        f"Purchase endpoint must resolve to production cloud functions hostname. Got: {parsed.hostname} (URL: {url})"
    )

    leaving the subsequent checks about processPddcPurchase in the path and absence of “mock/local” substrings unchanged.

No other files or logic need to be modified.


Suggested changeset 1
tests/core/test_cloud.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/tests/core/test_cloud.py b/tests/core/test_cloud.py
--- a/tests/core/test_cloud.py
+++ b/tests/core/test_cloud.py
@@ -39,6 +39,7 @@
 import asyncio
 from unittest.mock import patch, MagicMock, AsyncMock
 from z3 import Solver, Bool, And, Not
+from urllib.parse import urlparse
 
 # Import the code under test
 from pdd.core.cloud import (
@@ -597,9 +598,11 @@
     https://us-central1-prompt-driven-development.cloudfunctions.net/processPddcPurchase
     """
     url = CloudConfig.get_endpoint_url("processPddcPurchase")
+    parsed = urlparse(url)
 
-    assert "us-central1-prompt-driven-development.cloudfunctions.net" in url, (
-        f"Purchase endpoint must resolve to production cloud functions URL. Got: {url}"
+    assert parsed.hostname == "us-central1-prompt-driven-development.cloudfunctions.net", (
+        f"Purchase endpoint must resolve to production cloud functions hostname. "
+        f"Got: {parsed.hostname} (URL: {url})"
     )
     assert "processPddcPurchase" in url, (
         f"Purchase endpoint URL must contain 'processPddcPurchase'. Got: {url}"
EOF
@@ -39,6 +39,7 @@
import asyncio
from unittest.mock import patch, MagicMock, AsyncMock
from z3 import Solver, Bool, And, Not
from urllib.parse import urlparse

# Import the code under test
from pdd.core.cloud import (
@@ -597,9 +598,11 @@
https://us-central1-prompt-driven-development.cloudfunctions.net/processPddcPurchase
"""
url = CloudConfig.get_endpoint_url("processPddcPurchase")
parsed = urlparse(url)

assert "us-central1-prompt-driven-development.cloudfunctions.net" in url, (
f"Purchase endpoint must resolve to production cloud functions URL. Got: {url}"
assert parsed.hostname == "us-central1-prompt-driven-development.cloudfunctions.net", (
f"Purchase endpoint must resolve to production cloud functions hostname. "
f"Got: {parsed.hostname} (URL: {url})"
)
assert "processPddcPurchase" in url, (
f"Purchase endpoint URL must contain 'processPddcPurchase'. Got: {url}"
Copilot is powered by AI and may make mistakes. Always verify output.
call_args = app.add_middleware.call_args
kwargs = call_args[1]
origins = kwargs["allow_origins"]

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization High test

The string
https://promptdriven.ai
may be at an arbitrary position in the sanitized URL.

Copilot Autofix

AI about 1 month ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

f"Purchase endpoint URL must not contain '{indicator}'. Got: {url}"
)

assert "us-central1-prompt-driven-development.cloudfunctions.net" in url

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization High test

The string
us-central1-prompt-driven-development.cloudfunctions.net
may be at an arbitrary position in the sanitized URL.

Copilot Autofix

AI about 1 month ago

In general, to avoid incomplete URL substring sanitization, do not treat the URL as an opaque string when checking for allowed or disallowed hosts. Instead, parse it with a proper URL parser (such as urllib.parse.urlparse in Python) and inspect the hostname (and potentially scheme/port) fields, then compare those fields against an allowlist (or explicit expected values) using exact or well-defined suffix checks.

For this specific test, we should replace the substring assertion:

assert "us-central1-prompt-driven-development.cloudfunctions.net" in url

with a host-based assertion that parses url and verifies that its hostname matches the expected production hostname. This keeps the functional intent (“must point to the Cloud Functions production host”) while avoiding substring-based checks. Concretely:

  1. Import urlparse (or urllib.parse) at the top of this test file (we’re allowed to add well-known standard-library imports).
  2. Parse url via urlparse(url) and extract hostname.
  3. Assert that hostname equals "us-central1-prompt-driven-development.cloudfunctions.net" (or, if you want to be tolerant of schemes/paths but strict about host, assert parsed.hostname == EXPECTED_HOST).

No other tests or logic need to change.

Suggested changeset 1
tests/test_e2e_issue_652_purchase_cors.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/tests/test_e2e_issue_652_purchase_cors.py b/tests/test_e2e_issue_652_purchase_cors.py
--- a/tests/test_e2e_issue_652_purchase_cors.py
+++ b/tests/test_e2e_issue_652_purchase_cors.py
@@ -16,6 +16,7 @@
 import os
 import pytest
 from unittest.mock import patch
+from urllib.parse import urlparse
 
 from fastapi import FastAPI
 from fastapi.testclient import TestClient
@@ -207,7 +208,11 @@
                 f"Purchase endpoint URL must not contain '{indicator}'. Got: {url}"
             )
 
-        assert "us-central1-prompt-driven-development.cloudfunctions.net" in url
+        parsed = urlparse(url)
+        assert (
+            parsed.hostname
+            == "us-central1-prompt-driven-development.cloudfunctions.net"
+        ), f"Purchase endpoint host must be the production Cloud Functions host. Got: {parsed.hostname!r} in URL: {url}"
 
     def test_purchase_endpoint_registered_not_fallback(self, clean_env):
         """Verify processPddcPurchase is explicitly registered, not using fallback.
EOF
@@ -16,6 +16,7 @@
import os
import pytest
from unittest.mock import patch
from urllib.parse import urlparse

from fastapi import FastAPI
from fastapi.testclient import TestClient
@@ -207,7 +208,11 @@
f"Purchase endpoint URL must not contain '{indicator}'. Got: {url}"
)

assert "us-central1-prompt-driven-development.cloudfunctions.net" in url
parsed = urlparse(url)
assert (
parsed.hostname
== "us-central1-prompt-driven-development.cloudfunctions.net"
), f"Purchase endpoint host must be the production Cloud Functions host. Got: {parsed.hostname!r} in URL: {url}"

def test_purchase_endpoint_registered_not_fallback(self, clean_env):
"""Verify processPddcPurchase is explicitly registered, not using fallback.
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants