Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions tests/e2e/configuration/lightspeed-stack-auth-noop-token.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Lightspeed Core Service (LCS)
service:
host: 0.0.0.0
port: 8080
auth_enabled: false
workers: 1
color_log: true
access_log: true
llama_stack:
# Uses a remote llama-stack service
# The instance would have already been started with a llama-stack-run.yaml file
use_as_library_client: false
# Alternative for "as library use"
# use_as_library_client: true
# library_client_config_path: <path-to-llama-stack-run.yaml-file>
url: http://llama-stack:8321
api_key: xyzzy
user_data_collection:
feedback_enabled: true
feedback_storage: "/tmp/data/feedback"
transcripts_enabled: true
transcripts_storage: "/tmp/data/transcripts"

authentication:
module: "noop-with-token"
34 changes: 0 additions & 34 deletions tests/e2e/features/authorized.feature

This file was deleted.

58 changes: 58 additions & 0 deletions tests/e2e/features/authorized_noop.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
Feature: Authorized endpoint API tests for the noop authentication module

Background:
Given The service is started locally
And REST API service hostname is localhost
And REST API service port is 8080
And REST API service prefix is /v1

Scenario: Check if the authorized endpoint works fine when user_id and auth header are not provided
Given The system is in default state
When I access endpoint "authorized" using HTTP POST method
"""
{"placeholder":"abc"}
"""
Then The status code of the response is 200
And The body of the response is the following
"""
{"user_id": "00000000-0000-0000-0000-000","username": "lightspeed-user"}
"""

Scenario: Check if the authorized endpoint works when auth token is not provided
Given The system is in default state
When I access endpoint "authorized" using HTTP POST method with user_id "test_user"
Then The status code of the response is 200
And The body of the response is the following
"""
{"user_id": "test_user","username": "lightspeed-user"}
"""

Scenario: Check if the authorized endpoint works when user_id is not provided
Given The system is in default state
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
When I access endpoint "authorized" using HTTP POST method without user_id
Then The status code of the response is 200
And The body of the response is the following
"""
{"user_id": "00000000-0000-0000-0000-000","username": "lightspeed-user"}
"""

Scenario: Check if the authorized endpoint works when providing empty user_id
Given The system is in default state
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
When I access endpoint "authorized" using HTTP POST method with user_id ""
Then The status code of the response is 200
And The body of the response is the following
"""
{"user_id": "","username": "lightspeed-user"}
"""

Scenario: Check if the authorized endpoint works when providing proper user_id
Given The system is in default state
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
When I access endpoint "authorized" using HTTP POST method with user_id "test_user"
Then The status code of the response is 200
And The body of the response is the following
"""
{"user_id": "test_user","username": "lightspeed-user"}
"""
69 changes: 69 additions & 0 deletions tests/e2e/features/authorized_noop_token.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
@Authorized
Feature: Authorized endpoint API tests for the noop-with-token

Background:
Given The service is started locally
And REST API service hostname is localhost
And REST API service port is 8080
And REST API service prefix is /v1

Scenario: Check if the authorized endpoint fails when user_id and auth header are not provided
Given The system is in default state
When I access endpoint "authorized" using HTTP POST method
"""
{"placeholder":"abc"}
"""
Then The status code of the response is 400
And The body of the response is the following
"""
{"detail": "No Authorization header found"}
"""

Scenario: Check if the authorized endpoint works when user_id is not provided
Given The system is in default state
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
When I access endpoint "authorized" using HTTP POST method without user_id
Then The status code of the response is 200
And The body of the response is the following
"""
{"user_id": "00000000-0000-0000-0000-000","username": "lightspeed-user"}
"""

Scenario: Check if the authorized endpoint works when providing empty user_id
Given The system is in default state
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
When I access endpoint "authorized" using HTTP POST method with user_id ""
Then The status code of the response is 200
And The body of the response is the following
"""
{"user_id": "","username": "lightspeed-user"}
"""

Scenario: Check if the authorized endpoint works when providing proper user_id
Given The system is in default state
And I set the Authorization header to Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
When I access endpoint "authorized" using HTTP POST method with user_id "test_user"
Then The status code of the response is 200
And The body of the response is the following
"""
{"user_id": "test_user","username": "lightspeed-user"}
"""

Scenario: Check if the authorized endpoint works with proper user_id but bearer token is not present
Given The system is in default state
When I access endpoint "authorized" using HTTP POST method with user_id "test_user"
Then The status code of the response is 400
And The body of the response is the following
"""
{"detail": "No Authorization header found"}
"""

Scenario: Check if the authorized endpoint works when auth token is malformed
Given The system is in default state
And I set the Authorization header to BearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpva
When I access endpoint "authorized" using HTTP POST method with user_id "test_user"
Then The status code of the response is 400
And The body of the response is the following
"""
{"detail": "No token found in Authorization header"}
"""
23 changes: 21 additions & 2 deletions tests/e2e/features/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@

import subprocess
import time
from behave.model import Scenario
from behave.model import Scenario, Feature
from behave.runner import Context

from tests.e2e.utils.utils import switch_config_and_restart

try:
import os # noqa: F401
except ImportError as e:
Expand Down Expand Up @@ -82,5 +84,22 @@ def after_scenario(context: Context, scenario: Scenario) -> None:
print(f"Warning: Could not restore Llama Stack connection: {e}")


def before_feature(context: Context, feature: Scenario) -> None:
def before_feature(context: Context, feature: Feature) -> None:
"""Run before each feature file is exercised."""
if "Authorized" in feature.tags:
context.backup_file = switch_config_and_restart(
"lightspeed-stack.yaml",
"tests/e2e/configuration/lightspeed-stack-auth-noop-token.yaml",
"lightspeed-stack",
)


