Skip to content

LCORE-1826: Expose OpenTelemetry configuration in v1/config endpoint - #2283

Open
anik120 wants to merge 1 commit into
lightspeed-core:mainfrom
anik120:env-vars-otel
Open

LCORE-1826: Expose OpenTelemetry configuration in v1/config endpoint#2283
anik120 wants to merge 1 commit into
lightspeed-core:mainfrom
anik120:env-vars-otel

Conversation

@anik120

@anik120 anik120 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Description

Add observability configuration to the v1/config endpoint, exposing all OTEL_* environment variables to provide visibility into the active OpenTelemetry tracing setup.

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
  • Benchmarks improvement

Tools used to create PR

Identify any AI code assistants used in this PR (for transparency and review context)

  • Assisted-by: (e.g., Claude, CodeRabbit, Ollama, etc., N/A if not used)
  • Generated by: (e.g., tool name and version; N/A if not used)

Related Tickets & Documents

  • Related Issue #
  • Closes #

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

  • New Features

    • Added an observability section to the configuration response.
    • Automatically surfaces OpenTelemetry settings from OTEL_* environment variables.
    • Sensitive OpenTelemetry values are redacted before being exposed.
    • Updated published API documentation with the new observability configuration schema.
  • Tests

    • Added integration tests for /config response structure and OTEL_* collection.
    • Added unit tests for defaults, parsing behavior, input validation, and redaction.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The configuration model derives observability.otel from OTEL_* environment variables, redacts sensitive values, exposes the data through the configuration response, documents it in OpenAPI, and adds unit and integration coverage.

Changes

Observability configuration

Layer / File(s) Summary
Environment-derived observability model
src/models/config.py
Adds ObservabilityConfiguration, OTEL environment collection, secret redaction, and automatic wiring into Configuration.
Configuration response and schema contract
src/models/api/responses/successful/configuration.py, docs/devel_doc/openapi.json
Adds observability examples and OpenAPI definitions for inline and shared observability.otel schemas.
Observability behavior validation
tests/unit/models/config/test_observability_configuration.py, tests/unit/models/config/test_dump_configuration.py, tests/integration/endpoints/test_config_integration.py
Tests defaults, environment filtering, empty values, rejected extras, redaction, serialized configuration, and endpoint exposure.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Environment
  participant ObservabilityConfiguration
  participant Configuration
  participant config_endpoint_handler
  Environment->>ObservabilityConfiguration: Read OTEL_* variables
  ObservabilityConfiguration->>ObservabilityConfiguration: Redact sensitive values
  ObservabilityConfiguration->>Configuration: Populate observability
  Configuration->>config_endpoint_handler: Provide configuration
  config_endpoint_handler-->>Configuration: Return observability.otel
Loading

Possibly related PRs

Suggested reviewers: tisnik

🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: exposing OpenTelemetry configuration in the v1/config endpoint.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
Performance And Algorithmic Complexity ✅ Passed PASS: New observability config does one linear OTEL env scan and one-pass redaction at config load; no N+1s, unbounded growth, or request-loop work.
Security And Secret Handling ✅ Passed PASS: /config is protected by auth decorator + auth dependency, and ObservabilityConfiguration redacts OTEL headers/certs/keys before serialization; no plaintext leaks found.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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.

Comment thread src/models/config.py Outdated
for key, value in os.environ.items():
if key.startswith("OTEL_"):
# Exclude sensitive variables that might contain tokens or keys
# Currently no secret OTEL_ vars are used, but this is future-proof

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.

This is actually not true. Anyone can export optional env variables and those will be leaked now.
Please research which OTEL variables can contain sensitive values and wrap those into SecretStr for example. The list of all configurable OTEL variables is attached in design doc

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

🤖 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 `@docs/devel_doc/openapi.json`:
- Around line 15133-15148: Update ObservabilityConfiguration.from_environment()
to include OTEL_EXPORTER_OTLP_TRACES_HEADERS,
OTEL_EXPORTER_OTLP_METRICS_HEADERS, and OTEL_EXPORTER_OTLP_LOGS_HEADERS in the
existing redaction set, ensuring these per-signal header values are masked in
the public /v1/config response alongside OTEL_EXPORTER_OTLP_HEADERS.

