Skip to content

Implement infrastructure integration testing suite using LocalStack#5190

Open
arkid15r wants to merge 3 commits into
mainfrom
feature/infrastructure-integration-tests
Open

Implement infrastructure integration testing suite using LocalStack#5190
arkid15r wants to merge 3 commits into
mainfrom
feature/infrastructure-integration-tests

Conversation

@arkid15r

Copy link
Copy Markdown
Collaborator

Proposed change

Merge infrastructure integration branch into main.

Checklist

  • Required: I followed the contributing workflow
  • Required: I verified that my code works as intended and resolves the issue as described
  • Required: I ran all required checks and tests locally; all warnings addressed and failures resolved
  • I used AI for code, documentation, tests, or communication related to this PR

…tack and Terraform (#5122)

* feat: implement infrastructure integration testing suite using LocalStack and Terraform

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

fix: align AWS provider version constraint to ~> 6.36.0 across storage modules

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

Revert "fix: align AWS provider version constraint to ~> 6.36.0 across storage modules"

This reverts commit 8403b28.

fix: bump AWS provider to ~> 6.53.0 across all modules and address review feedback

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

* Guard against an empty LocalStack image tag before starting the container

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

* fix: correct region identifier usage in KMS policy and document TF_PLUGIN_CACHE_DIR requirement

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

* refactor: consolidate override file paths and resource names into a single array for easier management

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

* chore: update LocalStack Dockerfile to run as non-root user

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

* Update code

* refactor: replace shell-based test and tag scripts with a consolidated Python implementation

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

* extract LocalStack readiness check into a helper function

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

* reduced the cognitive complexity of each function

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

* refactor: replace sys.exit calls with TestRunnerError and improve localstack container management

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>

* Update code

* Update permissions

---------

Signed-off-by: Nachiket Roy <nachiket.roy.2@gmail.com>
Co-authored-by: Arkadii Yakovets <arkadii.yakovets@owasp.org>
@github-actions github-actions Bot added docs Improvements or additions to documentation docker Pull requests that update Docker code makefile ci infrastructure labels Jul 12, 2026
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Infrastructure testing is reorganized around reusable Terraform and Poetry actions, Dockerized unit and LocalStack integration environments, Python-based orchestration, new Terraform module integration tests, and expanded CI workflow coverage.

Changes

Infrastructure testing

Layer / File(s) Summary
CI environment and workflow wiring
.github/actions/*, .github/workflows/*
Terraform and dependency setup is centralized in local composite actions, while CI forwards LOCALSTACK_AUTH_TOKEN and separates infrastructure unit and integration jobs.
Docker test runtime and local commands
.gitignore, .trivyignore.yaml, docker-compose/infrastructure/*, docker/infrastructure/*, docker/localstack/*, infrastructure/Makefile, infrastructure/README.md, infrastructure/poetry.toml, infrastructure/pyproject.toml, Makefile
Docker images, Compose services, Make targets, Poetry configuration, and documentation define infrastructure unit and LocalStack integration test execution.
Test runner and LocalStack orchestration
infrastructure/scripts/*
New Python utilities handle command execution, Terraform test discovery, LocalStack lifecycle management, temporary overrides, and CLI dispatch.
Terraform module integration coverage
infrastructure/modules/*/tests/*, infrastructure/modules/storage/modules/s3-bucket/*
Integration tests validate ECR, KMS, SSM parameters, storage policies, and server-side encryption output wiring.
Runner and orchestration tests
infrastructure/tests/scripts/*
Pytest coverage validates command handling, LocalStack behavior, runner lifecycle branches, CLI errors, and Terraform test failures.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • OWASP/Nest#5076 — Both PRs modify infrastructure Makefile test execution and module discovery.
  • OWASP/Nest#5122 — Both PRs modify the LocalStack-backed integration flow, Terraform setup action, and CI wiring.

Suggested labels: infrastructure, ci, docker, makefile

Suggested reviewers: kasya, rudransh-shrivastava

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.12% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: adding a LocalStack-based infrastructure integration testing suite.
Description check ✅ Passed The description is related to the PR, describing the merge of the infrastructure integration branch into main.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/infrastructure-integration-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.86%. Comparing base (fccd43f) to head (f8b6bd7).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #5190   +/-   ##
=======================================
  Coverage   98.86%   98.86%           
=======================================
  Files         536      536           
  Lines       17072    17072           
  Branches     2451     2451           
=======================================
  Hits        16878    16878           
  Misses         97       97           
  Partials       97       97           
Flag Coverage Δ
backend 99.37% <ø> (ø)
frontend 97.41% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fccd43f...f8b6bd7. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 39 files

Confidence score: 5/5

  • In infrastructure/scripts/commands.py, command execution changes currently lack direct regression tests, so argv/subprocess option drift could silently break Terraform or Docker calls in a future edit; this looks low risk for now, but add mocked subprocess.run tests around resolved executable/argument construction before or immediately after merging to de-risk follow-on regressions.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="infrastructure/scripts/commands.py">

<violation number="1" location="infrastructure/scripts/commands.py:30">
P3: Command execution has no direct regression coverage, so changes to argv construction or subprocess options can break Terraform/Docker invocation undetected. Add mocked `subprocess.run` coverage for resolved executable, arguments, and both options.

(Based on your team's feedback about tests for new utility logic.) [FEEDBACK_USED]</violation>
</file>

Tip: cubic used a learning from your PR history. Let your coding agent read cubic learnings directly with the cubic MCP.

Re-trigger cubic

Comment thread infrastructure/scripts/runner.py
Comment thread infrastructure/scripts/localstack.py Outdated
Comment thread infrastructure/scripts/terraform_tests.py
Comment thread infrastructure/Makefile Outdated
Comment thread .github/workflows/run-infrastructure-tests.yaml Outdated
) -> subprocess.CompletedProcess[str]:
"""Run an executable resolved from PATH with fixed argv arguments."""
executable = self.require(command)
return subprocess.run(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Command execution has no direct regression coverage, so changes to argv construction or subprocess options can break Terraform/Docker invocation undetected. Add mocked subprocess.run coverage for resolved executable, arguments, and both options.

(Based on your team's feedback about tests for new utility logic.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At infrastructure/scripts/commands.py, line 30:

<comment>Command execution has no direct regression coverage, so changes to argv construction or subprocess options can break Terraform/Docker invocation undetected. Add mocked `subprocess.run` coverage for resolved executable, arguments, and both options.

(Based on your team's feedback about tests for new utility logic.) </comment>

<file context>
@@ -0,0 +1,35 @@
+    ) -> subprocess.CompletedProcess[str]:
+        """Run an executable resolved from PATH with fixed argv arguments."""
+        executable = self.require(command)
+        return subprocess.run(
+            [executable, *args],
+            check=check,
</file context>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docker/infrastructure/Dockerfile.tests`:
- Around line 4-6: Update the Terraform base image declaration in the terraform
stage of Dockerfile.tests from hashicorp/terraform:1.14.6 to
hashicorp/terraform:1.15.8, leaving the Python and LocalStack image pins
unchanged.

In `@infrastructure/Makefile`:
- Around line 50-51: Update the test-infrastructure-integration recipe around
build-infrastructure-test-image to stop immediately when the image build fails,
replacing the unconditional command sequencing so status=0 and subsequent
compose execution cannot overwrite or obscure the original build error.

In `@infrastructure/scripts/runner.py`:
- Around line 91-94: Update the runner’s finally block so self.localstack.stop()
executes in a nested finally after self.overrides.cleanup(), while retaining the
localstack_started guard. Ensure unexpected cleanup failures still propagate
without preventing shutdown of a LocalStack instance started by the runner.

In `@infrastructure/scripts/terraform_tests.py`:
- Around line 86-110: Update run_module_tests so both Terraform
self.commands.run invocations use capture_output=True, then append each result’s
stderr to its corresponding TestRunnerError message while retaining the module
directory context.

In `@infrastructure/tests/scripts/localstack_test.py`:
- Around line 62-104: Add negative-path tests alongside test_image_info_pro,
test_image_info_standard, and test_start_success. Cover LocalStack.image_info()
raising the expected errors for a missing Dockerfile, no matching FROM line, and
an unparsable tag; also verify LocalStack.start() raises MissingAuthTokenError
when LOCALSTACK_AUTH_TOKEN is absent and TestRunnerError when CommandRunner.run
fails.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: cca63467-7470-4f2e-9ca8-47b1c235b5e7

📥 Commits

Reviewing files that changed from the base of the PR and between fccd43f and 0dfa82f.

⛔ Files ignored due to path filters (1)
  • infrastructure/poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (38)
  • .github/actions/apply-infrastructure-changes/action.yaml
  • .github/actions/install-infrastructure-dependencies/action.yaml
  • .github/actions/setup-terraform-environment/action.yaml
  • .github/workflows/ci.yaml
  • .github/workflows/run-code-checks.yaml
  • .github/workflows/run-code-tests.yaml
  • .github/workflows/run-infrastructure-tests.yaml
  • .gitignore
  • .trivyignore.yaml
  • Makefile
  • cspell/custom-dict.txt
  • docker-compose/infrastructure/compose.yaml
  • docker/infrastructure/Dockerfile.tests
  • docker/localstack/Dockerfile
  • infrastructure/Makefile
  • infrastructure/README.md
  • infrastructure/modules/ecr-cache/tests/integration.tftest.hcl
  • infrastructure/modules/kms/tests/integration.tftest.hcl
  • infrastructure/modules/parameters/tests/integration.tftest.hcl
  • infrastructure/modules/storage/modules/s3-bucket/README.md
  • infrastructure/modules/storage/modules/s3-bucket/outputs.tf
  • infrastructure/modules/storage/tests/integration.tftest.hcl
  • infrastructure/poetry.toml
  • infrastructure/pyproject.toml
  • infrastructure/scripts/__init__.py
  • infrastructure/scripts/commands.py
  • infrastructure/scripts/errors.py
  • infrastructure/scripts/localstack.py
  • infrastructure/scripts/run_tests.py
  • infrastructure/scripts/runner.py
  • infrastructure/scripts/terraform_tests.py
  • infrastructure/tests/__init__.py
  • infrastructure/tests/scripts/__init__.py
  • infrastructure/tests/scripts/commands_test.py
  • infrastructure/tests/scripts/localstack_test.py
  • infrastructure/tests/scripts/run_tests_test.py
  • infrastructure/tests/scripts/runner_test.py
  • infrastructure/tests/scripts/terraform_tests_test.py

Comment thread docker/infrastructure/Dockerfile.tests Outdated
Comment thread infrastructure/Makefile Outdated
Comment thread infrastructure/scripts/runner.py Outdated
Comment thread infrastructure/scripts/terraform_tests.py Outdated
Comment thread infrastructure/tests/scripts/localstack_test.py
@github-actions

Copy link
Copy Markdown

Contribution validation failed:

  • commit_sign_off: One or more commits are missing or have an invalid Signed-off-by trailer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
infrastructure/scripts/runner.py (1)

97-100: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard stop() against cleanup() failures to prevent container leaks.

This concern was raised previously and remains unaddressed. If self.overrides.cleanup() raises an unexpected (non-OSError) exception, self.localstack.stop() is skipped, leaving the container running. A nested try/finally ensures the container is always stopped when the runner started it.

🔒 Proposed fix for finally block ordering
         finally:
-            self.overrides.cleanup()
-            if localstack_started:
-                self.localstack.stop()
+            try:
+                self.overrides.cleanup()
+            finally:
+                if localstack_started:
+                    self.localstack.stop()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infrastructure/scripts/runner.py` around lines 97 - 100, Update the cleanup
logic in the runner’s finally block so self.localstack.stop() is executed in a
nested finally whenever localstack_started is true, even if
self.overrides.cleanup() raises an unexpected exception. Preserve the existing
cleanup call and conditional container-stop behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@infrastructure/tests/scripts/commands_test.py`:
- Around line 63-69: In test_run_missing_command, instantiate CommandRunner
before entering the pytest.raises block, then invoke only its run method inside
the block while preserving the existing mocks and assertion that subprocess.run
is not called.

In `@infrastructure/tests/scripts/localstack_test.py`:
- Around line 87-91: Hoist LocalStack() construction outside each pytest.raises
block in the five flagged tests: test_image_info_missing_dockerfile, the
adjacent image_info error tests, and the start-related tests. Keep only the
intended image_info(...) or start(...) invocation inside pytest.raises so the
expected exception source is unambiguous.

In `@infrastructure/tests/scripts/terraform_tests_test.py`:
- Around line 70-82: Hoist the TerraformTests construction out of the
pytest.raises blocks in both init-failure tests: assign TerraformTests(commands)
to a local variable before each assertion, then invoke run_module_tests on that
variable inside pytest.raises while preserving the existing assertions.

---

Duplicate comments:
In `@infrastructure/scripts/runner.py`:
- Around line 97-100: Update the cleanup logic in the runner’s finally block so
self.localstack.stop() is executed in a nested finally whenever
localstack_started is true, even if self.overrides.cleanup() raises an
unexpected exception. Preserve the existing cleanup call and conditional
container-stop behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 22626072-f441-476b-b2bd-80b5ac174290

📥 Commits

Reviewing files that changed from the base of the PR and between 0dfa82f and 41e9a18.

📒 Files selected for processing (12)
  • .github/workflows/run-infrastructure-tests.yaml
  • docker/infrastructure/Dockerfile.tests
  • infrastructure/Makefile
  • infrastructure/scripts/localstack.py
  • infrastructure/scripts/run_tests.py
  • infrastructure/scripts/runner.py
  • infrastructure/scripts/terraform_tests.py
  • infrastructure/tests/scripts/commands_test.py
  • infrastructure/tests/scripts/localstack_test.py
  • infrastructure/tests/scripts/run_tests_test.py
  • infrastructure/tests/scripts/runner_test.py
  • infrastructure/tests/scripts/terraform_tests_test.py

Comment thread infrastructure/tests/scripts/commands_test.py
Comment thread infrastructure/tests/scripts/localstack_test.py Outdated
Comment thread infrastructure/tests/scripts/terraform_tests_test.py

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 12 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread infrastructure/Makefile
@github-actions

Copy link
Copy Markdown

Contribution validation failed:

  • commit_sign_off: One or more commits are missing or have an invalid Signed-off-by trailer.

@sonarqubecloud

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 5 files (changes from recent commits).

Requires human review: Auto-approval blocked by 1 unresolved issue from previous reviews.

Re-trigger cubic

@arkid15r
arkid15r marked this pull request as ready for review July 12, 2026 20:09
@arkid15r

Copy link
Copy Markdown
Collaborator Author

@Nachiket-Roy @rudransh-shrivastava could you review this one?

Thank you!



if __name__ == "__main__":
main()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add an unit test to assert try/finally cleanup execution & order

"""Raise if any override file already exists on disk."""
for filepath, _ in self.overrides:
if Path(filepath).exists():
raise OverrideExistsError(filepath)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The makefile clean the temporary overrides files should it be added here too? to be safe?


def find_test_dirs(self) -> list[str]:
"""Return sorted ``tests`` directories under the search roots."""
test_dirs: list[str] = []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should prune .terraform from dirs in-place to avoid traversing provider cache trees and slowing down test runs.

localstack.start.assert_not_called()
localstack.wait_ready.assert_called_once()
localstack.stop.assert_not_called()
terraform_tests.discover_and_run.assert_called_once_with("integration")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No test verifies that discover_and_run() correctly raises a TestRunnerError if no tests are found/matched.

cache_dir = Path.home() / ".terraform.d" / "plugin-cache"
try:
cache_dir.mkdir(parents=True, exist_ok=True)
os.environ["TF_PLUGIN_CACHE_DIR"] = str(cache_dir)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should check if TF_PLUGIN_CACHE_DIR is already set in the environment before unconditionally overwriting it.

skip_metadata_api_check = true
skip_requesting_account_id = true
endpoints {
ecr = "http://localhost:4566"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious if its possible to use tflocal to run these tests instead of hardcoding http://localhost:4566

@Nachiket-Roy Nachiket-Roy Jul 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I checked out tflocal. It relies on generated override files and adds another dependency, whereas we can use AWS_ENDPOINT_URL which is supported natively by the AWS provider. Check it out and LMK

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arkid15r arkid15r changed the title Iimplement infrastructure integration testing suite using LocalStack Implement infrastructure integration testing suite using LocalStack Jul 17, 2026
@github-actions

Copy link
Copy Markdown

Contribution validation failed:

  • commit_sign_off: One or more commits are missing or have an invalid Signed-off-by trailer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci docker Pull requests that update Docker code docs Improvements or additions to documentation infrastructure makefile

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants