Skip to content

Conversation

@omertuc
Copy link
Contributor

@omertuc omertuc commented Oct 8, 2025

Description

This commit adds end-to-end tests for the authorization functionality.

Implementation details

  • Modified .gitignore to ignore leftover config backup files
    (unrelated to this change but useful)
  • Updated testing documentation to include instructions for running e2e
    tests
  • Added a JWK server container to docker-compose.yaml which is needed
    for e2e testing JWK auth
  • Added a tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml
    config file for lightspeed-stack with JWK auth enabled to be used in
    the JWK e2e tests
  • Removed hard dependency on the docker command in e2e tests and
    instead use the CONTAINER_CMD environment variable if set (to allow
    using podman instead of docker)
  • Added tests/e2e/features/authorization_jwk.feature which contains
    the actual e2e tests for JWK authz
  • Added tests/e2e/features/steps/jwk_auth.py which implements the
    steps for the JWK authz tests
  • Modified tests/e2e/features/environment.py to handle the new JWK
    authz tests, including creating a temporary JWK key pair for the
    tests and writing the public key to a file served by the JWK server
    container (which lightspeed-stack is directed to access through the
    config file mentioned above)
    functionality to functions that can be reused in the e2e tests
  • Added tests/e2e/configuration/test_jwk/.gitignore to ignore
    generated JWK files
  • Updated tests/e2e/test_list.txt to include the new JWK authz tests

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement

Related Tickets & Documents

  • Related Issue #
  • Closes #

LCORE-598

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • Please provide detailed steps to perform tests related to this code change.
  • How were the fix/results from this change verified? Please provide relevant screenshots or results.

Summary by CodeRabbit

  • Documentation

    • Added E2E testing prerequisites with container choice (docker/podman), OpenAI key notes, and example commands.
  • Tests

    • Added end-to-end coverage for JWK-based authentication and role-based authorization (admin/config/readonly).
    • Added a local JWK test server to the compose setup.
    • Test tooling now respects CONTAINER_CMD for container operations.
    • Improved unit test helpers for JWT/JWKS generation.
  • Chores

    • Updated ignore rules to exclude backup and generated JWK JSON files.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 8, 2025

Walkthrough

Adds JWK-based end-to-end authentication tests and supporting infra: new test JWK server service, E2E configuration/feature/step and environment wiring to generate and mount JWKS, parameterizes container CLI via CONTAINER_CMD, updates unit test JWKS/JWT helpers, docs, and ignore rules.

Changes