In `@src/models/config.py`:
- Around line 39-45: Replace the exact-name _SECRET_OTEL_VARS approach with a
complete Pydantic validator on ObservabilityConfiguration. Have the validator
redact generic and signal-specific OTEL headers, certificates, and client key
variants, return a new mapping without mutating caller data, and ensure both
collector output and direct ObservabilityConfiguration(otel=...) construction
are covered by the validation path.

In `@tests/integration/endpoints/test_config_integration.py`:
- Around line 124-167: The test_config_endpoint_observability_collects_otel_vars
test currently bypasses the endpoint and only validates
ObservabilityConfiguration.from_environment(). After setting the OTEL variables,
recreate or reload the root configuration, invoke config_endpoint_handler, and
assert the expected OTEL values through
response.configuration.observability.otel, ensuring endpoint model-to-response
wiring is exercised.

In `@tests/unit/models/config/test_dump_configuration.py`:
- Around line 47-49: Update the tests using _DEFAULT_OBSERVABILITY_DUMP to
isolate them from ambient OTEL_* environment variables: clear those variables in
a fixture before constructing Configuration, or derive the expected dump from
the controlled environment. Ensure expectations remain stable on instrumented CI
runners while preserving the existing default behavior.

In `@tests/unit/models/config/test_observability_configuration.py`:
- Around line 16-17: Update the affected test functions, including
test_from_environment_no_otel_vars and the additionally referenced tests, to
document every fixture and parametrized input in their docstrings. Add a
Parameters: section describing each applicable monkeypatch, otel_dict, and
expected_count parameter, while preserving the existing test descriptions and
behavior.
- Around line 170-198: Update _SECRET_OTEL_VARS and
test_from_environment_redacts_all_secret_vars so signal-specific OTLP header
variables—OTEL_EXPORTER_OTLP_TRACES_HEADERS, OTEL_EXPORTER_OTLP_METRICS_HEADERS,
and OTEL_EXPORTER_OTLP_LOGS_HEADERS—are redacted alongside
OTEL_EXPORTER_OTLP_HEADERS, while non-secret variables remain unchanged.
🪄 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 Plus

Run ID: 9f50b0c6-44a2-4be5-9c0b-18bf134d51eb

📥 Commits

Reviewing files that changed from the base of the PR and between 2a9c8a7 and 4245a22.

📒 Files selected for processing (6)
  • docs/devel_doc/openapi.json
  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
  • tests/integration/endpoints/test_config_integration.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/models/config/test_observability_configuration.py
📜 Review details
⏰ Context from checks skipped due to timeout. (14)
  • GitHub Check: build-pr
  • GitHub Check: integration_tests (3.13)
  • GitHub Check: integration_tests (3.12)
  • GitHub Check: Pylinter
  • GitHub Check: unit_tests (3.12)
  • GitHub Check: unit_tests (3.13)
  • GitHub Check: E2E Tests for Lightspeed Evaluation job
  • GitHub Check: E2E: library mode / ci / group 2
  • GitHub Check: E2E: library mode / ci / group 1
  • GitHub Check: E2E: library mode / ci / group 3
  • GitHub Check: E2E: server mode / ci / group 1
  • GitHub Check: E2E: server mode / ci / group 3
  • GitHub Check: E2E: server mode / ci / group 2
  • GitHub Check: Konflux kflux-prd-rh02 / lightspeed-stack-0-7-on-pull-request
🧰 Additional context used
📓 Path-based instructions (5)
**/*

📄 CodeRabbit inference engine (Custom checks)

**/*: Flag meaningful O(n^2)+ algorithms on non-trivial inputs, including handlers and Kubernetes list operations.
Flag N+1 patterns that list items and then query once per item, including Kubernetes API and database access.
Flag expensive work inside loops, including API calls, JSON parsing, and regex compilation.
Flag unbounded growth in caches, watchers, or buffers when eviction or limits are missing.
Flag missing pagination or limits on list operations and API endpoints.
Flag secrets or tokens logged in plaintext or hardcoded in source.
Flag API endpoints missing authentication or authorization.
Flag injection vulnerabilities, including SQL injection, command injection, and path traversal.
Flag sensitive data leaked in API responses, WebSocket messages, or logs.
Flag Kubernetes Secrets and Red Hat secrets missing OwnerReferences.

Files:

  • src/models/api/responses/successful/configuration.py
  • docs/devel_doc/openapi.json
  • tests/integration/endpoints/test_config_integration.py
  • src/models/config.py
  • tests/unit/models/config/test_observability_configuration.py
  • tests/unit/models/config/test_dump_configuration.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use absolute imports for internal Python modules.
All modules must begin with descriptive docstrings explaining their purpose.
Use logger = get_logger(__name__) from log.py for module logging.
Use complete type annotations for function parameters and return types.
Use modern union syntax such as str | int; use Optional[Type] for optional values.
Use typing_extensions.Self for model validators.
Functions must use descriptive, action-oriented snake_case names such as get_, validate_, and check_.
Avoid modifying mutable parameters in place; return a new data structure instead.
Use async def for I/O operations and external API calls.
Handle APIConnectionError from Llama Stack.
All classes must have descriptive docstrings and complete type annotations for class attributes; use specific types instead of Any.
Use PascalCase for classes and descriptive standard suffixes such as Configuration, Error/Exception, Resolver, and Interface.
Use ABC and @abstractmethod for abstract interfaces.
Follow Google Python docstring conventions; document all modules, classes, and functions, including Parameters, Returns, Raises, and Attributes sections as applicable.
Never commit secrets or keys; use environment variables for sensitive data.

Files:

  • src/models/api/responses/successful/configuration.py
  • tests/integration/endpoints/test_config_integration.py
  • src/models/config.py
  • tests/unit/models/config/test_observability_configuration.py
  • tests/unit/models/config/test_dump_configuration.py
src/models/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/models/**/*.py: Extend ConfigurationBase for configuration models and BaseModel for data models.
Use @model_validator and @field_validator for Pydantic model validation.

Files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
tests/integration/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use pytest for all integration tests; do not use unittest.

Files:

  • tests/integration/endpoints/test_config_integration.py
tests/unit/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

tests/unit/**/*.py: Use pytest for all unit tests; do not use unittest.
Use conftest.py for shared fixtures, pytest-mock for AsyncMock objects, and pytest.mark.asyncio for asynchronous tests.

Files:

  • tests/unit/models/config/test_observability_configuration.py
  • tests/unit/models/config/test_dump_configuration.py
🧠 Learnings (5)
📚 Learning: 2026-01-12T10:58:40.230Z
Learnt from: blublinsky
Repo: lightspeed-core/lightspeed-stack PR: 972
File: src/models/config.py:459-513
Timestamp: 2026-01-12T10:58:40.230Z
Learning: In lightspeed-core/lightspeed-stack, for Python files under src/models, when a user claims a fix is done but the issue persists, verify the current code state before accepting the fix. Steps: review the diff, fetch the latest changes, run relevant tests, reproduce the issue, search the codebase for lingering references to the original problem, confirm the fix is applied and not undone by subsequent commits, and validate with local checks to ensure the issue is resolved.

Applied to files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
📚 Learning: 2026-02-25T07:46:33.545Z
Learnt from: asimurka
Repo: lightspeed-core/lightspeed-stack PR: 1211
File: src/models/responses.py:8-16
Timestamp: 2026-02-25T07:46:33.545Z
Learning: In the Python codebase, requests.py should use OpenAIResponseInputTool as Tool while responses.py uses OpenAIResponseTool as Tool. This difference is intentional due to differing schemas for input vs output tools in llama-stack-api. Apply this distinction consistently to other models under src/models (e.g., ensure request-related tools use the InputTool variant and response-related tools use the ResponseTool variant). If adding new tools, choose the corresponding InputTool or Tool class based on whether the tool represents input or output, and document the rationale in code comments.

Applied to files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
📚 Learning: 2026-06-24T13:45:37.249Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 1971
File: src/utils/markdown_repair.py:31-36
Timestamp: 2026-06-24T13:45:37.249Z
Learning: In the lightspeed-stack repository, docstrings must use the section header name "Parameters:" (not "Args:") for function arguments, even if the project references Google Python docstring conventions. Ensure docstrings follow the project’s established "Parameters:" header format for any documented function parameters.

Applied to files:

  • src/models/api/responses/successful/configuration.py
  • tests/integration/endpoints/test_config_integration.py
  • src/models/config.py
  • tests/unit/models/config/test_observability_configuration.py
  • tests/unit/models/config/test_dump_configuration.py
📚 Learning: 2026-07-06T15:26:18.398Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 2071
File: src/models/config.py:2416-2422
Timestamp: 2026-07-06T15:26:18.398Z
Learning: In this repo’s Python code under src/**, don’t treat differences in string concatenation style as a style inconsistency when Black has effectively forced (or made clearer) use of explicit `+` string concatenation in multi-line logger/string expressions. If adjacent-literal implicit concatenation is avoided/changed specifically to accommodate Black’s formatting in these call sites, accept the `+` usage and don’t recommend converting it solely for consistency with nearby blocks that use implicit concatenation.

Applied to files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
📚 Learning: 2026-07-17T19:25:05.325Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 2166
File: src/utils/saved_prompts.py:129-157
Timestamp: 2026-07-17T19:25:05.325Z
Learning: For any endpoint that handles saved prompts and calls `src/utils/saved_prompts.py::create_saved_prompt`, treat the endpoint as the validation boundary. Before calling `create_saved_prompt`, validate the incoming saved-prompt name and content, specifically using `validate_saved_prompt_name` and then persist (store) the normalized value it returns. Do not call `create_saved_prompt` with unvalidated/raw name/content.

Applied to files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
🔇 Additional comments (5)
src/models/config.py (2)

2842-2850: LGTM!


3039-3044: 🎯 Functional Correctness

Verify exact configuration-dump fixtures include the new default.

default_factory=ObservabilityConfiguration.from_environment adds an observability section to every Configuration.model_dump(), even when no OTEL variables exist, and makes dumps depend on the process environment. Existing full-dictionary dump fixtures must either include this field or explicitly isolate/override the environment-derived configuration.

src/models/api/responses/successful/configuration.py (1)

90-98: LGTM!

docs/devel_doc/openapi.json (1)

12379-12383: LGTM!

tests/integration/endpoints/test_config_integration.py (1)

94-121: LGTM!

Comment thread docs/devel_doc/openapi.json
Comment thread src/models/config.py Outdated
Comment thread tests/integration/endpoints/test_config_integration.py Outdated
Comment thread tests/unit/models/config/test_dump_configuration.py Outdated
Comment thread tests/unit/models/config/test_observability_configuration.py Outdated
Comment thread tests/unit/models/config/test_observability_configuration.py
Add observability configuration to the v1/config endpoint, exposing all
OTEL_* environment variables to provide visibility into the active OpenTelemetry
tracing setup.

Signed-off-by: Anik Bhattacharjee <anbhatta@redhat.com>

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

🤖 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 `@src/models/config.py`:
- Around line 2850-2908: Update ObservabilityConfiguration.redact_secrets to use
a reviewed allowlist of explicitly safe OTEL variable names, redacting every
unknown key—including resource attributes and vendor extensions—by default.
Preserve only allowlisted non-sensitive values, and sanitize compound values so
embedded secrets are not returned verbatim; ensure from_environment’s complete
OTEL_* collection cannot bypass this validator.

In `@tests/unit/models/config/test_dump_configuration.py`:
- Around line 57-74: Update the docstrings for clear_otel_env_fixture and
_get_expected_observability_dump. Add a Parameters: section documenting the
monkeypatch parameter in clear_otel_env_fixture, and revise the helper docstring
to state that it returns the fixed expected observability dump with an empty
otel mapping, without implying it reads the environment.
🪄 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 Plus

Run ID: 4545a430-0abb-414f-9fde-78d031e58651

📥 Commits

Reviewing files that changed from the base of the PR and between 4245a22 and 6acd7f4.

📒 Files selected for processing (6)
  • docs/devel_doc/openapi.json
  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
  • tests/integration/endpoints/test_config_integration.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/models/config/test_observability_configuration.py
📜 Review details
⏰ Context from checks skipped due to timeout. (16)
  • GitHub Check: mypy
  • GitHub Check: integration_tests (3.13)
  • GitHub Check: unit_tests (3.12)
  • GitHub Check: integration_tests (3.12)
  • GitHub Check: unit_tests (3.13)
  • GitHub Check: E2E: library mode / ci / group 3
  • GitHub Check: E2E: library mode / ci / group 2
  • GitHub Check: E2E: server mode / ci / group 3
  • GitHub Check: E2E: library mode / ci / group 1
  • GitHub Check: E2E: server mode / ci / group 2
  • GitHub Check: E2E: server mode / ci / group 1
  • GitHub Check: build-pr
  • GitHub Check: Pyright
  • GitHub Check: Pylinter
  • GitHub Check: E2E Tests for Lightspeed Evaluation job
  • GitHub Check: Konflux kflux-prd-rh02 / lightspeed-stack-0-7-on-pull-request
🧰 Additional context used
📓 Path-based instructions (5)
**/*

📄 CodeRabbit inference engine (Custom checks)

**/*: Flag meaningful O(n^2)+ algorithms on non-trivial inputs, including handlers and Kubernetes list operations.
Flag N+1 patterns that list items and then query once per item, including Kubernetes API and database access.
Flag expensive work inside loops, including API calls, JSON parsing, and regex compilation.
Flag unbounded growth in caches, watchers, or buffers when eviction or limits are missing.
Flag missing pagination or limits on list operations and API endpoints.
Flag secrets or tokens logged in plaintext or hardcoded in source.
Flag API endpoints missing authentication or authorization.
Flag injection vulnerabilities, including SQL injection, command injection, and path traversal.
Flag sensitive data leaked in API responses, WebSocket messages, or logs.
Flag Kubernetes Secrets and Red Hat secrets missing OwnerReferences.

Files:

  • src/models/api/responses/successful/configuration.py
  • docs/devel_doc/openapi.json
  • src/models/config.py
  • tests/integration/endpoints/test_config_integration.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/models/config/test_observability_configuration.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use absolute imports for internal Python modules.
All modules must begin with descriptive docstrings explaining their purpose.
Use logger = get_logger(__name__) from log.py for module logging.
Use complete type annotations for function parameters and return types.
Use modern union syntax such as str | int; use Optional[Type] for optional values.
Use typing_extensions.Self for model validators.
Functions must use descriptive, action-oriented snake_case names such as get_, validate_, and check_.
Avoid modifying mutable parameters in place; return a new data structure instead.
Use async def for I/O operations and external API calls.
Handle APIConnectionError from Llama Stack.
All classes must have descriptive docstrings and complete type annotations for class attributes; use specific types instead of Any.
Use PascalCase for classes and descriptive standard suffixes such as Configuration, Error/Exception, Resolver, and Interface.
Use ABC and @abstractmethod for abstract interfaces.
Follow Google Python docstring conventions; document all modules, classes, and functions, including Parameters, Returns, Raises, and Attributes sections as applicable.
Never commit secrets or keys; use environment variables for sensitive data.

Files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
  • tests/integration/endpoints/test_config_integration.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/models/config/test_observability_configuration.py
src/models/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/models/**/*.py: Extend ConfigurationBase for configuration models and BaseModel for data models.
Use @model_validator and @field_validator for Pydantic model validation.

Files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
tests/integration/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use pytest for all integration tests; do not use unittest.

Files:

  • tests/integration/endpoints/test_config_integration.py
tests/unit/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

tests/unit/**/*.py: Use pytest for all unit tests; do not use unittest.
Use conftest.py for shared fixtures, pytest-mock for AsyncMock objects, and pytest.mark.asyncio for asynchronous tests.

Files:

  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/models/config/test_observability_configuration.py
🧠 Learnings (5)
📚 Learning: 2026-01-12T10:58:40.230Z
Learnt from: blublinsky
Repo: lightspeed-core/lightspeed-stack PR: 972
File: src/models/config.py:459-513
Timestamp: 2026-01-12T10:58:40.230Z
Learning: In lightspeed-core/lightspeed-stack, for Python files under src/models, when a user claims a fix is done but the issue persists, verify the current code state before accepting the fix. Steps: review the diff, fetch the latest changes, run relevant tests, reproduce the issue, search the codebase for lingering references to the original problem, confirm the fix is applied and not undone by subsequent commits, and validate with local checks to ensure the issue is resolved.

