Skip to content

feat(extraction): log sticky runtime start failures via domain probe#790

Merged
aredenba-rh merged 1 commit into
mainfrom
fix/gma-runtime-start-failure-observability
Jul 7, 2026
Merged

feat(extraction): log sticky runtime start failures via domain probe#790
aredenba-rh merged 1 commit into
mainfrom
fix/gma-runtime-start-failure-observability

Conversation

@aredenba-rh

Copy link
Copy Markdown
Collaborator

Summary

  • The Graph Management Assistant's "no credentials resolved" / RUNTIME_START_FAILED error is completely invisible server-side today: it's only ever surfaced to the browser via the /runtime/warm NDJSON stream body, with zero corresponding log line in the api container (confirmed via 9+ hours of production logs with no matches for "vertex", "provider", "credential", etc).
  • Adds a StickySessionRuntimeProbe (Domain-Oriented Observability) that logs the raw failure detail (error=str(exc)) whenever get_or_start_runtime raises or the health wait times out, in both stream_runtime_warmup and ensure_runtime_for_chat code paths.
  • This is a pure observability addition (no behavior change) so the next occurrence of this or any other sticky-runtime start failure is immediately visible via kubectl logs/ArgoCD without needing to reproduce it live.

Test plan

  • uv run pytest tests/unit/extraction/application/observability/test_sticky_session_runtime_probe.py -v
  • uv run pytest tests/unit/extraction/application/test_sticky_session_runtime_service.py -v
  • uv run pytest tests/unit -q (full suite, 3512 passed)
  • uv run ruff format / ruff check on changed files

Made with Cursor

The Graph Management Assistant "no credentials resolved" / RUNTIME_START_FAILED
error was invisible server-side: it only ever reached the browser via the
runtime/warm NDJSON stream, with no corresponding log line in the api
container. Add a StickySessionRuntimeProbe (Domain-Oriented Observability)
that logs the raw failure/timeout detail whenever get_or_start_runtime or the
health wait fails, so future occurrences show up in kubectl/ArgoCD logs
without needing to reproduce them interactively.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added structured observability for sticky-session runtime events, including startup failures and unhealthy runtime states.
    • The runtime service now accepts an optional observability hook, enabling richer runtime event reporting.
  • Tests

    • Added unit coverage for the new observability behavior.
    • Expanded service tests to verify runtime failure notifications are emitted as expected.

Walkthrough

New StickySessionRuntimeProbe protocol and DefaultStickySessionRuntimeProbe structlog-backed implementation added under observability module, exposing runtime_start_failed, runtime_unhealthy, and with_context operations. StickySessionRuntimeService constructor accepts an optional probe parameter, defaulting to DefaultStickySessionRuntimeProbe(), and invokes probe callbacks on container start failure and health-check timeout paths. Unit tests added for the probe's structured logging output and for service-level invocation of runtime_start_failed via a recording test double.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
  participant StickySessionRuntimeService
  participant ContainerRuntime
  participant StickySessionRuntimeProbe
  participant structlog

  StickySessionRuntimeService->>ContainerRuntime: start runtime
  ContainerRuntime--xStickySessionRuntimeService: ContainerRuntimeError/RuntimeError
  StickySessionRuntimeService->>StickySessionRuntimeProbe: runtime_start_failed(session_id, knowledge_graph_id, mode, error)
  StickySessionRuntimeProbe->>structlog: logger.error("sticky_runtime_start_failed", context)

  StickySessionRuntimeService->>ContainerRuntime: health check
  ContainerRuntime--xStickySessionRuntimeService: TimeoutError
  StickySessionRuntimeService->>StickySessionRuntimeProbe: runtime_unhealthy(session_id, knowledge_graph_id, mode, error)
  StickySessionRuntimeProbe->>structlog: logger.error("sticky_runtime_unhealthy", context)
Loading

Related PRs: None identified from provided data.

Suggested labels: observability, testing

Suggested reviewers: No mentions provided; assign per team ownership of src/api/extraction/application.