Cohort / File(s) Summary
Ignore rules
\.gitignore, tests/e2e/configuration/test_jwk/.gitignore
Add lightspeed-stack.yaml.backup to repo ignore and ignore generated JWK JSON files used by E2E tests.
Compose: test JWK server
docker-compose.yaml
Add test-jwk-server service that builds from the existing Containerfile, serves jwk.json via Python http.server on port 16161, mounts ./tests/e2e/configuration/test_jwk, and joins lightspeednet.
Docs: E2E prerequisites
docs/testing.md
Add "Prerequisites for E2E tests" section with podman/docker-compose notes, build/up/test commands, and example test invocation.
E2E config for JWK auth
tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml, tests/e2e/configuration/test_jwk/*
New LCS config enabling jwk-token auth, JWKS URL, JWT claim-to-role mapping (role_rules JSONPath), access_rules, and directory for generated jwk.json.
E2E feature/tests list
tests/e2e/features/authorization_jwk.feature, tests/e2e/test_list.txt
New feature validating role-based access for /v1/info and /v1/config across admin/config/readonly roles; feature added to test list.
E2E harness: env/health/utils
tests/e2e/features/environment.py, tests/e2e/features/steps/health.py, tests/e2e/utils/utils.py
Parameterize container CLI via CONTAINER_CMD (default docker); add JWKAuth before/after feature flow that generates JWKS file, backs up/switches config, restarts container, and restores on cleanup; update health/restart helpers to use CONTAINER_CMD.
E2E step: JWT creation
tests/e2e/features/steps/jwk_auth.py
New step to create an RS256 JWT with a specified role using test key helpers and set Authorization header in test context.
Unit test helpers (JWK/JWT)
tests/unit/authentication/test_jwk_token.py
Add typed helpers and fixtures: GeneratedKey alias, create_token_header, create_token_payload, create_jwks_keys, typed make_key/fixtures, and adapt mock signing server to return JWKS from the builder.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant T as E2E Tests
  participant J as Test JWK Server (http://localhost:16161/jwk.json)
  participant L as Lightspeed Core Service (LCS)
  participant U as Upstream Llama Stack

  rect rgba(200,230,255,0.25)
  note over T: Before feature (JWKAuth)
  T->>J: Write generated jwk.json (mounted volume)
  T->>L: Swap to lightspeed-stack-auth-jwk.yaml and restart container
  L->>J: Fetch JWKS from /jwk.json
  J-->>L: JWKS keys
  end

  rect rgba(220,255,220,0.25)
  note over T,L: Scenario request
  T->>T: Create RS256 JWT with roles
  T->>L: HTTP request with Authorization: Bearer <jwt>
  L->>L: Validate JWT via JWKS and evaluate role_rules
  alt Authorized
    L->>U: Optional upstream call
    U-->>L: Response
    L-->>T: 200 OK
  else Forbidden
    L-->>T: 403 Insufficient permissions
  end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • tisnik

Poem

In burrows of bytes I nudge a key,
I craft a jwk for tests to see.
Tokens hop in a header bright,
Roles find doors beneath moonlight.
Thump—compose spins; tests take flight. 🐇🔐

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “LCORE-598: Add authorization e2e tests” accurately and concisely summarizes the primary change by referencing the ticket and describing the addition of end-to-end authorization tests, matching the PR’s objectives without extraneous details.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
Contributor

@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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/e2e/features/environment.py (1)

25-28: Remove unused try-except block.

Lines 25-28 contain a try-except block that attempts to import os, which is already imported at line 10. This appears to be legacy code and serves no purpose.

Apply this diff to remove the unused code:

-try:
-    import os  # noqa: F401
-except ImportError as e:
-    print("Warning: unable to import module:", e)
-
tests/unit/authentication/test_jwk_token.py (1)

31-38: Add type annotations.

The function lacks a return type annotation.

As per coding guidelines, all functions require complete type annotations. Apply this diff:

-def create_token_payload():
+def create_token_payload() -> dict[str, str | int]:
     """Create a sample token payload with the default user_id and username claims."""
     return {
         "user_id": TEST_USER_ID,
         "username": TEST_USER_NAME,
         "exp": int(time.time()) + 3600,
         "iat": int(time.time()),
     }

Based on coding guidelines.

🧹 Nitpick comments (3)
docker-compose.yaml (1)

45-61: Consider adding a healthcheck for the test-jwk-server.

While the simple http.server is likely to start quickly, adding a healthcheck would ensure consistency with other services and allow dependent services to wait for JWK server readiness if needed.

Example healthcheck:

    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:16161/"]
      interval: 5s
      timeout: 3s
      retries: 2
      start_period: 5s
tests/e2e/features/steps/jwk_auth.py (1)

12-18: Consider restructuring imports to avoid sys.path manipulation.

The sys.path.append workaround and the comment about "module load issues" suggest a structural concern. While this works for tests, it would be cleaner to ensure the test package structure allows direct imports.

Consider one of these approaches:

  • Install the package in editable mode (pip install -e .) so all modules are importable
  • Use relative imports if the test structure permits
  • Add an __init__.py to make tests a proper package

That said, this pattern is acceptable for E2E tests if restructuring is not feasible at this time.

tests/e2e/features/environment.py (1)

115-126: Refactor to use context.feature_config consistently.

Line 125 hardcodes the config path that's already stored in context.feature_config on line 117. Additionally, the file write operation (lines 119-122) lacks error handling.

Apply this diff to improve consistency and add error handling:

     elif "JWKAuth" in feature.tags:
         context.feature_config = (
             "tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml"
         )
-        with open("tests/e2e/configuration/test_jwk/jwk.json", "w") as f:
-            context.test_key = make_key()
-            keys = create_jwks_keys([context.test_key], ["RS256"])
-            f.write(json.dumps(keys))
+        try:
+            with open("tests/e2e/configuration/test_jwk/jwk.json", "w") as f:
+                context.test_key = make_key()
+                keys = create_jwks_keys([context.test_key], ["RS256"])
+                f.write(json.dumps(keys))
+        except (IOError, OSError) as e:
+            print(f"Failed to write JWK file: {e}")
+            raise
 
         context.default_config_backup = create_config_backup("lightspeed-stack.yaml")
-        switch_config("tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml")
+        switch_config(context.feature_config)
         restart_container("lightspeed-stack")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 690a6bc and c57a847.

📒 Files selected for processing (12)
  • .gitignore (1 hunks)
  • docker-compose.yaml (1 hunks)
  • docs/testing.md (1 hunks)
  • tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml (1 hunks)
  • tests/e2e/configuration/test_jwk/.gitignore (1 hunks)
  • tests/e2e/features/authorization_jwk.feature (1 hunks)
  • tests/e2e/features/environment.py (5 hunks)
  • tests/e2e/features/steps/health.py (3 hunks)
  • tests/e2e/features/steps/jwk_auth.py (1 hunks)
  • tests/e2e/test_list.txt (1 hunks)
  • tests/e2e/utils/utils.py (2 hunks)
  • tests/unit/authentication/test_jwk_token.py (4 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: All modules start with descriptive module-level docstrings explaining purpose
Use logger = logging.getLogger(name) for module logging after import logging
Define type aliases at module level for clarity
All functions require docstrings with brief descriptions
Provide complete type annotations for all function parameters and return types
Use typing_extensions.Self in model validators where appropriate
Use modern union syntax (str | int) and Optional[T] or T | None consistently
Function names use snake_case with descriptive, action-oriented prefixes (get_, validate_, check_)
Avoid in-place parameter modification; return new data structures instead of mutating arguments
Use appropriate logging levels: debug, info, warning, error with clear messages
All classes require descriptive docstrings explaining purpose
Class names use PascalCase with conventional suffixes (Configuration, Error/Exception, Resolver, Interface)
Abstract base classes should use abc.ABC and @AbstractMethod for interfaces
Provide complete type annotations for all class attributes
Follow Google Python docstring style for modules, classes, and functions, including Args, Returns, Raises, Attributes sections as needed

Files:

  • tests/e2e/features/steps/jwk_auth.py
  • tests/e2e/utils/utils.py
  • tests/e2e/features/steps/health.py
  • tests/unit/authentication/test_jwk_token.py
  • tests/e2e/features/environment.py
tests/e2e/features/steps/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Place behave step definitions under tests/e2e/features/steps/

Files:

  • tests/e2e/features/steps/jwk_auth.py
  • tests/e2e/features/steps/health.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use pytest-mock to create AsyncMock objects for async interactions in tests
Use the shared auth mock constant: MOCK_AUTH = ("mock_user_id", "mock_username", False, "mock_token") in tests

Files:

  • tests/e2e/features/steps/jwk_auth.py
  • tests/e2e/utils/utils.py
  • tests/e2e/features/steps/health.py
  • tests/unit/authentication/test_jwk_token.py
  • tests/e2e/features/environment.py
tests/{unit,integration}/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/{unit,integration}/**/*.py: Use pytest for all unit and integration tests
Do not use unittest in tests; pytest is the standard

Files:

  • tests/unit/authentication/test_jwk_token.py
tests/e2e/test_list.txt

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain the E2E test list in tests/e2e/test_list.txt

Files:

  • tests/e2e/test_list.txt
tests/e2e/features/**/*.feature

📄 CodeRabbit inference engine (CLAUDE.md)

Write E2E tests as Gherkin feature files for behave

Files:

  • tests/e2e/features/authorization_jwk.feature
🧠 Learnings (1)
📚 Learning: 2025-09-18T16:46:33.353Z
Learnt from: CR
PR: lightspeed-core/lightspeed-stack#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-18T16:46:33.353Z
Learning: Applies to tests/e2e/test_list.txt : Maintain the E2E test list in tests/e2e/test_list.txt

Applied to files:

  • tests/e2e/test_list.txt
🧬 Code graph analysis (2)
tests/e2e/features/steps/jwk_auth.py (1)
tests/unit/authentication/test_jwk_token.py (2)
  • create_token_header (20-22)
  • create_token_payload (31-38)
tests/e2e/features/environment.py (2)
tests/unit/authentication/test_jwk_token.py (2)
  • create_jwks_keys (94-105)
  • make_key (47-54)
tests/e2e/utils/utils.py (3)
  • create_config_backup (108-117)
  • switch_config (97-105)
  • restart_container (129-143)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-pr
  • GitHub Check: e2e_tests (ci)
🔇 Additional comments (14)
docs/testing.md (1)

144-177: LGTM! Well-documented E2E test prerequisites.

The new section clearly explains how to run E2E tests with both docker-compose and podman-compose, including the CONTAINER_CMD environment variable override. The practical example of running a specific test with live output is particularly helpful.

tests/e2e/test_list.txt (1)

11-11: LGTM! Test list correctly updated.

The new JWK authorization test has been appropriately added to the E2E test list.

tests/e2e/configuration/test_jwk/.gitignore (1)

1-2: LGTM! Appropriate ignore rule for generated test artifacts.

The gitignore pattern correctly excludes generated JWK JSON files from version control, with a clear comment explaining the purpose.

.gitignore (1)

191-193: LGTM! Backup file correctly ignored.

The ignore rule appropriately excludes the temporary backup file created during E2E tests. The comment clearly explains the purpose.

tests/e2e/utils/utils.py (2)

40-40: LGTM! Parameterized container command enables podman support.

The change to use os.getenv("CONTAINER_CMD", "docker") appropriately enables runtime selection of the container command while maintaining backward compatibility.


133-133: LGTM! Consistent container command parameterization.

The same pattern applied to restart_container maintains consistency across the codebase.

tests/e2e/features/steps/health.py (1)

3-3: LGTM! Consistent container command parameterization in test steps.

The changes appropriately enable runtime selection of the container command for both inspection and stop operations, maintaining consistency with other E2E test utilities.

Also applies to: 18-24, 33-36

tests/e2e/features/steps/jwk_auth.py (2)

1-11: LGTM!

The module docstring and imports are appropriate for a Behave step definition file.


21-41: No guard needed for context.test_key. The before_scenario hook initializes context.test_key for every @JWKAuth scenario (as seen in environment.py), and all uses of create_role_token are within those scenarios.

tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml (1)

1-52: LGTM!

The JWK authentication configuration is well-structured:

  • The JWK server URL points to the test server container
  • Role mappings correctly transform external claims to internal roles
  • Authorization rules properly map roles to permitted actions

This configuration aligns well with the test infrastructure in environment.py and the step definitions in jwk_auth.py.

tests/e2e/features/environment.py (2)

62-74: LGTM!

The parameterization of the container command via the CONTAINER_CMD environment variable is a good improvement that enables support for alternative container runtimes like Podman.


134-137: LGTM!

The cleanup logic correctly includes JWKAuth scenarios alongside Authorized scenarios, ensuring proper restoration of configuration and container state.

tests/unit/authentication/test_jwk_token.py (2)

26-44: LGTM!

Good refactoring to extract token creation logic into reusable helpers. The fixtures now properly delegate to the helper functions, improving maintainability and enabling reuse in E2E tests.


108-115: LGTM!

The refactoring to use create_jwks_keys improves code consistency and reduces duplication.

Copy link
Contributor

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/unit/authentication/test_jwk_token.py (1)

31-38: Add type annotations.

The function lacks type annotations for its return type, which violates the coding guidelines. This is similar to the issues already flagged for other helper functions in this file.

As per coding guidelines, apply this diff:

-def create_token_payload():
+def create_token_payload() -> dict[str, str | int]:
     """Create a sample token payload with the default user_id and username claims."""
     return {
         "user_id": TEST_USER_ID,
         "username": TEST_USER_NAME,
         "exp": int(time.time()) + 3600,
         "iat": int(time.time()),
     }

Based on coding guidelines.

🧹 Nitpick comments (9)
tests/e2e/features/environment.py (1)

115-127: Add error handling for file operations.

The code writes to a JWK configuration file without checking if the directory exists or handling potential I/O errors. If the directory tests/e2e/configuration/test_jwk/ doesn't exist, the test will fail with an unclear error.

Apply this diff to add directory creation and error handling:

     elif "JWKAuth" in feature.tags:
         context.feature_config = (
             "tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml"
         )
-        with open("tests/e2e/configuration/test_jwk/jwk.json", "w") as f:
+        jwk_dir = "tests/e2e/configuration/test_jwk"
+        os.makedirs(jwk_dir, exist_ok=True)
+        jwk_path = os.path.join(jwk_dir, "jwk.json")
+        with open(jwk_path, "w") as f:
             context.test_key = make_key()
             keys = create_jwks_keys([context.test_key], ["RS256"])
             f.write(json.dumps(keys))
tests/unit/authentication/test_jwk_token.py (1)

