From 0de0d4f69c2e180fbf6a4e674a9113544f2cbc2f Mon Sep 17 00:00:00 2001 From: Abdulrahman Abuzeid Date: Tue, 4 Aug 2026 20:35:11 +0200 Subject: [PATCH 1/2] Add LocalStack integration test pipeline --- .github/workflows/ci.yml | 54 +++++++++++++++++++++++++ tests/integration/test_localstack.py | 59 ++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 tests/integration/test_localstack.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b676ce3..bf36979 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,3 +78,57 @@ jobs: format: table exit-code: "1" severity: CRITICAL,HIGH + + integration-test: + name: Test API with LocalStack + needs: + - test + - infrastructure + runs-on: ubuntu-latest + env: + AWS_ACCESS_KEY_ID: test + AWS_SECRET_ACCESS_KEY: test + AWS_DEFAULT_REGION: us-east-1 + AWS_REGION: us-east-1 + RUN_INTEGRATION_TESTS: "1" + TF_IN_AUTOMATION: "true" + + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@v7 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: | + requirements.txt + requirements-dev.txt + + - name: Install Python dependencies + run: python -m pip install --requirement requirements-dev.txt + + - name: Set up Terraform + uses: hashicorp/setup-terraform@v4 + with: + terraform_version: "1.15.8" + + - name: Start LocalStack + uses: LocalStack/setup-localstack@v0.2.3 + with: + image-tag: "latest" + install-awslocal: "true" + use-pro: "true" + env: + LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }} + + - name: Create local AWS infrastructure + run: | + terraform -chdir=infrastructure init -backend=false -input=false + terraform -chdir=infrastructure apply -auto-approve -input=false + + - name: Run LocalStack integration test + run: python -m pytest tests/integration/test_localstack.py -v diff --git a/tests/integration/test_localstack.py b/tests/integration/test_localstack.py new file mode 100644 index 0000000..a53c4d5 --- /dev/null +++ b/tests/integration/test_localstack.py @@ -0,0 +1,59 @@ +import os +from uuid import uuid4 + +import pytest +from fastapi.testclient import TestClient + +from app.main import app +from app.storage import BUCKET_NAME, get_s3_client + + +client = TestClient(app) + + +@pytest.mark.skipif( + os.getenv("RUN_INTEGRATION_TESTS") != "1", + reason="Integration tests require LocalStack and Terraform infrastructure", +) +def test_artifact_storage_with_localstack() -> None: + artifact_name = f"integration-{uuid4().hex}.txt" + artifact_content = "Integration test successfully reached encrypted S3." + + s3_client = get_s3_client() + + try: + upload_response = client.post( + "/artifacts", + json={ + "name": artifact_name, + "content": artifact_content, + }, + ) + + assert upload_response.status_code == 201 + assert upload_response.json() == { + "name": artifact_name, + "status": "stored", + } + + list_response = client.get("/artifacts") + + assert list_response.status_code == 200 + assert artifact_name in list_response.json()["artifacts"] + + stored_object = s3_client.get_object( + Bucket=BUCKET_NAME, + Key=artifact_name, + ) + + stored_content = stored_object["Body"].read().decode("utf-8") + + assert stored_content == artifact_content + assert stored_object["ServerSideEncryption"] == "aws:kms" + assert stored_object["SSEKMSKeyId"] + + finally: + s3_client.delete_object( + Bucket=BUCKET_NAME, + Key=artifact_name, + ) \ No newline at end of file From 9ab130a03da294aea2a57a81f45b581dc7297330 Mon Sep 17 00:00:00 2001 From: Abdulrahman Abuzeid Date: Tue, 4 Aug 2026 20:48:41 +0200 Subject: [PATCH 2/2] Fix integration workflow indentation --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bf36979..6748ed1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,7 +79,7 @@ jobs: exit-code: "1" severity: CRITICAL,HIGH - integration-test: + integration-test: name: Test API with LocalStack needs: - test