From cf7c09be5e6e3c916b01355128ccb02e2f65f9be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sequeira?= Date: Tue, 30 Dec 2025 15:26:37 +0100 Subject: [PATCH 1/9] feat: SDK Compliance --- .github/workflows/sdk-compliance.yml | 22 ++ sdk_compliance_adapter/Dockerfile | 26 ++ sdk_compliance_adapter/README.md | 76 +++++ sdk_compliance_adapter/adapter.py | 362 ++++++++++++++++++++++ sdk_compliance_adapter/docker-compose.yml | 25 ++ sdk_compliance_adapter/requirements.txt | 3 + 6 files changed, 514 insertions(+) create mode 100644 .github/workflows/sdk-compliance.yml create mode 100644 sdk_compliance_adapter/Dockerfile create mode 100644 sdk_compliance_adapter/README.md create mode 100644 sdk_compliance_adapter/adapter.py create mode 100644 sdk_compliance_adapter/docker-compose.yml create mode 100644 sdk_compliance_adapter/requirements.txt diff --git a/.github/workflows/sdk-compliance.yml b/.github/workflows/sdk-compliance.yml new file mode 100644 index 00000000..b1512499 --- /dev/null +++ b/.github/workflows/sdk-compliance.yml @@ -0,0 +1,22 @@ +name: SDK Compliance Tests + +permissions: + contents: read + packages: read + pull-requests: write + +on: + pull_request: + push: + branches: + - master + +jobs: + compliance: + name: PostHog SDK compliance tests + continue-on-error: true + uses: PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml@v0.1 + with: + adapter-dockerfile: "Dockerfile" + adapter-context: "sdk_compliance_adapter" + test-harness-version: "latest" diff --git a/sdk_compliance_adapter/Dockerfile b/sdk_compliance_adapter/Dockerfile new file mode 100644 index 00000000..1bf42264 --- /dev/null +++ b/sdk_compliance_adapter/Dockerfile @@ -0,0 +1,26 @@ +FROM python:3.12-slim + +WORKDIR /app + +# Copy the SDK source code +COPY . /app/sdk + +# Install the SDK from source +RUN cd /app/sdk && pip install --no-cache-dir -e . + +# Install adapter dependencies +RUN pip install --no-cache-dir flask python-dateutil + +# Copy adapter code +COPY sdk_compliance_adapter/adapter.py /app/adapter.py + +# Expose port 8080 +EXPOSE 8080 + +# Set environment variables (will be overridden by docker run) +ENV POSTHOG_HOST=http://localhost:8080 +ENV POSTHOG_API_KEY=test_key +ENV PORT=8080 + +# Run the adapter +CMD ["python", "/app/adapter.py"] diff --git a/sdk_compliance_adapter/README.md b/sdk_compliance_adapter/README.md new file mode 100644 index 00000000..4b96ad1f --- /dev/null +++ b/sdk_compliance_adapter/README.md @@ -0,0 +1,76 @@ +# PostHog Python SDK Test Adapter + +This adapter wraps the posthog-python SDK for compliance testing with the [PostHog SDK Test Harness](https://github.com/PostHog/posthog-sdk-test-harness). + +## What is This? + +This is a simple Flask app that: +1. Wraps the posthog-python SDK +2. Exposes a REST API for the test harness to control +3. Tracks internal SDK state for test assertions + +## Running Tests + +Tests run automatically in CI via GitHub Actions. See the test harness repo for details. + +### Locally with Docker Compose + +```bash +# From the posthog-python/sdk_compliance_adapter directory +docker-compose up --build --abort-on-container-exit +``` + +This will: +1. Build the Python SDK adapter +2. Pull the test harness image +3. Run all compliance tests +4. Show results + +### Manually with Docker + +```bash +# Create network +docker network create test-network + +# Build and run adapter +docker build -f sdk_compliance_adapter/Dockerfile -t posthog-python-adapter . +docker run -d --name sdk-adapter --network test-network -p 8080:8080 posthog-python-adapter + +# Run test harness +docker run --rm \ + --name test-harness \ + --network test-network \ + ghcr.io/posthog/sdk-test-harness:latest \ + run --adapter-url http://sdk-adapter:8080 --mock-url http://test-harness:8081 + +# Cleanup +docker stop sdk-adapter && docker rm sdk-adapter +docker network rm test-network +``` + +## Adapter Implementation + +See [adapter.py](adapter.py) for the implementation. + +The adapter implements the standard SDK adapter interface defined in the [test harness CONTRACT](https://github.com/PostHog/posthog-sdk-test-harness/blob/main/CONTRACT.yaml): + +- `GET /health` - Return SDK information +- `POST /init` - Initialize SDK with config +- `POST /capture` - Capture an event +- `POST /flush` - Flush pending events +- `GET /state` - Return internal state +- `POST /reset` - Reset SDK state + +### Key Implementation Details + +**Request Tracking**: The adapter monkey-patches `batch_post` to track all HTTP requests made by the SDK, including retries. + +**State Management**: Thread-safe state tracking for events captured vs sent, retry attempts, and errors. + +**UUID Tracking**: Extracts and tracks UUIDs from batches to verify deduplication. + +## Documentation + +For complete documentation on the test harness and how to implement adapters, see: +- [PostHog SDK Test Harness](https://github.com/PostHog/posthog-sdk-test-harness) +- [Adapter Implementation Guide](https://github.com/PostHog/posthog-sdk-test-harness/blob/main/ADAPTER_GUIDE.md) diff --git a/sdk_compliance_adapter/adapter.py b/sdk_compliance_adapter/adapter.py new file mode 100644 index 00000000..14ab6a9f --- /dev/null +++ b/sdk_compliance_adapter/adapter.py @@ -0,0 +1,362 @@ +""" +PostHog Python SDK Test Adapter + +This adapter implements the SDK Test Adapter Interface defined in the PostHog Capture API Contract. +It wraps the posthog-python SDK and exposes a REST API for the test harness to exercise. +""" + +import json +import logging +import os +import threading +import time +from datetime import datetime +from typing import Any, Dict, List, Optional + +from flask import Flask, jsonify, request + +from posthog import Client, Posthog +from posthog.request import batch_post as original_batch_post +from posthog.version import VERSION + +# Configure logging +logging.basicConfig( + level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" +) +logger = logging.getLogger(__name__) + +app = Flask(__name__) + + +class RequestInfo: + """Information about an HTTP request made by the SDK""" + + def __init__(self, timestamp_ms: int, status_code: int, retry_attempt: int, event_count: int, uuid_list: List[str]): + self.timestamp_ms = timestamp_ms + self.status_code = status_code + self.retry_attempt = retry_attempt + self.event_count = event_count + self.uuid_list = uuid_list + + def to_dict(self) -> Dict[str, Any]: + return { + "timestamp_ms": self.timestamp_ms, + "status_code": self.status_code, + "retry_attempt": self.retry_attempt, + "event_count": self.event_count, + "uuid_list": self.uuid_list, + } + + +class SDKState: + """Tracks SDK internal state for test assertions""" + + def __init__(self): + self.lock = threading.Lock() + self.pending_events = 0 + self.total_events_captured = 0 + self.total_events_sent = 0 + self.total_retries = 0 + self.last_error: Optional[str] = None + self.requests_made: List[RequestInfo] = [] + self.client: Optional[Client] = None + self.retry_attempts: Dict[str, int] = {} # Track retry attempts by batch ID + + def reset(self): + """Reset all state""" + with self.lock: + self.pending_events = 0 + self.total_events_captured = 0 + self.total_events_sent = 0 + self.total_retries = 0 + self.last_error = None + self.requests_made = [] + self.retry_attempts = {} + if self.client: + # Flush and shutdown existing client + try: + self.client.shutdown() + except Exception as e: + logger.warning(f"Error shutting down client: {e}") + self.client = None + + def increment_captured(self): + """Increment total events captured""" + with self.lock: + self.total_events_captured += 1 + self.pending_events += 1 + + def record_request(self, status_code: int, batch: List[Dict], batch_id: str): + """Record an HTTP request made by the SDK""" + with self.lock: + # Determine retry attempt for this batch + retry_attempt = self.retry_attempts.get(batch_id, 0) + + # Extract UUIDs from batch + uuid_list = [event.get("uuid", "") for event in batch] + + request_info = RequestInfo( + timestamp_ms=int(time.time() * 1000), + status_code=status_code, + retry_attempt=retry_attempt, + event_count=len(batch), + uuid_list=uuid_list, + ) + self.requests_made.append(request_info) + + # Update counters + if status_code == 200: + # Success - clear pending events + self.total_events_sent += len(batch) + self.pending_events = max(0, self.pending_events - len(batch)) + # Remove batch from retry tracking + self.retry_attempts.pop(batch_id, None) + else: + # Failure - increment retry count + self.retry_attempts[batch_id] = retry_attempt + 1 + if retry_attempt > 0: + self.total_retries += 1 + + def record_error(self, error: str): + """Record an error""" + with self.lock: + self.last_error = error + + def get_state(self) -> Dict[str, Any]: + """Get current state as dict""" + with self.lock: + return { + "pending_events": self.pending_events, + "total_events_captured": self.total_events_captured, + "total_events_sent": self.total_events_sent, + "total_retries": self.total_retries, + "last_error": self.last_error, + "requests_made": [r.to_dict() for r in self.requests_made], + } + + +# Global state +state = SDKState() + + +def create_batch_id(batch: List[Dict]) -> str: + """Create a unique ID for a batch based on UUIDs""" + uuids = sorted([event.get("uuid", "") for event in batch]) + return "-".join(uuids[:3]) # Use first 3 UUIDs as batch ID + + +def patched_batch_post(api_key: str, host: Optional[str] = None, gzip: bool = False, timeout: int = 15, **kwargs): + """Patched version of batch_post that tracks requests""" + batch = kwargs.get("batch", []) + batch_id = create_batch_id(batch) + + try: + # Call original batch_post + response = original_batch_post(api_key, host, gzip, timeout, **kwargs) + # Record successful request + state.record_request(200, batch, batch_id) + return response + except Exception as e: + # Record failed request + status_code = getattr(e, "status_code", 500) if hasattr(e, "status_code") else 500 + state.record_request(status_code, batch, batch_id) + state.record_error(str(e)) + raise + + +# Monkey-patch the batch_post function +import posthog.request + +posthog.request.batch_post = patched_batch_post + +# Also patch in consumer module +import posthog.consumer + +posthog.consumer.batch_post = patched_batch_post + + +@app.route("/health", methods=["GET"]) +def health(): + """Health check endpoint""" + return jsonify({"sdk_name": "posthog-python", "sdk_version": VERSION, "adapter_version": "1.0.0"}) + + +@app.route("/init", methods=["POST"]) +def init(): + """Initialize the SDK client""" + try: + data = request.json or {} + + # Reset state + state.reset() + + # Extract config + api_key = data.get("api_key") + host = data.get("host") + flush_at = data.get("flush_at", 100) + flush_interval_ms = data.get("flush_interval_ms", 500) + max_retries = data.get("max_retries", 3) + enable_compression = data.get("enable_compression", False) + + if not api_key: + return jsonify({"error": "api_key is required"}), 400 + if not host: + return jsonify({"error": "host is required"}), 400 + + # Convert flush_interval from ms to seconds + flush_interval = flush_interval_ms / 1000.0 + + # Create client + client = Client( + project_api_key=api_key, + host=host, + flush_at=flush_at, + flush_interval=flush_interval, + gzip=enable_compression, + max_retries=max_retries, + debug=True, + ) + + state.client = client + + logger.info( + f"Initialized SDK with api_key={api_key[:10]}..., host={host}, " + f"flush_at={flush_at}, flush_interval={flush_interval}, " + f"max_retries={max_retries}, gzip={enable_compression}" + ) + + return jsonify({"success": True}) + except Exception as e: + logger.exception("Error initializing SDK") + return jsonify({"error": str(e)}), 500 + + +@app.route("/capture", methods=["POST"]) +def capture(): + """Capture a single event""" + try: + if not state.client: + return jsonify({"error": "SDK not initialized"}), 400 + + data = request.json or {} + + distinct_id = data.get("distinct_id") + event = data.get("event") + properties = data.get("properties") + timestamp = data.get("timestamp") + + if not distinct_id: + return jsonify({"error": "distinct_id is required"}), 400 + if not event: + return jsonify({"error": "event is required"}), 400 + + # Capture event + kwargs = {"distinct_id": distinct_id, "properties": properties} + if timestamp: + # Parse ISO8601 timestamp + from dateutil.parser import parse + + kwargs["timestamp"] = parse(timestamp) + + uuid = state.client.capture(event, **kwargs) + + # Track that we captured an event + state.increment_captured() + + logger.info(f"Captured event: {event} for {distinct_id}, uuid={uuid}") + + return jsonify({"success": True, "uuid": uuid}) + except Exception as e: + logger.exception("Error capturing event") + state.record_error(str(e)) + return jsonify({"error": str(e)}), 500 + + +@app.route("/identify", methods=["POST"]) +def identify(): + """Identify a user""" + try: + if not state.client: + return jsonify({"error": "SDK not initialized"}), 400 + + data = request.json or {} + + distinct_id = data.get("distinct_id") + properties = data.get("properties") + properties_set_once = data.get("properties_set_once") + + if not distinct_id: + return jsonify({"error": "distinct_id is required"}), 400 + + # Use the identify pattern - set + set_once + if properties: + state.client.set(distinct_id=distinct_id, properties=properties) + state.increment_captured() + + if properties_set_once: + state.client.set_once(distinct_id=distinct_id, properties=properties_set_once) + state.increment_captured() + + logger.info(f"Identified user: {distinct_id}") + + return jsonify({"success": True}) + except Exception as e: + logger.exception("Error identifying user") + state.record_error(str(e)) + return jsonify({"error": str(e)}), 500 + + +@app.route("/flush", methods=["POST"]) +def flush(): + """Force flush all pending events""" + try: + if not state.client: + return jsonify({"error": "SDK not initialized"}), 400 + + # Flush and wait + state.client.flush() + + # Wait a bit for flush to complete + # The flush() method triggers queue.join() which blocks until all items are processed + time.sleep(0.5) + + logger.info("Flushed pending events") + + return jsonify({"success": True, "events_flushed": state.total_events_sent}) + except Exception as e: + logger.exception("Error flushing events") + state.record_error(str(e)) + return jsonify({"error": str(e), "errors": [str(e)]}, 500) + + +@app.route("/state", methods=["GET"]) +def get_state(): + """Get internal SDK state""" + try: + return jsonify(state.get_state()) + except Exception as e: + logger.exception("Error getting state") + return jsonify({"error": str(e)}), 500 + + +@app.route("/reset", methods=["POST"]) +def reset(): + """Reset SDK state""" + try: + state.reset() + logger.info("Reset SDK state") + return jsonify({"success": True}) + except Exception as e: + logger.exception("Error resetting state") + return jsonify({"error": str(e)}), 500 + + +def main(): + """Main entry point""" + port = int(os.environ.get("PORT", 8080)) + logger.info(f"Starting SDK Test Adapter on port {port}") + app.run(host="0.0.0.0", port=port, debug=False) + + +if __name__ == "__main__": + main() diff --git a/sdk_compliance_adapter/docker-compose.yml b/sdk_compliance_adapter/docker-compose.yml new file mode 100644 index 00000000..138bf4a8 --- /dev/null +++ b/sdk_compliance_adapter/docker-compose.yml @@ -0,0 +1,25 @@ +version: "3.8" + +services: + # PostHog Python SDK adapter + sdk-adapter: + build: + context: .. + dockerfile: sdk_compliance_adapter/Dockerfile + ports: + - "8080:8080" + networks: + - test-network + + # Test harness + test-harness: + image: ghcr.io/posthog/sdk-test-harness:latest + command: ["run", "--adapter-url", "http://sdk-adapter:8080", "--mock-url", "http://test-harness:8081"] + networks: + - test-network + depends_on: + - sdk-adapter + +networks: + test-network: + driver: bridge diff --git a/sdk_compliance_adapter/requirements.txt b/sdk_compliance_adapter/requirements.txt new file mode 100644 index 00000000..bc677133 --- /dev/null +++ b/sdk_compliance_adapter/requirements.txt @@ -0,0 +1,3 @@ +# SDK Test Adapter dependencies +flask>=3.0.0 +python-dateutil>=2.8.0 From 1cbcb6b7d9e9395c25b87c8615b598f1961ca2b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sequeira?= Date: Tue, 30 Dec 2025 15:28:36 +0100 Subject: [PATCH 2/9] fix workflow --- .github/workflows/sdk-compliance.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/sdk-compliance.yml b/.github/workflows/sdk-compliance.yml index b1512499..4755cf80 100644 --- a/.github/workflows/sdk-compliance.yml +++ b/.github/workflows/sdk-compliance.yml @@ -14,7 +14,6 @@ on: jobs: compliance: name: PostHog SDK compliance tests - continue-on-error: true uses: PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml@v0.1 with: adapter-dockerfile: "Dockerfile" From ea2bf8fc488df2037f1ca3df4d625c9d10751170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sequeira?= Date: Tue, 30 Dec 2025 15:38:36 +0100 Subject: [PATCH 3/9] fix workflow --- .github/workflows/sdk-compliance.yml | 2 +- sdk_compliance_adapter/adapter.py | 41 +++++++++++++++++++++------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/.github/workflows/sdk-compliance.yml b/.github/workflows/sdk-compliance.yml index 4755cf80..da7f8e38 100644 --- a/.github/workflows/sdk-compliance.yml +++ b/.github/workflows/sdk-compliance.yml @@ -14,7 +14,7 @@ on: jobs: compliance: name: PostHog SDK compliance tests - uses: PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml@v0.1 + uses: PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml@main with: adapter-dockerfile: "Dockerfile" adapter-context: "sdk_compliance_adapter" diff --git a/sdk_compliance_adapter/adapter.py b/sdk_compliance_adapter/adapter.py index 14ab6a9f..fc20dba4 100644 --- a/sdk_compliance_adapter/adapter.py +++ b/sdk_compliance_adapter/adapter.py @@ -5,17 +5,15 @@ It wraps the posthog-python SDK and exposes a REST API for the test harness to exercise. """ -import json import logging import os import threading import time -from datetime import datetime from typing import Any, Dict, List, Optional from flask import Flask, jsonify, request -from posthog import Client, Posthog +from posthog import Client from posthog.request import batch_post as original_batch_post from posthog.version import VERSION @@ -31,7 +29,14 @@ class RequestInfo: """Information about an HTTP request made by the SDK""" - def __init__(self, timestamp_ms: int, status_code: int, retry_attempt: int, event_count: int, uuid_list: List[str]): + def __init__( + self, + timestamp_ms: int, + status_code: int, + retry_attempt: int, + event_count: int, + uuid_list: List[str], + ): self.timestamp_ms = timestamp_ms self.status_code = status_code self.retry_attempt = retry_attempt @@ -145,7 +150,13 @@ def create_batch_id(batch: List[Dict]) -> str: return "-".join(uuids[:3]) # Use first 3 UUIDs as batch ID -def patched_batch_post(api_key: str, host: Optional[str] = None, gzip: bool = False, timeout: int = 15, **kwargs): +def patched_batch_post( + api_key: str, + host: Optional[str] = None, + gzip: bool = False, + timeout: int = 15, + **kwargs, +): """Patched version of batch_post that tracks requests""" batch = kwargs.get("batch", []) batch_id = create_batch_id(batch) @@ -158,19 +169,21 @@ def patched_batch_post(api_key: str, host: Optional[str] = None, gzip: bool = Fa return response except Exception as e: # Record failed request - status_code = getattr(e, "status_code", 500) if hasattr(e, "status_code") else 500 + status_code = ( + getattr(e, "status_code", 500) if hasattr(e, "status_code") else 500 + ) state.record_request(status_code, batch, batch_id) state.record_error(str(e)) raise # Monkey-patch the batch_post function -import posthog.request +import posthog.request # noqa: E402 posthog.request.batch_post = patched_batch_post # Also patch in consumer module -import posthog.consumer +import posthog.consumer # noqa: E402 posthog.consumer.batch_post = patched_batch_post @@ -178,7 +191,13 @@ def patched_batch_post(api_key: str, host: Optional[str] = None, gzip: bool = Fa @app.route("/health", methods=["GET"]) def health(): """Health check endpoint""" - return jsonify({"sdk_name": "posthog-python", "sdk_version": VERSION, "adapter_version": "1.0.0"}) + return jsonify( + { + "sdk_name": "posthog-python", + "sdk_version": VERSION, + "adapter_version": "1.0.0", + } + ) @app.route("/init", methods=["POST"]) @@ -294,7 +313,9 @@ def identify(): state.increment_captured() if properties_set_once: - state.client.set_once(distinct_id=distinct_id, properties=properties_set_once) + state.client.set_once( + distinct_id=distinct_id, properties=properties_set_once + ) state.increment_captured() logger.info(f"Identified user: {distinct_id}") From 8fc5c72ce2e1c8deba45042107ab1db662943718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sequeira?= Date: Tue, 30 Dec 2025 15:48:24 +0100 Subject: [PATCH 4/9] add mypy ignore --- sdk_compliance_adapter/adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk_compliance_adapter/adapter.py b/sdk_compliance_adapter/adapter.py index fc20dba4..826a5383 100644 --- a/sdk_compliance_adapter/adapter.py +++ b/sdk_compliance_adapter/adapter.py @@ -273,7 +273,7 @@ def capture(): kwargs = {"distinct_id": distinct_id, "properties": properties} if timestamp: # Parse ISO8601 timestamp - from dateutil.parser import parse + from dateutil.parser import parse # type: ignore[import-untyped] kwargs["timestamp"] = parse(timestamp) From 7478fff1111f5cec1258a67192b6edb304b6b17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sequeira?= Date: Tue, 30 Dec 2025 15:54:32 +0100 Subject: [PATCH 5/9] one more --- .github/workflows/sdk-compliance.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk-compliance.yml b/.github/workflows/sdk-compliance.yml index da7f8e38..33831233 100644 --- a/.github/workflows/sdk-compliance.yml +++ b/.github/workflows/sdk-compliance.yml @@ -14,7 +14,7 @@ on: jobs: compliance: name: PostHog SDK compliance tests - uses: PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml@main + uses: PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml@2a2578e3c62542a80d5be99268fc6970c0299ec5 with: adapter-dockerfile: "Dockerfile" adapter-context: "sdk_compliance_adapter" From 8d54a3ff0a760f295d1da51c4947b89dd587209a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sequeira?= Date: Tue, 30 Dec 2025 16:13:06 +0100 Subject: [PATCH 6/9] fix action --- .github/workflows/sdk-compliance.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk-compliance.yml b/.github/workflows/sdk-compliance.yml index 33831233..da7f8e38 100644 --- a/.github/workflows/sdk-compliance.yml +++ b/.github/workflows/sdk-compliance.yml @@ -14,7 +14,7 @@ on: jobs: compliance: name: PostHog SDK compliance tests - uses: PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml@2a2578e3c62542a80d5be99268fc6970c0299ec5 + uses: PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml@main with: adapter-dockerfile: "Dockerfile" adapter-context: "sdk_compliance_adapter" From b03459cf916c825aa16c27a238d877224f409857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sequeira?= Date: Tue, 30 Dec 2025 16:14:59 +0100 Subject: [PATCH 7/9] fix dockerfile --- sdk_compliance_adapter/Dockerfile | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sdk_compliance_adapter/Dockerfile b/sdk_compliance_adapter/Dockerfile index 1bf42264..a2b9c353 100644 --- a/sdk_compliance_adapter/Dockerfile +++ b/sdk_compliance_adapter/Dockerfile @@ -2,8 +2,9 @@ FROM python:3.12-slim WORKDIR /app -# Copy the SDK source code -COPY . /app/sdk +# Copy the SDK source code (everything except sdk_compliance_adapter) +COPY posthog/ /app/sdk/posthog/ +COPY setup.py pyproject.toml README.md LICENSE /app/sdk/ # Install the SDK from source RUN cd /app/sdk && pip install --no-cache-dir -e . @@ -17,10 +18,5 @@ COPY sdk_compliance_adapter/adapter.py /app/adapter.py # Expose port 8080 EXPOSE 8080 -# Set environment variables (will be overridden by docker run) -ENV POSTHOG_HOST=http://localhost:8080 -ENV POSTHOG_API_KEY=test_key -ENV PORT=8080 - # Run the adapter CMD ["python", "/app/adapter.py"] From f60be574b91c0fa8b97caf3c81c098353bbea9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sequeira?= Date: Tue, 30 Dec 2025 16:17:43 +0100 Subject: [PATCH 8/9] fix dockerfile --- sdk_compliance_adapter/Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk_compliance_adapter/Dockerfile b/sdk_compliance_adapter/Dockerfile index a2b9c353..3a242c35 100644 --- a/sdk_compliance_adapter/Dockerfile +++ b/sdk_compliance_adapter/Dockerfile @@ -2,9 +2,9 @@ FROM python:3.12-slim WORKDIR /app -# Copy the SDK source code (everything except sdk_compliance_adapter) -COPY posthog/ /app/sdk/posthog/ -COPY setup.py pyproject.toml README.md LICENSE /app/sdk/ +# Copy the SDK source code from parent directory +COPY ../posthog/ /app/sdk/posthog/ +COPY ../setup.py ../pyproject.toml ../README.md ../LICENSE /app/sdk/ # Install the SDK from source RUN cd /app/sdk && pip install --no-cache-dir -e . @@ -12,8 +12,8 @@ RUN cd /app/sdk && pip install --no-cache-dir -e . # Install adapter dependencies RUN pip install --no-cache-dir flask python-dateutil -# Copy adapter code -COPY sdk_compliance_adapter/adapter.py /app/adapter.py +# Copy adapter code (from current context) +COPY adapter.py /app/adapter.py # Expose port 8080 EXPOSE 8080 From 106e97276fc5b1c969cc109675c0df08059d97c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sequeira?= Date: Tue, 30 Dec 2025 16:19:19 +0100 Subject: [PATCH 9/9] fix dockerfile --- .github/workflows/sdk-compliance.yml | 4 ++-- sdk_compliance_adapter/Dockerfile | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/sdk-compliance.yml b/.github/workflows/sdk-compliance.yml index da7f8e38..82dc865b 100644 --- a/.github/workflows/sdk-compliance.yml +++ b/.github/workflows/sdk-compliance.yml @@ -16,6 +16,6 @@ jobs: name: PostHog SDK compliance tests uses: PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml@main with: - adapter-dockerfile: "Dockerfile" - adapter-context: "sdk_compliance_adapter" + adapter-dockerfile: "sdk_compliance_adapter/Dockerfile" + adapter-context: "." test-harness-version: "latest" diff --git a/sdk_compliance_adapter/Dockerfile b/sdk_compliance_adapter/Dockerfile index 3a242c35..c347f326 100644 --- a/sdk_compliance_adapter/Dockerfile +++ b/sdk_compliance_adapter/Dockerfile @@ -2,9 +2,9 @@ FROM python:3.12-slim WORKDIR /app -# Copy the SDK source code from parent directory -COPY ../posthog/ /app/sdk/posthog/ -COPY ../setup.py ../pyproject.toml ../README.md ../LICENSE /app/sdk/ +# Copy the SDK source code +COPY posthog/ /app/sdk/posthog/ +COPY setup.py pyproject.toml README.md LICENSE /app/sdk/ # Install the SDK from source RUN cd /app/sdk && pip install --no-cache-dir -e . @@ -12,8 +12,8 @@ RUN cd /app/sdk && pip install --no-cache-dir -e . # Install adapter dependencies RUN pip install --no-cache-dir flask python-dateutil -# Copy adapter code (from current context) -COPY adapter.py /app/adapter.py +# Copy adapter code +COPY sdk_compliance_adapter/adapter.py /app/adapter.py # Expose port 8080 EXPOSE 8080