⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content

Conversation

@tmikula-dev
Copy link
Collaborator

@tmikula-dev tmikula-dev commented Jan 20, 2026

Overview

This pull request refactors the EventGate Lambda entrypoint and related handler classes to improve modularity, testability, and maintainability. The main changes include extracting the OpenAPI handler into its own class, refactoring the topic handler.

Release Notes

  • Refactoring lambda module to OOP

Related

Closes #105

Summary by CodeRabbit

  • New Features

    • Added an API specification endpoint and a termination endpoint.
    • Access configuration can now be loaded from S3 or local files.
    • Routing consolidated into a centralized route map for simpler dispatch.
  • Bug Fixes

    • Improved error handling to return 500 on unexpected exceptions.
  • Tests

    • Added tests for API spec loading and access-config loading; updated topic-schema and local-access tests.

✏️ Tip: You can customize this high-level summary in your review settings.

@tmikula-dev tmikula-dev self-assigned this Jan 20, 2026
@tmikula-dev tmikula-dev added enhancement New feature or request refactoring Improving code quality, paying off tech debt, aligning APIs labels Jan 20, 2026
@github-actions
Copy link

AquaSec has completed a full security repository scan ✅ You can find the analysis results for this PR branch on this overview.
Below is the summary of the findings:

AQUASEC CRITICAL HIGH MEDIUM LOW TOTAL
sast 0 4 2 0 6
vulnerabilities 0 0 0 0 0
iacMisconfigurations 1 2 2 10 15
secrets 0 0 0 0 0
pipelineMisconfigurations 0 0 0 16 16
license 0 0 0 0 0
➡️ Total 1 6 4 26 37

@coderabbitai
Copy link

coderabbitai bot commented Jan 20, 2026

Walkthrough

Refactors the Lambda entry to a ROUTE_MAP-driven dispatcher, adds HandlerApi to serve api.yaml, updates HandlerTopic to load access config from S3 or local sources and to handle requests, and adjusts tests to cover the new handlers and configuration paths.

Changes

Cohort / File(s) Summary
Main Lambda Entry Point
src/event_gate_lambda.py
Replaced ad-hoc routing with ROUTE_MAP; centralized handler initialization (HandlerToken, HandlerTopic, HandlerHealth, HandlerApi) and AWS S3 client setup; removed get_api() and added /terminate route; expanded error handling (500 on unexpected exceptions).
New API Handler
src/handlers/handler_api.py
Added HandlerApi with load_api_definition() to read api.yaml and get_api() to return an HTTP-like response containing the YAML.
Topic Handler Refactoring
src/handlers/handler_topic.py
Constructor now accepts config and aws_s3; added load_access_config() to load access config from S3 or local file; introduced handle_request() and made topic schema/message methods private (_get_topic_schema, _post_topic_message).
Handler Tests
tests/handlers/test_handler_api.py, tests/handlers/test_handler_topic.py
New tests for HandlerApi loading and response; extended HandlerTopic tests to validate load_access_config from local and S3; updated test setups to use handler instances.
Config & Local Lambda Tests
tests/test_conf_validation.py, tests/test_event_gate_lambda_local_access.py
Updated schema discovery path to topic_schemas/*.json; adjusted assertions to use handler_topic.access_config instead of previous ACCESS.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Lambda
    participant ROUTE_MAP
    participant Handler
    participant ConfigS3

    Client->>Lambda: invoke with event/path
    Lambda->>ROUTE_MAP: lookup handler for path
    alt found
        ROUTE_MAP-->>Lambda: handler reference
        Lambda->>Handler: call handler.handle_request(event)
        Handler->>ConfigS3: load access_config / schemas (S3 or local)
        ConfigS3-->>Handler: return config/data
        Handler->>Handler: validate, extract token, process
        Handler-->>Lambda: response dict (statusCode, headers, body)
    else not found
        ROUTE_MAP-->>Lambda: no match
        Lambda-->>Client: 404 response
    end
    Lambda-->>Client: return HTTP response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • petr-pokorny-absa
  • lsulak
  • oto-macenauer-absa

Poem

🐰
I hopped through routes with a map so neat,
Swapped files for handlers and tidy dispatch feet.
S3 and schemas now dance in a row,
Api.yaml served with a soft yaml glow.
Hooray — OOP makes the code skip a beat!

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.00% 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
Title check ✅ Passed The title 'EventGate Lambda entrypoint OOP' clearly and concisely captures the main refactoring objective to convert the Lambda module to an object-oriented architecture.
Description check ✅ Passed The pull request description includes the required Overview and Release Notes sections, and correctly links to the related issue #105, following the template structure.
Linked Issues check ✅ Passed The code changes fully implement the stated objectives from issue #105: extracting handlers into OOP classes, consolidating routing via ROUTE_MAP, clearing top-level script code, and preparing architecture for future development.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the OOP refactoring objective. No unrelated modifications are present; even test updates support the handler restructuring.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/event_gate_lambda.py`:
- Around line 79-87: The /terminate route in ROUTE_MAP currently maps to an
unprotected lambda that calls sys.exit("TERMINATING"); remove or guard this
endpoint: either delete the "/terminate" entry from ROUTE_MAP, or replace it
with a dedicated terminate handler that first checks an environment flag (e.g.,
ENABLE_TERMINATE or only allow in non-production) and validates a
secret/authorization token from the request before calling sys.exit; ensure the
new handler is the symbol referenced in ROUTE_MAP instead of the direct lambda
so authorization and env checks run prior to invoking sys.exit("TERMINATING").

In `@src/handlers/handler_topic.py`:
- Around line 114-125: The handler reads event["pathParameters"]["topic_name"],
event["body"], and calls json.loads without validating, which raises
KeyError/TypeError/JSONDecodeError; update the function handling this request to
validate inputs: check event is a dict, ensure pathParameters exists and
contains a non-empty topic_name (normalize with .lower()), verify httpMethod is
present and supported, and for POST ensure event["body"] is not None and is
valid JSON before calling json.loads; on any client-side issue return
build_error_response(400, "request", "<clear message>") and for unsupported
methods return 404 as before; keep references to topic_name, _get_topic_schema,
_post_topic_message, handler_token.extract_token, and build_error_response when
implementing these checks.

In `@tests/handlers/test_handler_api.py`:
- Around line 1-5: Add the standard 2026 copyright header to the top of the new
test file tests/handlers/test_handler_api.py so it includes the required project
header for new Python files created in 2026; modify the top of the file (above
the imports) to insert the exact project copyright block used across the repo
(year 2026) to satisfy header checks.
🧹 Nitpick comments (2)
tests/test_conf_validation.py (1)

62-64: Assertion is ineffective with @pytest.mark.parametrize.

When the glob returns an empty list, pytest.mark.parametrize will simply skip the test (0 test cases generated) rather than fail it. The assert topic_file on line 64 will never execute if there are no files, so it cannot catch missing schema files.

Consider using a separate test or fixture to validate that schema files exist:

💡 Suggested approach
def test_topic_schemas_directory_has_files():
    """Ensure at least one topic schema exists."""
    files = glob(os.path.join(CONF_DIR, "topic_schemas", "*.json"))
    assert files, "No *.json files found in topic_schemas/"


`@pytest.mark.parametrize`("topic_file", glob(os.path.join(CONF_DIR, "topic_schemas", "*.json")))
def test_topic_json_schemas_basic(topic_file):
    schema = load_json(topic_file)
    # ... rest of validation
src/handlers/handler_api.py (1)

51-63: Consider handling uninitialized state.

get_api() returns an empty body if load_api_definition() was never called. While the current initialization flow in event_gate_lambda.py chains these calls correctly, a defensive check could improve robustness.

💡 Optional defensive check
     def get_api(self) -> Dict[str, Any]:
         """
         Return the OpenAPI specification.

         Returns:
             Dict[str, Any]: API Gateway response with OpenAPI spec.
         """
         logger.debug("Handling GET API")
+        if not self.api_spec:
+            logger.warning("API spec not loaded; returning empty response")
         return {
             "statusCode": 200,
             "headers": {"Content-Type": "application/yaml"},
             "body": self.api_spec,
         }

Comment on lines +79 to +87
# Route to handler function mapping
ROUTE_MAP: Dict[str, Any] = {
"/api": lambda _: handler_api.get_api(),
"/token": lambda _: handler_token.get_token_provider_info(),
"/health": lambda _: handler_health.get_health(),
"/topics": lambda _: handler_topic.get_topics_list(),
"/topics/{topic_name}": handler_topic.handle_request,
"/terminate": lambda _: sys.exit("TERMINATING"),
}
Copy link

@coderabbitai coderabbitai bot Jan 20, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, get the full context of the event_gate_lambda.py file
wc -l src/event_gate_lambda.py

Repository: AbsaOSS/EventGate

Length of output: 89


🏁 Script executed:

# Read the entire file to understand context
cat -n src/event_gate_lambda.py

Repository: AbsaOSS/EventGate

Length of output: 5115


🏁 Script executed:

# Search for authentication/authorization patterns
rg -n "auth" -i src/

Repository: AbsaOSS/EventGate

Length of output: 1070


🏁 Script executed:

# Search for API Gateway configuration
find . -name "*.yaml" -o -name "*.yml" -o -name "*.json" | head -20 | xargs grep -l "terminate\|authorize\|auth" 2>/dev/null || echo "No matches in config files"

Repository: AbsaOSS/EventGate

Length of output: 108


🏁 Script executed:

# Look for environment variable checks related to terminate or dev/prod
rg -n "environ|getenv|TERMINATE|DEV|PROD" src/event_gate_lambda.py

Repository: AbsaOSS/EventGate

Length of output: 111


🏁 Script executed:

# Search for the handler functions to understand flow
rg -n "def get_api|def get_token|def get_health|def get_topics|def handle_request" src/

Repository: AbsaOSS/EventGate

Length of output: 488


🏁 Script executed:

# Check if there's a decorator or middleware wrapping the routes
rg -n "@|middleware|decorator" src/event_gate_lambda.py

Repository: AbsaOSS/EventGate

Length of output: 43


🏁 Script executed:

# Check api.yaml for authorization and endpoint config
cat api.yaml | head -100

Repository: AbsaOSS/EventGate

Length of output: 2873


🏁 Script executed:

# Search for SAM template or CloudFormation config
find . -name "*.yaml" -o -name "*.yml" -o -name "*.json" | grep -E "(sam|cloudformation|template|serverless)" | head -10

Repository: AbsaOSS/EventGate

Length of output: 43


🏁 Script executed:

# Search for test files that might test the terminate endpoint
find . -name "*test*.py" -o -name "test_*.py" | xargs grep -l "terminate" 2>/dev/null || echo "No test files found with 'terminate'"

Repository: AbsaOSS/EventGate

Length of output: 97


🏁 Script executed:

# Search for any documentation or README mentioning terminate
rg -n "terminate" --type md --type txt . 2>/dev/null || echo "No docs found"

Repository: AbsaOSS/EventGate

Length of output: 299


🏁 Script executed:

# Look for deployment configuration in .github workflows
find .github -name "*.yaml" -o -name "*.yml" 2>/dev/null | xargs cat

Repository: AbsaOSS/EventGate

Length of output: 40342


🏁 Script executed:

# Search for any config files that might define environment or feature flags
find . -name "*.env*" -o -name "config*.json" -o -name "settings*.py" | head -10 | xargs cat 2>/dev/null || echo "No config files found"

Repository: AbsaOSS/EventGate

Length of output: 359


Remove or guard the /terminate endpoint.

The endpoint lacks authentication protection at the code level and can be called without credentials. While it's documented as "(internal)" for triggering cold starts, this lacks technical enforcement. An attacker with network access to the Lambda could repeatedly terminate instances, causing service disruption and increased cold start costs.

Recommended fixes:

  • Guard the endpoint behind an environment variable check (enable only in development)
  • Validate a secret/authorization token before allowing termination
  • Remove the endpoint entirely and use Lambda lifecycle hooks or external orchestration for config reloads
🤖 Prompt for AI Agents
In `@src/event_gate_lambda.py` around lines 79 - 87, The /terminate route in
ROUTE_MAP currently maps to an unprotected lambda that calls
sys.exit("TERMINATING"); remove or guard this endpoint: either delete the
"/terminate" entry from ROUTE_MAP, or replace it with a dedicated terminate
handler that first checks an environment flag (e.g., ENABLE_TERMINATE or only
allow in non-production) and validates a secret/authorization token from the
request before calling sys.exit; ensure the new handler is the symbol referenced
in ROUTE_MAP instead of the direct lambda so authorization and env checks run
prior to invoking sys.exit("TERMINATING").

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This issue is not part of this PR, the potential issue was not created inside this PR.

Copy link

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check git history for when the /terminate endpoint was introduced
echo "=== Searching for 'terminate' in git history for src/event_gate_lambda.py ==="
git log -p --all -S "terminate" -- src/event_gate_lambda.py | head -100

echo ""
echo "=== Checking the file before this PR (master branch) ==="
git show master:src/event_gate_lambda.py | grep -n "terminate" -i -C 3 || echo "No 'terminate' found in master branch version"

echo ""
echo "=== Checking all commits that modified this file ==="
git log --oneline --all -- src/event_gate_lambda.py | head -10

Length of output: 1171


@tmikula-dev You're absolutely right—I apologize for the confusion. The /terminate endpoint already existed in the master branch (line 130) before this PR. Your refactoring simply moved the existing route handling from if-statements to the new ROUTE_MAP structure. The security concern, while potentially valid, is a pre-existing issue and not something introduced by your changes.

Thank you for the clarification! 🐰

 />  />
(• ་ •)
|    つ  oops!
 ◡◡◡

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

Labels

enhancement New feature or request refactoring Improving code quality, paying off tech debt, aligning APIs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lambda module OOP

2 participants