def after_feature(context: Context, feature: Feature) -> None:
"""Run after each feature file is exercised."""
if "Authorized" in feature.tags:
switch_config_and_restart(
"lightspeed-stack.yaml",
context.backup_file,
"lightspeed-stack",
cleanup=True,
)
67 changes: 51 additions & 16 deletions tests/e2e/features/steps/auth.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,60 @@
"""Implementation of common test steps."""

from behave import given, then # pyright: ignore[reportAttributeAccessIssue]
import requests
from behave import given, when # pyright: ignore[reportAttributeAccessIssue]
from behave.runner import Context
from tests.e2e.utils.utils import normalize_endpoint


@then("The body of the response has proper username")
def check_body_username(context: Context) -> None:
"""Check that the username is correct in response."""
# TODO: add step implementation
assert context is not None
@given("I set the Authorization header to {header_value}")
def set_authorization_header_custom(context: Context, header_value: str) -> None:
"""Set a custom Authorization header value."""
if not hasattr(context, "auth_headers"):
context.auth_headers = {}
context.auth_headers["Authorization"] = header_value
print(f"🔑 Set Authorization header to: {header_value}")
Comment on lines +9 to +15
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

Don’t log secrets; optionally strip quotes from header value.

Avoid printing Authorization values to CI logs; also consider stripping wrapping quotes.

Apply:

-    context.auth_headers["Authorization"] = header_value
-    print(f"🔑 Set Authorization header to: {header_value}")
+    header_value = header_value.strip('"')
+    context.auth_headers["Authorization"] = header_value
+    print("🔑 Authorization header set.")
📝 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
@given("I set the Authorization header to {header_value}")
def set_authorization_header_custom(context: Context, header_value: str) -> None:
"""Set a custom Authorization header value."""
if not hasattr(context, "auth_headers"):
context.auth_headers = {}
context.auth_headers["Authorization"] = header_value
print(f"🔑 Set Authorization header to: {header_value}")
@given("I set the Authorization header to {header_value}")
def set_authorization_header_custom(context: Context, header_value: str) -> None:
"""Set a custom Authorization header value."""
if not hasattr(context, "auth_headers"):
context.auth_headers = {}
header_value = header_value.strip('"')
context.auth_headers["Authorization"] = header_value
print("🔑 Authorization header set.")
🤖 Prompt for AI Agents
In tests/e2e/features/steps/auth.py around lines 9 to 15, remove the print that
logs the Authorization header (do not output secrets to CI logs) and instead log
a non-sensitive confirmation message or nothing; additionally, sanitize the
incoming header_value by stripping surrounding single or double quotes before
storing it in context.auth_headers["Authorization"] so quoted inputs become
unquoted while still avoiding printing the secret.



@given("I remove the auth header")
def remove_auth_header(context: Context) -> None:
"""Remove the auth header."""
# TODO: add step implementation
assert context is not None
@when("I access endpoint {endpoint} using HTTP POST method with user_id {user_id}")
def access_rest_api_endpoint_post(
context: Context, endpoint: str, user_id: str
) -> None:
"""Send POST HTTP request with payload in the endpoint as parameter to tested service.

The response is stored in `context.response` attribute.
"""
endpoint = normalize_endpoint(endpoint)
user_id = user_id.replace('"', "")
base = f"http://{context.hostname}:{context.port}"
path = f"{endpoint}?user_id={user_id}".replace("//", "/")
url = base + path

@given("I modify the auth header so that the user is it authorized")
def modify_auth_header(context: Context) -> None:
"""Modify the auth header making the user unauthorized."""
# TODO: add step implementation
assert context is not None
if not hasattr(context, "auth_headers"):
context.auth_headers = {}

# perform REST API call
context.response = requests.post(
url, json="", headers=context.auth_headers, timeout=10
)


@when("I access endpoint {endpoint} using HTTP POST method without user_id")
def access_rest_api_endpoint_post_without_param(
context: Context, endpoint: str
) -> None:
"""Send POST HTTP request without user_id payload.

The response is stored in `context.response` attribute.
"""
endpoint = normalize_endpoint(endpoint)
base = f"http://{context.hostname}:{context.port}"
path = f"{endpoint}".replace("//", "/")
url = base + path

if not hasattr(context, "auth_headers"):
context.auth_headers = {}

# perform REST API call
context.response = requests.post(
url, json="", headers=context.auth_headers, timeout=10
)
5 changes: 3 additions & 2 deletions tests/e2e/features/steps/common_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,17 @@ def access_rest_api_endpoint_get(context: Context, endpoint: str) -> None:
context.response = requests.get(url, timeout=DEFAULT_TIMEOUT)


@when("I access endpoint {endpoint:w} using HTTP POST method")
@when("I access endpoint {endpoint} using HTTP POST method")
def access_rest_api_endpoint_post(context: Context, endpoint: str) -> None:
"""Send POST HTTP request with JSON payload to tested service.

The JSON payload is retrieved from `context.text` attribute,
which must not be None. The response is stored in
`context.response` attribute.
"""
endpoint = normalize_endpoint(endpoint)
base = f"http://{context.hostname}:{context.port}"
path = f"{context.api_prefix}/{endpoint}".replace("//", "/")
path = f"{endpoint}".replace("//", "/")
url = base + path

assert context.text is not None, "Payload needs to be specified"
Expand Down
3 changes: 2 additions & 1 deletion tests/e2e/test_list.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
features/smoketests.feature
features/authorized.feature
features/authorized_noop.feature
features/authorized_noop_token.feature
features/conversations.feature
features/feedback.feature
features/health.feature
Expand Down
Loading