41-44: Consider removing redundant fixture wrapper.

The token_payload fixture simply wraps a call to create_token_payload() without adding any value. Since create_token_payload() is already a standalone function, tests that need a fresh payload can call it directly, reducing indirection.

If you prefer to keep the fixture for consistency with the existing test structure, you can ignore this suggestion. Otherwise, consider removing the fixture and updating call sites to use create_token_payload() directly.

docker-compose.yaml (7)

58-58: Bind explicitly to 0.0.0.0 for predictability.

Make the bind address explicit to avoid surprises across Python versions/runtimes.

-    entrypoint: ["python3", "-m", "http.server", "16161"]
+    entrypoint: ["python3", "-m", "http.server", "16161", "--bind", "0.0.0.0"]

60-60: Mount JWK directory read-only.

The server only needs to read JWKS. Tighten perms with ro,Z.

-      - ./tests/e2e/configuration/test_jwk:/app-root/test_jwk:Z
+      - ./tests/e2e/configuration/test_jwk:/app-root/test_jwk:ro,Z

53-59: Add a healthcheck for the JWK server.

Improves readiness gating and allows adding depends_on conditions if needed.

     ports:
       - "16161:16161"
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:16161/"]
+      interval: 5s
+      timeout: 3s
+      retries: 5
+      start_period: 2s

53-56: Do you need to publish port 16161 to the host?