Applied to files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
📚 Learning: 2026-02-25T07:46:33.545Z
Learnt from: asimurka
Repo: lightspeed-core/lightspeed-stack PR: 1211
File: src/models/responses.py:8-16
Timestamp: 2026-02-25T07:46:33.545Z
Learning: In the Python codebase, requests.py should use OpenAIResponseInputTool as Tool while responses.py uses OpenAIResponseTool as Tool. This difference is intentional due to differing schemas for input vs output tools in llama-stack-api. Apply this distinction consistently to other models under src/models (e.g., ensure request-related tools use the InputTool variant and response-related tools use the ResponseTool variant). If adding new tools, choose the corresponding InputTool or Tool class based on whether the tool represents input or output, and document the rationale in code comments.

Applied to files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
📚 Learning: 2026-06-24T13:45:37.249Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 1971
File: src/utils/markdown_repair.py:31-36
Timestamp: 2026-06-24T13:45:37.249Z
Learning: In the lightspeed-stack repository, docstrings must use the section header name "Parameters:" (not "Args:") for function arguments, even if the project references Google Python docstring conventions. Ensure docstrings follow the project’s established "Parameters:" header format for any documented function parameters.

Applied to files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
  • tests/integration/endpoints/test_config_integration.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/models/config/test_observability_configuration.py