Security note (per role): No dependency, CI/CD, IDE config, or .gitattributes changes present in this diff — no supply-chain surface introduced. Structured logging fields (session_id, knowledge_graph_id, mode, error) are emitted via structlog.error; verify no PII or credential material flows into error strings from caught exceptions (CWE-532: Insertion of Sensitive Information into Log File) before merge.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Sec-02: Secrets In Log Output ❌ Error CWE-532/CWE-209: error=str(exc) is logged verbatim in runtime_start_failed and runtime_unhealthy, so secret-bearing exceptions can reach logs. Redact exception text before logging; emit only sanitized codes/causes and keep raw detail out of logger.error(...) fields.
No Pii Or Sensitive Data In Logs ⚠️ Warning DefaultStickySessionRuntimeProbe logs session_id/knowledge_graph_id on errors, and the service logs raw str(exc); this matches CWE-532/CWE-209 risk. Redact session_id and exception text before logging; use opaque/hashes for identifiers and sanitize stderr-derived failure messages.
✅ Passed checks (9 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: adding domain-probe logging for sticky runtime start failures.
Description check ✅ Passed The description is directly aligned with the observability probe and runtime failure logging changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
No Hardcoded Secrets ✅ Passed No hardcoded credentials, embedded user:pass URLs, or long base64 secrets appear in the changed files; only dynamic runtime error strings/logging (CWE-798/CWE-259).
No Weak Cryptography ✅ Passed No CWE-327/CWE-208 issues: the touched files add only observability/logging, with no md5/des/rc4/sha1, ECB, custom crypto, or secret comparisons.
No Injection Vectors ✅ Passed No CWE-89/78/79/502 injection vectors found: the new code only passes typed args to a probe/logger; no SQL concat, exec, template.HTML, or yaml.Unmarshal in non-test code.
No Privileged Containers ✅ Passed PASS: PR touches only Python and uv.lock; no Kubernetes/OpenShift manifests, Helm templates, or Dockerfiles changed, and no privileged fields were introduced.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/gma-runtime-start-failure-observability
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/gma-runtime-start-failure-observability

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

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

🤖 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/api/extraction/application/observability/sticky_session_runtime_probe.py`:
- Around line 75-113: The sticky session runtime probe methods are logging and
forwarding raw exception text, which can leak sensitive Docker/Podman/OpenShell
details. Update runtime_start_failed and runtime_unhealthy to sanitize the error
argument before calling self._logger.error, and apply the same redaction before
any API response uses the exception text. Keep the existing context fields, but
ensure ContainerRuntimeError/RuntimeError messages are scrubbed for secrets or
connection data before emission.
🪄 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: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 3d28b8c9-50a5-4cd6-9415-a20906ae0068

📥 Commits

Reviewing files that changed from the base of the PR and between 4dd935e and 5a5b990.

⛔ Files ignored due to path filters (1)
  • src/api/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • src/api/extraction/application/observability/__init__.py
  • src/api/extraction/application/observability/sticky_session_runtime_probe.py
  • src/api/extraction/application/sticky_session_runtime_service.py
  • src/api/tests/unit/extraction/application/observability/test_sticky_session_runtime_probe.py
  • src/api/tests/unit/extraction/application/test_sticky_session_runtime_service.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)

Comment on lines +75 to +113
def runtime_start_failed(
self,
*,
session_id: str,
knowledge_graph_id: str,
mode: str,
error: str,
) -> None:
context_kwargs = self._get_context_kwargs(
exclude={"session_id", "knowledge_graph_id", "mode", "error"}
)
self._logger.error(
"sticky_runtime_start_failed",
session_id=session_id,
knowledge_graph_id=knowledge_graph_id,
mode=mode,
error=error,
**context_kwargs,
)

def runtime_unhealthy(
self,
*,
session_id: str,
knowledge_graph_id: str,
mode: str,
error: str,
) -> None:
context_kwargs = self._get_context_kwargs(
exclude={"session_id", "knowledge_graph_id", "mode", "error"}
)
self._logger.error(
"sticky_runtime_unhealthy",
session_id=session_id,
knowledge_graph_id=knowledge_graph_id,
mode=mode,
error=error,
**context_kwargs,
)

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 | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== file outline ==\n'
ast-grep outline src/api/extraction/application/observability/sticky_session_runtime_probe.py --view expanded || true

printf '\n== relevant references ==\n'
rg -n "runtime_start_failed|runtime_unhealthy|ContainerRuntimeError|str\\(exc\\)|no credentials resolved|redact|sanitize|secret|credential" src/api/extraction src/api/shared_kernel src/api -g '!**/__pycache__/**' || true

printf '\n== nearby file slice ==\n'
sed -n '1,220p' src/api/extraction/application/observability/sticky_session_runtime_probe.py

printf '\n== runtime service slice ==\n'
sed -n '1,260p' src/api/extraction/application/sticky_session_runtime_service.py

Repository: openshift-hyperfleet/kartograph

Length of output: 50388


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '260,380p' src/api/extraction/application/sticky_session_runtime_service.py
printf '\n== probe file ==\n'
sed -n '1,180p' src/api/extraction/application/observability/sticky_session_runtime_probe.py
printf '\n== runtime error type ==\n'
sed -n '1,120p' src/api/shared_kernel/container_runtime/ports.py

Repository: openshift-hyperfleet/kartograph

Length of output: 10319


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,240p' src/api/shared_kernel/container_runtime/cli_runtime.py
printf '\n== grep for runtime error propagation ==\n'
rg -n "ContainerRuntimeError\\(|raise RuntimeError\\(|detail|stderr|stdout|redact|sanitize" src/api/shared_kernel/container_runtime src/api/extraction/application src/api/extraction/infrastructure -g '!**/__pycache__/**'

Repository: openshift-hyperfleet/kartograph

Length of output: 24565


CWE-532/CWE-209: redact runtime exception text before logging or returning it.
error=str(exc) is emitted unchanged here, and the same text is also forwarded to the API response. ContainerRuntimeError/RuntimeError can carry Docker/Podman/OpenShell stderr/stdout, so any token, connection string, or credential fragment in the failure text will land in logs and user-visible errors. Redact known secret patterns before emitting.

🤖 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/api/extraction/application/observability/sticky_session_runtime_probe.py`
around lines 75 - 113, The sticky session runtime probe methods are logging and
forwarding raw exception text, which can leak sensitive Docker/Podman/OpenShell
details. Update runtime_start_failed and runtime_unhealthy to sanitize the error
argument before calling self._logger.error, and apply the same redaction before
any API response uses the exception text. Keep the existing context fields, but
ensure ContainerRuntimeError/RuntimeError messages are scrubbed for secrets or
connection data before emission.

Source: Path instructions

@aredenba-rh aredenba-rh merged commit cb9f4a7 into main Jul 7, 2026
10 checks passed
@aredenba-rh aredenba-rh deleted the fix/gma-runtime-start-failure-observability branch July 7, 2026 17:17
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