If lightspeed-stack resolves JWKS via service DNS (http://test-jwk-server:16161/...), you can avoid host port conflicts by dropping ports and using expose.

-    ports:
-      - "16161:16161"
+    expose:
+      - "16161"

If lightspeed needs localhost access, keep the published port.


52-52: container_name may collide in parallel CI runs.

Consider removing container_name and rely on Compose’s project scoping to avoid name clashes.


49-52: Optional: use a lighter image for the static JWKS server.

Reusing the main Containerfile is convenient but heavy. A tiny python:alpine stage (or busybox httpd) would speed build/pull for tests.


58-58: Heads-up: JSON Content-Type.

python http.server may serve .json with a generic type on some environments. If any client enforces application/json, swap to a tiny handler that sets the header. Only act if tests complain.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c57a847 and 64b8990.

📒 Files selected for processing (12)
  • .gitignore (1 hunks)
  • docker-compose.yaml (1 hunks)
  • docs/testing.md (1 hunks)
  • tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml (1 hunks)
  • tests/e2e/configuration/test_jwk/.gitignore (1 hunks)
  • tests/e2e/features/authorization_jwk.feature (1 hunks)
  • tests/e2e/features/environment.py (5 hunks)
  • tests/e2e/features/steps/health.py (3 hunks)
  • tests/e2e/features/steps/jwk_auth.py (1 hunks)
  • tests/e2e/test_list.txt (1 hunks)
  • tests/e2e/utils/utils.py (2 hunks)
  • tests/unit/authentication/test_jwk_token.py (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tests/e2e/test_list.txt
🚧 Files skipped from review as they are similar to previous changes (6)
  • .gitignore
  • tests/e2e/configuration/test_jwk/.gitignore
  • tests/e2e/utils/utils.py
  • tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml
  • tests/e2e/features/authorization_jwk.feature
  • docs/testing.md
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: All modules start with descriptive module-level docstrings explaining purpose
Use logger = logging.getLogger(name) for module logging after import logging
Define type aliases at module level for clarity
All functions require docstrings with brief descriptions
Provide complete type annotations for all function parameters and return types
Use typing_extensions.Self in model validators where appropriate
Use modern union syntax (str | int) and Optional[T] or T | None consistently
Function names use snake_case with descriptive, action-oriented prefixes (get_, validate_, check_)
Avoid in-place parameter modification; return new data structures instead of mutating arguments
Use appropriate logging levels: debug, info, warning, error with clear messages
All classes require descriptive docstrings explaining purpose
Class names use PascalCase with conventional suffixes (Configuration, Error/Exception, Resolver, Interface)
Abstract base classes should use abc.ABC and @AbstractMethod for interfaces
Provide complete type annotations for all class attributes
Follow Google Python docstring style for modules, classes, and functions, including Args, Returns, Raises, Attributes sections as needed

Files:

  • tests/e2e/features/environment.py
  • tests/e2e/features/steps/jwk_auth.py
  • tests/unit/authentication/test_jwk_token.py
  • tests/e2e/features/steps/health.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use pytest-mock to create AsyncMock objects for async interactions in tests
Use the shared auth mock constant: MOCK_AUTH = ("mock_user_id", "mock_username", False, "mock_token") in tests

Files:

  • tests/e2e/features/environment.py
  • tests/e2e/features/steps/jwk_auth.py
  • tests/unit/authentication/test_jwk_token.py
  • tests/e2e/features/steps/health.py
tests/e2e/features/steps/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Place behave step definitions under tests/e2e/features/steps/

Files:

  • tests/e2e/features/steps/jwk_auth.py
  • tests/e2e/features/steps/health.py
tests/{unit,integration}/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/{unit,integration}/**/*.py: Use pytest for all unit and integration tests
Do not use unittest in tests; pytest is the standard

Files:

  • tests/unit/authentication/test_jwk_token.py
🧬 Code graph analysis (2)
tests/e2e/features/environment.py (2)
tests/unit/authentication/test_jwk_token.py (2)
  • create_jwks_keys (94-105)
  • make_key (47-54)
tests/e2e/utils/utils.py (3)
  • create_config_backup (108-117)
  • switch_config (97-105)
  • restart_container (129-143)
tests/e2e/features/steps/jwk_auth.py (1)
tests/unit/authentication/test_jwk_token.py (2)
  • create_token_header (20-22)
  • create_token_payload (31-38)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: e2e_tests (ci)
  • GitHub Check: build-pr
🔇 Additional comments (3)
tests/e2e/features/steps/health.py (1)

3-3: LGTM! Container command parameterization is well-implemented.

The changes correctly introduce the CONTAINER_CMD environment variable to support both Docker and Podman, maintaining backward compatibility with a sensible default of "docker". The implementation is consistent across both the inspect and stop operations.

Also applies to: 18-24, 33-36

tests/e2e/features/environment.py (1)

10-10: LGTM! Consistent use of CONTAINER_CMD and proper test imports.

The changes correctly introduce the CONTAINER_CMD environment variable for container operations and import the necessary JWK test utilities. This maintains consistency with the broader parameterization effort across the e2e test suite.

Also applies to: 14-14, 30-30, 62-62, 74-74

tests/e2e/features/steps/jwk_auth.py (1)

21-41: Add complete type annotations.

The function lacks type annotations for its parameters and return type, violating the coding guidelines.

As per coding guidelines, apply this diff:

 @given("I have a valid JWT token with the {role} role")
-def create_role_token(context: Context, role: str) -> None:
+def create_role_token(context: Context, role: str) -> None:
     """Create token with role using the shared test key."""

Wait, I see the function already has type annotations (context: Context, role: str) -> None). Let me re-check... Yes, it does have them. This comment would be incorrect. Let me skip this.

Actually, looking more carefully, the function signature at line 22 already has proper type annotations: def create_role_token(context: Context, role: str) -> None:. So this is already compliant with coding guidelines.

Let me check if there are other issues with this function.

  • The docstring is brief but adequate
  • The logic is sound
  • Context mutation is expected in behave steps

No issues to flag here beyond the sys.path.append issue already covered.

Likely an incorrect or invalid review comment.


from authlib.jose import JsonWebToken

sys.path.append(str(Path(__file__).resolve().parents[4]))
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Avoid sys.path.append for imports.

Manipulating sys.path at runtime is fragile and pollutes the global import state. Instead, structure your imports using relative imports or ensure the package is properly installed.

Apply this diff to use a relative import:

-sys.path.append(str(Path(__file__).resolve().parents[4]))
-
-# Import at runtime to avoid module load issues
 from tests.unit.authentication.test_jwk_token import (
     create_token_header,
     create_token_payload,
 )

If this approach causes import errors, verify that the test runner is invoked from the repository root or that the package structure includes proper __init__.py files.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sys.path.append(str(Path(__file__).resolve().parents[4]))
from tests.unit.authentication.test_jwk_token import (
create_token_header,
create_token_payload,
)
🤖 Prompt for AI Agents
In tests/e2e/features/steps/jwk_auth.py around line 12, remove the runtime
sys.path.append modification and replace it with proper package-relative imports
(or absolute imports assuming the package is installed); update the import
statements in this file to use relative form (e.g., from ...module import X) or
full package paths, ensure any needed __init__.py files exist in the package
directories, and confirm the test runner is executed from the repository root
(or install the package in editable mode) so imports resolve without modifying
sys.path.

This commit adds end-to-end tests for the authorization functionality.

# Implementation details

- Modified `.gitignore` to ignore leftover config backup files
  (unrelated to this change but useful)
- Updated testing documentation to include instructions for running e2e
  tests
- Added a JWK server container to `docker-compose.yaml` which is needed
  for e2e testing JWK auth
- Added a `tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml`
  config file for lightspeed-stack with JWK auth enabled to be used in
  the JWK e2e tests
- Removed hard dependency on the `docker` command in e2e tests and
  instead use the `CONTAINER_CMD` environment variable if set (to allow
  using `podman` instead of `docker`)
- Added `tests/e2e/features/authorization_jwk.feature` which contains
  the actual e2e tests for JWK authz
- Added `tests/e2e/features/steps/jwk_auth.py` which implements the
  steps for the JWK authz tests
- Modified `tests/e2e/features/environment.py` to handle the new JWK
  authz tests, including creating a temporary JWK key pair for the
  tests and writing the public key to a file served by the JWK server
  container (which lightspeed-stack is directed to access through the
  config file mentioned above)
  functionality to functions that can be reused in the e2e tests
- Added `tests/e2e/configuration/test_jwk/.gitignore` to ignore
  generated JWK files
- Updated `tests/e2e/test_list.txt` to include the new JWK authz tests
Copy link
Contributor

@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: 0

♻️ Duplicate comments (1)
tests/unit/authentication/test_jwk_token.py (1)

23-25: Add missing parameter type annotation.

The create_token_header function lacks a type annotation for the key_id parameter. This was flagged in a previous review but remains unaddressed.

Based on coding guidelines, apply this diff:

-def create_token_header(key_id) -> dict[str, str]:
+def create_token_header(key_id: str) -> dict[str, str]:
     """Create a sample token header."""
     return {"alg": "RS256", "typ": "JWT", "kid": key_id}

Based on coding guidelines.

🧹 Nitpick comments (1)
tests/e2e/features/steps/health.py (1)

18-36: Consider extracting the container command to reduce duplication.

The os.getenv("CONTAINER_CMD", "docker") call is duplicated across lines 19 and 33. While this is acceptable for test code, you could extract it to a module-level constant or helper function for better maintainability.

For example:

CONTAINER_CMD = os.getenv("CONTAINER_CMD", "docker")

Then use CONTAINER_CMD directly in the subprocess calls.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64b8990 and cdec44c.

📒 Files selected for processing (12)
  • .gitignore (1 hunks)
  • docker-compose.yaml (1 hunks)
  • docs/testing.md (1 hunks)
  • tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml (1 hunks)
  • tests/e2e/configuration/test_jwk/.gitignore (1 hunks)
  • tests/e2e/features/authorization_jwk.feature (1 hunks)
  • tests/e2e/features/environment.py (5 hunks)
  • tests/e2e/features/steps/health.py (3 hunks)
  • tests/e2e/features/steps/jwk_auth.py (1 hunks)
  • tests/e2e/test_list.txt (1 hunks)
  • tests/e2e/utils/utils.py (2 hunks)
  • tests/unit/authentication/test_jwk_token.py (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • tests/e2e/configuration/test_jwk/.gitignore
  • .gitignore
  • docker-compose.yaml
  • tests/e2e/test_list.txt
  • tests/e2e/utils/utils.py
  • docs/testing.md
  • tests/e2e/features/steps/jwk_auth.py
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: All modules start with descriptive module-level docstrings explaining purpose
Use logger = logging.getLogger(name) for module logging after import logging
Define type aliases at module level for clarity
All functions require docstrings with brief descriptions
Provide complete type annotations for all function parameters and return types
Use typing_extensions.Self in model validators where appropriate
Use modern union syntax (str | int) and Optional[T] or T | None consistently
Function names use snake_case with descriptive, action-oriented prefixes (get_, validate_, check_)
Avoid in-place parameter modification; return new data structures instead of mutating arguments
Use appropriate logging levels: debug, info, warning, error with clear messages
All classes require descriptive docstrings explaining purpose
Class names use PascalCase with conventional suffixes (Configuration, Error/Exception, Resolver, Interface)
Abstract base classes should use abc.ABC and @AbstractMethod for interfaces
Provide complete type annotations for all class attributes
Follow Google Python docstring style for modules, classes, and functions, including Args, Returns, Raises, Attributes sections as needed

Files:

  • tests/e2e/features/environment.py
  • tests/e2e/features/steps/health.py
  • tests/unit/authentication/test_jwk_token.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use pytest-mock to create AsyncMock objects for async interactions in tests
Use the shared auth mock constant: MOCK_AUTH = ("mock_user_id", "mock_username", False, "mock_token") in tests

Files:

  • tests/e2e/features/environment.py
  • tests/e2e/features/steps/health.py
  • tests/unit/authentication/test_jwk_token.py
tests/e2e/features/steps/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Place behave step definitions under tests/e2e/features/steps/

Files:

  • tests/e2e/features/steps/health.py
tests/e2e/features/**/*.feature

📄 CodeRabbit inference engine (CLAUDE.md)

Write E2E tests as Gherkin feature files for behave

Files:

  • tests/e2e/features/authorization_jwk.feature
tests/{unit,integration}/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/{unit,integration}/**/*.py: Use pytest for all unit and integration tests
Do not use unittest in tests; pytest is the standard

Files:

  • tests/unit/authentication/test_jwk_token.py
🧬 Code graph analysis (2)
tests/e2e/features/environment.py (2)
tests/unit/authentication/test_jwk_token.py (2)
  • create_jwks_keys (89-102)
  • make_key (50-57)
tests/e2e/utils/utils.py (3)
  • create_config_backup (108-117)
  • switch_config (97-105)
  • restart_container (129-143)
tests/unit/authentication/test_jwk_token.py (1)
src/models/config.py (1)
  • JwkConfiguration (396-400)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-pr
  • GitHub Check: e2e_tests (ci)
🔇 Additional comments (12)
tests/e2e/features/authorization_jwk.feature (1)

1-39: LGTM! Well-structured authorization test scenarios.

The feature file provides comprehensive coverage of JWK-based authorization across all three roles (admin, config, readonly) with appropriate success and failure cases. The scenarios clearly test the access control rules defined in the configuration.

tests/e2e/features/steps/health.py (1)

18-24: Good parameterization for container command flexibility.

The change to use CONTAINER_CMD environment variable enables podman support. The implementation correctly defaults to "docker" when the variable is not set.

tests/e2e/configuration/lightspeed-stack-auth-jwk.yaml (1)

1-52: LGTM! Configuration correctly implements role-based access control.

The configuration properly maps JWT roles to internal roles and defines appropriate authorization rules that align with the test scenarios:

  • administrator role → ["admin"] actions
  • config role → ["get_config", "info"] actions
  • readonly role → ["info"] actions

The JWK configuration points to the test JWK server on port 16161, which integrates correctly with the e2e test infrastructure.

tests/e2e/features/environment.py (4)

10-10: LGTM! Appropriate imports added for JWK support.

The new imports enable JWK key generation and file operations required for the JWKAuth test flow.

Also applies to: 14-14, 30-30


62-62: LGTM! Container command parameterization implemented.

Consistent use of os.getenv("CONTAINER_CMD", "docker") throughout the file enables podman support while maintaining backward compatibility.

Also applies to: 74-74


134-137: LGTM! Cleanup properly handles both auth types.

The after_feature hook correctly restores the original configuration and removes the backup for both Authorized and JWKAuth features.


115-126: No directory creation needed The directory tests/e2e/configuration/test_jwk already exists, so writing jwk.json will succeed.

tests/unit/authentication/test_jwk_token.py (5)

6-6: LGTM! Type support enhanced for test helpers.

The addition of Any from typing and the GeneratedKey type alias improves type clarity for the test helper functions.

Also applies to: 20-20


34-41: LGTM! Properly typed payload generator.

The create_token_payload function has complete type annotations and creates a standard JWT payload with appropriate claims.


50-57: LGTM! Key generation with clear return type.

The make_key function properly returns a GeneratedKey type, improving type clarity for downstream consumers.


89-102: LGTM! JWKS helper function with proper typing.

The create_jwks_keys function has appropriate type annotations and correctly transforms the key set into JWKS format for the mock server.


139-147: LGTM! Type annotations added throughout test helpers.

All helper functions now have proper type annotations for parameters and return values, improving type safety and code clarity.

Also applies to: 150-158, 162-170, 174-182, 185-191

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.

1 participant