📚 Learning: 2026-07-06T15:26:18.398Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 2071
File: src/models/config.py:2416-2422
Timestamp: 2026-07-06T15:26:18.398Z
Learning: In this repo’s Python code under src/**, don’t treat differences in string concatenation style as a style inconsistency when Black has effectively forced (or made clearer) use of explicit `+` string concatenation in multi-line logger/string expressions. If adjacent-literal implicit concatenation is avoided/changed specifically to accommodate Black’s formatting in these call sites, accept the `+` usage and don’t recommend converting it solely for consistency with nearby blocks that use implicit concatenation.

Applied to files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
📚 Learning: 2026-07-17T19:25:05.325Z
Learnt from: Jdubrick
Repo: lightspeed-core/lightspeed-stack PR: 2166
File: src/utils/saved_prompts.py:129-157
Timestamp: 2026-07-17T19:25:05.325Z
Learning: For any endpoint that handles saved prompts and calls `src/utils/saved_prompts.py::create_saved_prompt`, treat the endpoint as the validation boundary. Before calling `create_saved_prompt`, validate the incoming saved-prompt name and content, specifically using `validate_saved_prompt_name` and then persist (store) the normalized value it returns. Do not call `create_saved_prompt` with unvalidated/raw name/content.

Applied to files:

  • src/models/api/responses/successful/configuration.py
  • src/models/config.py
🪛 ast-grep (0.45.0)
tests/unit/models/config/test_observability_configuration.py

[warning] 259-259: Do not make http calls without encryption
Context: "http://collector:4317"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)


[warning] 270-270: Do not make http calls without encryption
Context: "http://collector:4317"
Note: [CWE-319] Cleartext Transmission of Sensitive Information.

(requests-http)

🔇 Additional comments (12)
src/models/config.py (3)

5-5: LGTM!


2834-2848: LGTM!


3072-3077: LGTM!

src/models/api/responses/successful/configuration.py (1)

90-98: LGTM!

docs/devel_doc/openapi.json (2)

15133-15148: Same redaction gap flagged previously.

This re-introduces the ObservabilityConfiguration schema with the same structure previously reviewed. The prior round noted that only OTEL_EXPORTER_OTLP_HEADERS appears redacted, while per-signal variants (OTEL_EXPORTER_OTLP_TRACES_HEADERS, _METRICS_HEADERS, _LOGS_HEADERS) are valid OTEL_* values that can carry bearer/API tokens and should also be masked before exposure via /v1/config. src/models/config.py (where from_environment()/redaction logic lives) isn't included in this batch, so I can't confirm whether this was addressed — please verify.


6756-6764: LGTM!

Also applies to: 12379-12383, 12480-12488

tests/unit/models/config/test_observability_configuration.py (2)

1-146: LGTM!


149-313: LGTM! These redaction tests (including the new signal-specific header/cert coverage at lines 254-294) close the gap flagged in the prior review round.

tests/unit/models/config/test_dump_configuration.py (2)

7-11: LGTM!


257-257: LGTM!

Also applies to: 485-485, 864-864, 1127-1127, 1423-1423, 1646-1646, 2029-2029, 2258-2258, 2487-2487, 2723-2723

tests/integration/endpoints/test_config_integration.py (2)

93-121: LGTM!


152-158: 🩺 Stability & Availability

No change needed. current_config is function-scoped and the integration conftest auto-resets singleton configuration state before each test.

Comment thread src/models/config.py
Comment on lines +2850 to +2908
@field_validator("otel", mode="before")
@classmethod
def redact_secrets(cls, value: dict[str, str]) -> dict[str, str]:
"""Redact sensitive OTEL environment variables.

Redacts headers, certificates, and client keys for generic and signal-specific
(traces, metrics, logs) OTLP exporters.

Parameters:
----------
value: Dictionary of OTEL environment variables

Returns:
New dictionary with sensitive values redacted as "[REDACTED]"
"""
if not value:
return value

# Create a new dict to avoid mutating caller's data
redacted = {}

for key, val in value.items():
# Redact generic and signal-specific OTLP headers
# Matches: OTEL_EXPORTER_OTLP_HEADERS,
# OTEL_EXPORTER_OTLP_TRACES_HEADERS,
# OTEL_EXPORTER_OTLP_METRICS_HEADERS,
# OTEL_EXPORTER_OTLP_LOGS_HEADERS
if "HEADERS" in key and "OTLP" in key:
redacted[key] = "[REDACTED]"
# Redact generic and signal-specific certificates
# Matches: OTEL_EXPORTER_OTLP_CERTIFICATE,
# OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE, etc.
elif "CERTIFICATE" in key and "OTLP" in key:
redacted[key] = "[REDACTED]"
# Redact generic and signal-specific client keys
# Matches: OTEL_EXPORTER_OTLP_CLIENT_KEY,
# OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY, etc.
elif "CLIENT_KEY" in key and "OTLP" in key:
redacted[key] = "[REDACTED]"
else:
redacted[key] = val

return redacted

@classmethod
def from_environment(cls) -> "ObservabilityConfiguration":
"""Collect all OTEL_* environment variables from the environment.

Sensitive variables (headers, certificates, keys) are automatically redacted
by the field validator.

Returns:
ObservabilityConfiguration with otel dict populated from environment.
"""
otel_vars = {}
for key, value in os.environ.items():
if key.startswith("OTEL_"):
otel_vars[key] = value
return cls(otel=otel_vars)

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.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Redact unknown OTEL_* values by default.

The collector exports every OTEL_* variable, but the validator masks only keys containing HEADERS, CERTIFICATE, or CLIENT_KEY. Values such as OTEL_RESOURCE_ATTRIBUTES or vendor extension variables (for example, OTEL_VENDOR_API_TOKEN) are returned verbatim through the configuration response. Use a reviewed safe allowlist, redact unknown values, and sanitize compound values.

Based on learnings, verify the current fix fully resolves the earlier broad environment-variable disclosure concern.

🤖 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 `@src/models/config.py` around lines 2850 - 2908, Update
ObservabilityConfiguration.redact_secrets to use a reviewed allowlist of
explicitly safe OTEL variable names, redacting every unknown key—including
resource attributes and vendor extensions—by default. Preserve only allowlisted
non-sensitive values, and sanitize compound values so embedded secrets are not
returned verbatim; ensure from_environment’s complete OTEL_* collection cannot
bypass this validator.

Source: Learnings

Comment on lines +57 to +74
@pytest.fixture(name="clear_otel_env", autouse=True)
def clear_otel_env_fixture(monkeypatch: pytest.MonkeyPatch) -> None:
"""Clear OTEL_* environment variables to prevent ambient leakage in tests.

This fixture ensures dump configuration tests have stable expectations
regardless of whether they run on instrumented CI runners.
"""
for key in list(os.environ.keys()):
if key.startswith("OTEL_"):
monkeypatch.delenv(key, raising=False)


def _get_expected_observability_dump() -> dict[str, dict[str, str]]:
"""Get expected observability dump based on current environment.

Returns empty otel dict when OTEL_* vars are cleared by fixture.
"""
return {"otel": {}}

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the fixture's monkeypatch parameter; tighten the helper's docstring.

clear_otel_env_fixture takes monkeypatch but its docstring has no Parameters: section. As per coding guidelines, "document all modules, classes, and functions, including Parameters, Returns, Raises, and Attributes sections as applicable." Based on learnings, use the Parameters: header (not Args:).

Separately, _get_expected_observability_dump's docstring says the result is computed "based on current environment," but the function just returns a hardcoded {"otel": {}} — it never reads os.environ. It's correct today because the autouse fixture always clears OTEL_* first, but the wording invites someone to reuse this helper without that guarantee.

📝 Proposed docstring fixes
 `@pytest.fixture`(name="clear_otel_env", autouse=True)
 def clear_otel_env_fixture(monkeypatch: pytest.MonkeyPatch) -> None:
     """Clear OTEL_* environment variables to prevent ambient leakage in tests.
 
     This fixture ensures dump configuration tests have stable expectations
     regardless of whether they run on instrumented CI runners.
+
+    Parameters:
+    ----------
+        monkeypatch (pytest.MonkeyPatch): Pytest fixture for environment manipulation.
     """
     for key in list(os.environ.keys()):
         if key.startswith("OTEL_"):
             monkeypatch.delenv(key, raising=False)


 def _get_expected_observability_dump() -> dict[str, dict[str, str]]:
-    """Get expected observability dump based on current environment.
-
-    Returns empty otel dict when OTEL_* vars are cleared by fixture.
-    """
+    """Get the expected observability dump for tests in this module.
+
+    Returns a static empty otel dict, relying on the autouse
+    `clear_otel_env` fixture to guarantee no OTEL_* vars are set.
+    """
     return {"otel": {}}
📝 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
@pytest.fixture(name="clear_otel_env", autouse=True)
def clear_otel_env_fixture(monkeypatch: pytest.MonkeyPatch) -> None:
"""Clear OTEL_* environment variables to prevent ambient leakage in tests.
This fixture ensures dump configuration tests have stable expectations
regardless of whether they run on instrumented CI runners.
"""
for key in list(os.environ.keys()):
if key.startswith("OTEL_"):
monkeypatch.delenv(key, raising=False)
def _get_expected_observability_dump() -> dict[str, dict[str, str]]:
"""Get expected observability dump based on current environment.
Returns empty otel dict when OTEL_* vars are cleared by fixture.
"""
return {"otel": {}}
`@pytest.fixture`(name="clear_otel_env", autouse=True)
def clear_otel_env_fixture(monkeypatch: pytest.MonkeyPatch) -> None:
"""Clear OTEL_* environment variables to prevent ambient leakage in tests.
This fixture ensures dump configuration tests have stable expectations
regardless of whether they run on instrumented CI runners.
Parameters:
----------
monkeypatch (pytest.MonkeyPatch): Pytest fixture for environment manipulation.
"""
for key in list(os.environ.keys()):
if key.startswith("OTEL_"):
monkeypatch.delenv(key, raising=False)
def _get_expected_observability_dump() -> dict[str, dict[str, str]]:
"""Get the expected observability dump for tests in this module.
Returns a static empty otel dict, relying on the autouse
`clear_otel_env` fixture to guarantee no OTEL_* vars are set.
"""
return {"otel": {}}
🤖 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 `@tests/unit/models/config/test_dump_configuration.py` around lines 57 - 74,
Update the docstrings for clear_otel_env_fixture and
_get_expected_observability_dump. Add a Parameters: section documenting the
monkeypatch parameter in clear_otel_env_fixture, and revise the helper docstring
to state that it returns the fixed expected observability dump with an empty
otel mapping, without implying it reads the environment.

Sources: Coding guidelines, Learnings

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.

2 participants