Skip to content

New Evals for newrelic - #983

Merged
Avi-Robusta merged 49 commits into
masterfrom
evals-newrelic
Sep 22, 2025
Merged

Avi-Robusta merged 49 commits into
masterfrom
evals-newrelic

Conversation

@Avi-Robusta

Copy link
Copy Markdown
Collaborator

No description provided.

Sheeproid and others added 30 commits September 10, 2025 11:22
This demo environment in the trace-demo namespace runs three microservices—checkout (Node.js), inventory (Node.js), and risk (Python/Flask)—alongside a Postgres 16 database with an orders table. Checkout orchestrates requests by calling Inventory for stock checks, Risk for fraud scoring, and then writing to Postgres before replying to the client. Each service exposes a /healthz endpoint, logs via standard libraries, and is labeled for New Relic auto-instrumentation, so traces stitch across all components.
@CLAassistant

CLAassistant commented Sep 21, 2025 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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

Caution

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

⚠️ Outside diff range comments (6)
holmes/core/supabase_dal.py (3)

334-349: Avoid duplicate entries when adding alert_raw_data; also add type hints and simplify logic.

alert_raw_data items are currently included in data and also appended post‑decompression, yielding duplicates (and since unzip_evidence_file mutates in place, you end up with the same dict twice). Exclude compressed items up front and use a single membership test for the decompressible types. Added return/param hints per guidelines.

-def extract_relevant_issues(self, evidence):
+def extract_relevant_issues(self, evidence: Any) -> List[Dict]:
+    decompress_types = {"text_file", "alert_raw_data"}
     data = [
         enrich
         for enrich in evidence.data
-        if enrich.get("enrichment_type") not in ENRICHMENT_BLACKLIST_SET
+        if enrich.get("enrichment_type") not in ENRICHMENT_BLACKLIST_SET
+        and enrich.get("enrichment_type") not in decompress_types
     ]
 
     unzipped_files = [
         self.unzip_evidence_file(enrich)
         for enrich in evidence.data
-        if enrich.get("enrichment_type") == "text_file"
-        or enrich.get("enrichment_type") == "alert_raw_data"
+        if enrich.get("enrichment_type") in decompress_types
     ]
 
     data.extend(unzipped_files)
     return data

8-8: Import Any to support the added type hint.

Required for the evidence: Any annotation.

-from typing import Dict, List, Optional, Tuple
+from typing import Any, Dict, List, Optional, Tuple

330-333: Sanitize exception logging to avoid leaking payloads (PII/compliance risk).

On unzip failure we log the entire evidence record, which may include sensitive data. Log only metadata.

-        except Exception:
-            logging.exception(f"Unknown issue unzipping gz finding: {data}")
-            return data
+        except Exception:
+            logging.exception(
+                "Failed to unzip gz finding (type=%s, evidence_id=%s, data_len=%s).",
+                data.get("enrichment_type", "unknown"),
+                data.get("id", "unknown"),
+                len(str(data.get("data", ""))),
+            )
+            return data
holmes/plugins/toolsets/newrelic/newrelic.py (3)

100-101: Return a StructuredToolResult on missing configuration instead of raising.

Tools under holmes/{core,plugins} must surface detailed, structured errors rather than raising. Replace the ValueError with an ERROR result that includes context.

Apply:

-        if not self._toolset.nr_api_key or not self._toolset.nr_account_id:
-            raise ValueError("NewRelic API key or account ID is not configured")
+        if not self._toolset.nr_api_key or not self._toolset.nr_account_id:
+            return StructuredToolResult(
+                status=StructuredToolResultStatus.ERROR,
+                error="New Relic API key or account ID is not configured",
+                params={"reason": "missing_config"},
+                invocation="newrelic_execute_nrql_query",
+            )

136-147: Metrics branch likely inverted the fallback condition.

Currently, when results exist, you overwrite the formatted payload with the raw result; that’s the opposite of the intended flow. Also consider signaling NO_DATA explicitly when empty.

-            return_result = self.format_metrics(result, params=enriched_params)
-            if len(return_result.get("data", {}).get("results", [])):
-                return_result = result  # type: ignore[assignment]
+            return_result = self.format_metrics(result, params=enriched_params)
+            if not return_result.get("data", {}).get("results"):
+                # Optional: keep raw NRQL rows to aid debugging empty responses
+                return StructuredToolResult(
+                    status=StructuredToolResultStatus.NO_DATA,
+                    data={
+                        "message": "No metrics returned from NRQL",
+                        "query": query,
+                        "raw_result": result,
+                    },
+                    params=params,
+                    invocation=query,
+                )

(The final SUCCESS return below can remain unchanged.)


155-198: Avoid logging entire log records on exception (PII risk).

Dumping records may leak sensitive data. Log count and a sample of keys instead.

-        except Exception:
-            logging.exception(f"Failed to reformat newrelic logs {records}")
-            return records
+        except Exception:
+            logging.exception(
+                "Failed to reformat newrelic logs; record_count=%d",
+                len(records) if isinstance(records, list) else -1,
+            )
+            return records
🧹 Nitpick comments (8)
tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml (1)

7-7: Consider making EU datacenter setting more explicit.

The comment suggests using "{{env.NEW_RELIC_IS_EU}}" but defaults to hardcoded false. Consider defaulting to the environment variable with a fallback to maintain consistency.

-      is_eu_datacenter: false # set "{{env.NEW_RELIC_IS_EU}}" with true to use eu
+      is_eu_datacenter: "{{env.NEW_RELIC_IS_EU|false}}" # set to true to use EU datacenter

This makes the pattern consistent with the other configuration values and allows runtime override while maintaining the same default behavior.

holmes/plugins/toolsets/newrelic/newrelic.py (4)

199-201: Add type hint to params.

mypy requirement: all Python code must include type hints.

-    def get_parameterized_one_liner(self, params) -> str:
+    def get_parameterized_one_liner(self, params: Dict[str, Any]) -> str:

253-255: Add return type to stub.

-    def call_nerdql(self):
+    def call_nerdql(self) -> None:
         pass

66-66: Typo: “breif” -> “brief”.

User-facing copy should be clean.

-                    description="A breif 6 word human understandable description of the query you are running.",
+                    description="A brief 6 word human understandable description of the query you are running.",

41-41: Typo in docs string: “Usa ge” -> “Usage”.

-### ⚠️ Critical Rule: NRQL `FACET` Usa ge
+### ⚠️ Critical Rule: NRQL `FACET` Usage
tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/setup.sh (3)

3-3: Namespace creation should be idempotent.

kubectl create namespace app-117 fails on reruns. Use get-or-create to support repeated CI runs.

-kubectl create namespace app-117
+kubectl get ns app-117 >/dev/null 2>&1 || kubectl create namespace app-117

5-16: Make secret creation idempotent to avoid rerun failures.

kubectl create secret errors if the secret exists. Use dry-run + apply.

-kubectl -n app-117 create secret generic checkout-src \
-  --from-file=server.js=checkout/server.js \
-  --from-file=package.json=checkout/package.json
+kubectl -n app-117 create secret generic checkout-src \
+  --from-file=server.js=checkout/server.js \
+  --from-file=package.json=checkout/package.json \
+  --dry-run=client -o yaml | kubectl apply -f -
 
-kubectl -n app-117 create secret generic inventory-src \
-  --from-file=server.js=inventory/server.js \
-  --from-file=package.json=inventory/package.json
+kubectl -n app-117 create secret generic inventory-src \
+  --from-file=server.js=inventory/server.js \
+  --from-file=package.json=inventory/package.json \
+  --dry-run=client -o yaml | kubectl apply -f -
 
-kubectl -n app-117 create secret generic risk-src \
-  --from-file=app.py=risk/app.py \
-  --from-file=requirements.txt=risk/requirements.txt
+kubectl -n app-117 create secret generic risk-src \
+  --from-file=app.py=risk/app.py \
+  --from-file=requirements.txt=risk/requirements.txt \
+  --dry-run=client -o yaml | kubectl apply -f -

25-27: Wait on the StatefulSet directly for stronger guarantees (optional).

Waiting on pods by label works but can be brittle with restarts. If the name is stable, prefer statefulset/postgres.

-echo "Waiting for postgres statefulset to be ready..."
-kubectl wait --for=condition=ready --timeout=300s pod -l app=postgres -n app-117
+echo "Waiting for postgres statefulset to be ready..."
+kubectl wait --for=condition=ready --timeout=300s statefulset/postgres -n app-117
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cff789f and b9726c4.

📒 Files selected for processing (8)
  • holmes/core/supabase_dal.py (1 hunks)
  • holmes/plugins/toolsets/newrelic/newrelic.jinja2 (1 hunks)
  • holmes/plugins/toolsets/newrelic/newrelic.py (3 hunks)
  • tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/instrumentation.yaml (2 hunks)
  • tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/setup.sh (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/test_case.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/120_new_relic_traces2/test_case.yaml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/test_case.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/llm/fixtures/test_ask_holmes/120_new_relic_traces2/test_case.yaml
🧰 Additional context used
📓 Path-based instructions (9)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always place Python imports at the top of the file, not inside functions or methods
All Python code must include type hints (mypy enforced)

Files:

  • holmes/core/supabase_dal.py
  • holmes/plugins/toolsets/newrelic/newrelic.py
holmes/{core,plugins}/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

All tools must return detailed error messages from underlying APIs, including executed command/query, time ranges/parameters, and full API error response; 'no data' responses must specify what was searched and where

Files:

  • holmes/core/supabase_dal.py
  • holmes/plugins/toolsets/newrelic/newrelic.py
tests/**

📄 CodeRabbit inference engine (CLAUDE.md)

Test layout should mirror the source structure under tests/

Files:

  • tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/setup.sh
  • tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/instrumentation.yaml
  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml
tests/llm/fixtures/**/*.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

tests/llm/fixtures/**/*.yaml: Each LLM test must use a dedicated Kubernetes namespace 'app-' to prevent conflicts when running in parallel
All pod names in evals must be unique across tests; never reuse pod names

Files:

  • tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/instrumentation.yaml
  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml
tests/llm/fixtures/**/*.{yaml,md,log,txt}

📄 CodeRabbit inference engine (CLAUDE.md)

Eval artifacts must be realistic and neutral: no obvious/fake logs, no filenames or resource names that hint at the problem, and no messages revealing simulation

Files:

  • tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/instrumentation.yaml
  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml
tests/llm/**/*.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Always use Kubernetes Secrets for scripts in evals; do not embed scripts inline in manifests or ConfigMaps

Files:

  • tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/instrumentation.yaml
  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml
tests/llm/**/toolsets.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

In evals, all toolset-specific configuration must be under a top-level 'config' field in toolsets.yaml; do not place toolset config directly at the top level

Files:

  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml
{holmes/plugins/toolsets/**/*.yaml,tests/llm/**/toolsets.yaml}

📄 CodeRabbit inference engine (CLAUDE.md)

Valid top-level fields for toolset YAMLs are limited to: enabled, name, description, additional_instructions, prerequisites, tools, docs_url, icon_url, installation_instructions, config, url (MCP only)

Files:

  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml
holmes/plugins/toolsets/**

📄 CodeRabbit inference engine (CLAUDE.md)

Toolsets must be organized under holmes/plugins/toolsets/ as either {name}.yaml files or directories

Files:

  • holmes/plugins/toolsets/newrelic/newrelic.py
  • holmes/plugins/toolsets/newrelic/newrelic.jinja2
🧠 Learnings (3)
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to {holmes/plugins/toolsets/**/*.yaml,tests/llm/**/toolsets.yaml} : Valid top-level fields for toolset YAMLs are limited to: enabled, name, description, additional_instructions, prerequisites, tools, docs_url, icon_url, installation_instructions, config, url (MCP only)

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to tests/llm/**/test_case.yaml : Do not include toolset configuration in test_case.yaml; if runbooks are specified, entries must point to .md files in the same directory

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to tests/llm/**/toolsets.yaml : In evals, all toolset-specific configuration must be under a top-level 'config' field in toolsets.yaml; do not place toolset config directly at the top level

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml
🧬 Code graph analysis (1)
holmes/plugins/toolsets/newrelic/newrelic.py (2)
holmes/utils/keygen_utils.py (1)
  • generate_random_key (5-6)
holmes/core/tools.py (2)
  • StructuredToolResult (78-102)
  • StructuredToolResultStatus (51-75)
🪛 Shellcheck (0.11.0)
tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/setup.sh

[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.

(SC2148)

⏰ 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). (4)
  • GitHub Check: build (3.12)
  • GitHub Check: build (3.11)
  • GitHub Check: build (3.10)
  • GitHub Check: llm_evals
🔇 Additional comments (8)
tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml (2)

1-7: LGTM! Configuration structure follows the required pattern.

The toolset configuration correctly places all New Relic-specific settings under the top-level config field as required by the coding guidelines. The structure with enabled: true and environment variable placeholders for sensitive data follows best practices.


5-6: Document NEW_RELIC_ACCOUNT_ID and NEW_RELIC_API_KEY in test setup

tests/llm/fixtures/test_ask_holmes/117b_new_relic_block_embed/toolsets.yaml (lines 5–6) references NEW_RELIC_ACCOUNT_ID and NEW_RELIC_API_KEY but a repository-wide search returned no documentation or README entries. Add both variables to the relevant test setup/prerequisites (fixture README or project README) and state expected values/format.

holmes/plugins/toolsets/newrelic/newrelic.py (2)

18-18: Import of generate_random_key is appropriate.

Matches the new embedding workflow that requires a per-response key.


225-226: Graduating toolset from experimental: verify readiness.

Non-experimental implies stability. Confirm docs updated and e2e tests cover logs, metrics (TIMESERIES), traces, and empty-result paths.

Would you like a quick script to scan tests under tests/llm/fixtures/test_ask_holmes for NR cases and list coverage gaps?

tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/instrumentation.yaml (3)

1-2: Docs links helpful.

Keeping pointers to upstream operator docs in the fixture is useful for maintenance.


12-17: Confirm reserved namespace label exists or use a custom label

File: tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/instrumentation.yaml Lines: 12-17 (also applies to 27-31)

Automated check failed: kubectl not available in sandbox. Manually verify that namespace "app-117" exposes label "kubernetes.io/metadata.name" — if empty, add and match a custom label instead.

Verify:
kubectl get ns app-117 -o jsonpath='{.metadata.labels.kubernetes.io/metadata.name}{"\n"}'

Add label (if needed):
kubectl label ns app-117 app.newrelic.instrumentation=enabled --overwrite


11-11: Pin New Relic init images to an immutable version or digest — do not use :latest

Replace :latest with a specific version tag (major.minor.patch, or nodejs-suffixed for Node builds) or, preferably, a sha256 digest to make CI reproducible. New Relic supports versioned tags and Node-specific tags (e.g., 11.19.0-nodejs20x).

Example:

-    image: newrelic/newrelic-node-init:latest
+    image: newrelic/newrelic-node-init:<major.minor.patch-nodejsXX> # or sha256:<digest>

-    image: newrelic/newrelic-python-init:latest
+    image: newrelic/newrelic-python-init:<major.minor.patch> # or sha256:<digest>
tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/setup.sh (1)

17-20: No action required — both db.yaml and manifest.yaml already specify metadata.namespace: app-117.
Applying them without -n will deploy into app-117.

Comment thread holmes/plugins/toolsets/newrelic/newrelic.jinja2
Comment thread holmes/plugins/toolsets/newrelic/newrelic.py
Comment thread tests/llm/fixtures/test_ask_holmes/117_new_relic_tracing/setup.sh

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

Caution

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

⚠️ Outside diff range comments (1)
tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml (1)

15-73: Use the required dedicated namespace per test: app-121 (and fix all occurrences).

Current namespace "nr-115" violates the guideline and may collide with other evals. Align the echo text with the test id too.

-before_test: |
-  echo "🚀 Setting up test 115 - Creating namespace nr-115"
-  kubectl create namespace nr-115 || true
-  echo "✅ Namespace nr-115 created successfully!"
+before_test: |
+  echo "🚀 Setting up test 121 - Creating namespace app-121"
+  kubectl create namespace app-121 || true
+  echo "✅ Namespace app-121 created successfully!"
@@
-  kubectl apply -f ../../shared/tempo.yaml -n nr-115
+  kubectl apply -f ../../shared/tempo.yaml -n app-121
@@
-  kubectl create secret generic newrelickey --from-literal=key="${NEW_RELIC_LICENSE_KEY}" -n nr-115
+  kubectl create secret generic newrelickey --from-literal=key="${NEW_RELIC_LICENSE_KEY}" -n app-121
@@
-  kubectl apply -f checkout-service.yaml -n nr-115
+  kubectl apply -f checkout-service.yaml -n app-121
@@
-  kubectl wait --for=condition=ready pod -l app=checkout -n nr-115 --timeout=60s
+  kubectl wait --for=condition=ready pod -l app=checkout -n app-121 --timeout=60s
@@
-  kubectl get pods -n nr-115 -l app=checkout
+  kubectl get pods -n app-121 -l app=checkout
@@
-  kubectl apply -f traffic-generator.yaml -n nr-115
+  kubectl apply -f traffic-generator.yaml -n app-121
@@
-  kubectl wait --for=condition=ready pod -l app=traffic-generator -n nr-115 --timeout=60s
+  kubectl wait --for=condition=ready pod -l app=traffic-generator -n app-121 --timeout=60s
@@
-  kubectl get pods -n nr-115
+  kubectl get pods -n app-121
@@
-  if kubectl logs -n nr-115 -l app=traffic-generator --tail=-1 | grep -q "WITH promo_code"; then
+  if kubectl logs -n app-121 -l app=traffic-generator --tail=-1 | grep -q "WITH promo_code"; then
@@
-  if kubectl logs -n nr-115 -l app=traffic-generator --tail=-1 | grep -q "WITHOUT promo_code"; then
+  if kubectl logs -n app-121 -l app=traffic-generator --tail=-1 | grep -q "WITHOUT promo_code"; then
@@
-  if kubectl logs -n nr-115 -l app=checkout --tail=100 | grep -q "Processing checkout request"; then
+  if kubectl logs -n app-121 -l app=checkout --tail=100 | grep -q "Processing checkout request"; then
@@
-  kubectl delete -f traffic-generator.yaml -n nr-115
+  kubectl delete -f traffic-generator.yaml -n app-121
@@
-after_test: |
-  kubectl delete namespace nr-115 || true
+after_test: |
+  kubectl delete namespace app-121 || true
🧹 Nitpick comments (7)
holmes/plugins/toolsets/newrelic/newrelic.jinja2 (2)

39-41: Tighten guidance: add explicit time window; grammar; safe LIMIT example

Minor copy and query hygiene to prevent heavy queries and fix wording.

-        - ALWAYS include an embed, and don't include the raw results as plain text, for example << {"type": "traces-summary", "tool_name": "newrelic_execute_nrql_query", "random_key": "928js0l"} >>. "random_key" should always be replaced with the "random_key" from the tool's output.
-        - ALWAYS start by querying all fields using `SELECT * FROM DistributedTraceSummary`. We need as much fields as possible to visualize the traces to the user. However, the trade-off is that we might exceed the context size. In that case, if you need to narrow down your search, follow this strategy: First, select only the essential fields: trace.id, spanCount, root.entity.accountId, root.entity.guid, root.entity.name, root.span.name, timestamp, duration.ms. These are the absolute minimum fields required for the visualization. If that's still failing, add the `LIMIT` keyword to the query. `LIMIT` should always be the second option, we prefer to show the user as much traces as we can.
+        - ALWAYS include an embed, and don't include the raw results as plain text; for example: << {"type": "traces-summary", "tool_name": "newrelic_execute_nrql_query", "random_key": "928js0l"} >>. Replace "random_key" with the value returned by the tool.
+        - ALWAYS start by querying all fields using `SELECT * FROM DistributedTraceSummary SINCE 1 hour ago`. We need as many fields as possible to visualize the traces for the user. If this exceeds context, first select only the essential fields: `trace.id, spanCount, root.entity.accountId, root.entity.guid, root.entity.name, root.span.name, timestamp, duration.ms`. If that's still too large, add a conservative `LIMIT` (for example, `LIMIT 50`) as a last resort—we prefer to show the user as many traces as we can.

Note: The essential fields you listed are valid DistributedTraceSummary attributes. (docs.newrelic.com)


42-42: Fix typo: “even type” → “event type”

Also small punctuation polish.

- - If you query any other even type (like Span or Transaction), don't use any embeds - return the results as is.
+ - If you query any other event type (like Span or Transaction), don't use any embeds—return the results as is.
tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml (1)

42-44: Align message with actual sleep.

Echo says 45s but sleeps 20s.

-  echo "⏰ Letting traffic generator run for 45 seconds to generate requests"
-  sleep 20
+  echo "⏰ Letting traffic generator run for 20 seconds to generate requests"
+  sleep 20
tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml (2)

247-313: Harden the pod/container security context (Checkov CKV_K8S_20, CKV_K8S_23).

Run as non‑root, drop caps, disable privilege escalation, enable seccomp, and use read‑only root FS.

     spec:
+      securityContext:
+        runAsNonRoot: true
+        seccompProfile:
+          type: RuntimeDefault
       containers:
       - name: traffic-generator
         image: python:3.11-slim
+        securityContext:
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          runAsUser: 1000
+          runAsGroup: 1000
+          capabilities:
+            drop: ["ALL"]
         command: ["/bin/bash", "-c"]

131-137: Optional: avoid tracing the New Relic log POSTs.

Auto‑instrumenting requests will also create spans for NR log ingestion calls, adding noise. Consider suppressing instrumentation in NewRelicLogHandler.emit when posting logs.

If you want, I can draft a minimal suppression using the OpenTelemetry “suppress_instrumentation” context utility compatible with your pinned versions.

tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml (2)

260-327: Harden the checkout pod/container security context (Checkov CKV_K8S_20, CKV_K8S_23).

Mirror the same security hardening as the generator.

     spec:
+      securityContext:
+        runAsNonRoot: true
+        seccompProfile:
+          type: RuntimeDefault
       containers:
       - name: checkout
         image: python:3.11-slim
+        securityContext:
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          runAsUser: 1000
+          runAsGroup: 1000
+          capabilities:
+            drop: ["ALL"]
         command: ["/bin/bash", "-c"]

136-141: Optional: avoid tracing NR log POSTs from the app too.

Same consideration as the generator to reduce span noise.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9726c4 and 8cac7f7.

📒 Files selected for processing (5)
  • holmes/plugins/toolsets/newrelic/newrelic.jinja2 (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/toolsets.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/toolsets.yaml
🧰 Additional context used
📓 Path-based instructions (6)
tests/llm/fixtures/**/*.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

tests/llm/fixtures/**/*.yaml: Each LLM test must use a dedicated Kubernetes namespace 'app-' to prevent conflicts when running in parallel
All pod names in evals must be unique across tests; never reuse pod names

Files:

  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml
tests/llm/fixtures/**/*.{yaml,md,log,txt}

📄 CodeRabbit inference engine (CLAUDE.md)

Eval artifacts must be realistic and neutral: no obvious/fake logs, no filenames or resource names that hint at the problem, and no messages revealing simulation

Files:

  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml
tests/llm/**/*.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Always use Kubernetes Secrets for scripts in evals; do not embed scripts inline in manifests or ConfigMaps

Files:

  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml
tests/**

📄 CodeRabbit inference engine (CLAUDE.md)

Test layout should mirror the source structure under tests/

Files:

  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml
holmes/plugins/toolsets/**

📄 CodeRabbit inference engine (CLAUDE.md)

Toolsets must be organized under holmes/plugins/toolsets/ as either {name}.yaml files or directories

Files:

  • holmes/plugins/toolsets/newrelic/newrelic.jinja2
tests/llm/**/test_case.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Do not include toolset configuration in test_case.yaml; if runbooks are specified, entries must point to .md files in the same directory

Files:

  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
🪛 Checkov (3.2.334)
tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml

[medium] 233-313: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 233-313: Minimize the admission of root containers

(CKV_K8S_23)

tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml

[medium] 247-333: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 247-333: Minimize the admission of root containers

(CKV_K8S_23)

⏰ 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: Pre-commit checks
  • GitHub Check: llm_evals
🔇 Additional comments (4)
holmes/plugins/toolsets/newrelic/newrelic.jinja2 (2)

37-37: Fix invalid NRQL attribute on DistributedTraceSummary

root.span.eventType doesn’t exist on DistributedTraceSummary; this will yield empty results. Use an existence check on fields that do exist (or drop the filter entirely). The data dictionary lists root.entity.*, root.span.*, trace.id, spanCount, timestamp, duration.ms, but not root.span.eventType.

Apply:

-    - ALWAYS use the filter `WHERE root.span.eventType = 'Span'`
+    - Do not filter on `root.span.eventType` (it doesn't exist on DistributedTraceSummary). If you must sanity‑check root span presence, use `WHERE root.span.id IS NOT NULL` or omit this filter altogether.

Sources: New Relic attribute dictionary entries for DistributedTraceSummary showing available attributes (no root.span.eventType). (docs.newrelic.com)


39-39: Verify embed “type” and tool name match the code

Confirm that the consumer recognizes type: "traces-summary" and tool_name: "newrelic_execute_nrql_query"; there’s a risk of silent no‑ops if these identifiers don’t match your dispatcher.

tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml (1)

188-189: Cross‑file check: make sure test grep matches this log.

App logs “Processing checkout for user …”. The test has been updated to grep this exact string.

tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml (1)

20-20: Shared Tempo path verified — ../../shared/tempo.yaml resolves to tests/llm/fixtures/shared/tempo.yaml (file exists).

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

🧹 Nitpick comments (13)
tests/llm/fixtures/test_ask_holmes/114_checkout_latency_tracing_rebuild/checkout-service.yaml (5)

176-180: Ensure volumes item indentation is valid YAML.

Minor indentation nits here can also trigger “expected ':'” errors with strict linters.

Apply:

-        volumes:
-        - name: app
+        volumes:
+        - name: app
           secret:
             secretName: checkout-app

1-1: Remove scenario‑revealing comment.

Artifacts must be neutral; “Dummy SQL” hints at simulation.

-  # Simplified Checkout Service with Dummy SQL

70-93: Make latency deterministic; avoid “simulate” wording in code comments.

Random sleeps can cause flaky evals and “simulate” comments are non‑neutral. Use env‑configurable fixed delays and neutral comments.

-              # Simulate database query for shipping calculation
+              # Database query for shipping calculation (emulated latency)

-                  if promo_code:
-                      # Simulate slow query with promo_code
+                  if promo_code:
+                      # Slow path when promo code is used
                       query = "SELECT rate_per_kg, discount_percent FROM shipping_rates WHERE zone_id = ? AND promo_code = ? AND active = true"
                       db_span.set_attribute("db.statement", query)
-                      # print(f"[DB] Executing shipping rate query", flush=True)
-                      sleep_time = random.uniform(1.5, 3.5)
-                      time.sleep(sleep_time) # Simulate slow query
+                      slow_ms = int(os.environ.get("SLOW_QUERY_MS", "2500"))
+                      time.sleep(slow_ms / 1000.0)
                       shipping_rate = 4.5
                       discount = 15.0
                   else:
-                      # Simulate fast query without promo_code
+                      # Fast path without promo code
                       query = "SELECT rate_per_kg, discount_percent FROM shipping_rates WHERE zone_id = ? AND active = true"
                       db_span.set_attribute("db.statement", query)
-                      # print(f"[DB] Executing shipping rate query", flush=True)
-                      sleep_time = random.uniform(0.1, 0.2)
-                      time.sleep(sleep_time) # Simulate fast query
+                      fast_ms = int(os.environ.get("FAST_QUERY_MS", "150"))
+                      time.sleep(fast_ms / 1000.0)
                       shipping_rate = 5.0
                       discount = 0.0

Additionally, add these near the imports (already using os):

       from opentelemetry.instrumentation.flask import FlaskInstrumentor
+
+# Tunable latency via env (defaults used if not provided)

136-139: Pin dependencies for reproducibility.

Installing floating latest versions in-cluster risks future breakage.

Consider switching to a requirements file in the Secret and install with:

-            pip install flask opentelemetry-api opentelemetry-sdk \
-              opentelemetry-instrumentation-flask \
-              opentelemetry-exporter-otlp-proto-grpc && \
+            pip install --no-cache-dir -r /app/requirements.txt && \
             python /app/app.py

and add stringData.requirements.txt with pinned versions (or a constraints file).


160-168: Add a readinessProbe (startupProbe alone isn’t sufficient).

Ensures traffic only routes when the app is ready.

           startupProbe:
             httpGet:
               path: /health
               port: 8080
             initialDelaySeconds: 10
             periodSeconds: 5
             timeoutSeconds: 3
             successThreshold: 1
             failureThreshold: 24
+          readinessProbe:
+            httpGet:
+              path: /health
+              port: 8080
+            periodSeconds: 5
+            timeoutSeconds: 2
+            failureThreshold: 3
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /test_case.yaml (2)

72-85: Harden log checks to avoid false positives.

Grepping the last 100 lines may miss earlier entries on slower clusters. Consider a wider window or label selector per container.

Apply:

-  if kubectl logs -n "${TEST_NS}" -l app=traffic-generator --tail=100 | grep -q "WITH promo_code"; then
+  if kubectl logs -n "${TEST_NS}" -l app=traffic-generator --tail=1000 | grep -q "WITH promo_code"; then

Repeat similarly for WITHOUT promo_code.


118-121: Neutralize meta/mocked language in test logs.

Avoid phrases that reveal simulation (“so the ai won't cheat”).

-  # Delete Traffic generator so the ai won't cheat
+  # Delete traffic generator to stop background load before assertions
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /traffic-generator.yaml (3)

121-154: Add basic container securityContext (non-root, no privilege escalation).

Addresses CKV_K8S_20 and CKV_K8S_23.

       - name: traffic-generator
         image: python:3.11-slim
+        securityContext:
+          runAsNonRoot: true
+          runAsUser: 1000
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          capabilities:
+            drop: ["ALL"]

125-130: Pin dependency versions for determinism.

-          pip install requests && \
+          pip install requests==2.32.3 && \

12-12: Remove unused import.

-    from datetime import datetime
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /checkout-service.yaml (3)

130-176: Add container securityContext (non-root, no privilege escalation).

Same CKV findings as traffic generator.

       - name: checkout
         image: python:3.11-slim
+        securityContext:
+          runAsNonRoot: true
+          runAsUser: 1000
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          capabilities:
+            drop: ["ALL"]

136-139: Pin Python package versions to reduce flakiness.

-          pip install flask opentelemetry-api opentelemetry-sdk \
-            opentelemetry-instrumentation-flask \
-            opentelemetry-exporter-otlp-proto-grpc && \
+          pip install \
+            flask==3.0.3 \
+            opentelemetry-api==1.26.0 \
+            opentelemetry-sdk==1.26.0 \
+            opentelemetry-instrumentation-flask==0.47b0 \
+            opentelemetry-exporter-otlp-proto-grpc==1.26.0 && \

Adjust to the repo’s standard pin set if different.


55-55: Avoid logging PII-like identifiers in plain logs (even in tests).

Consider masking or truncating user_id.

-            print(f"[CHECKOUT] Processing checkout request for user {data.get('user_id', 'guest')}", flush=True)
+            print("[CHECKOUT] Processing checkout request", flush=True)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8cac7f7 and 8f54d41.

📒 Files selected for processing (5)
  • tests/llm/fixtures/test_ask_holmes/114_checkout_latency_tracing_rebuild/checkout-service.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /checkout-service.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /test_case.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /traffic-generator.yaml (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
tests/llm/**/toolsets.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

In evals, all toolset-specific configuration must be under a top-level 'config' field in toolsets.yaml; do not place toolset config directly at the top level

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml
{holmes/plugins/toolsets/**/*.yaml,tests/llm/**/toolsets.yaml}

📄 CodeRabbit inference engine (CLAUDE.md)

Valid top-level fields for toolset YAMLs are limited to: enabled, name, description, additional_instructions, prerequisites, tools, docs_url, icon_url, installation_instructions, config, url (MCP only)

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml
tests/llm/fixtures/**/*.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

tests/llm/fixtures/**/*.yaml: Each LLM test must use a dedicated Kubernetes namespace 'app-' to prevent conflicts when running in parallel
All pod names in evals must be unique across tests; never reuse pod names

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml
  • tests/llm/fixtures/test_ask_holmes/114_checkout_latency_tracing_rebuild/checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /traffic-generator.yaml
tests/llm/fixtures/**/*.{yaml,md,log,txt}

📄 CodeRabbit inference engine (CLAUDE.md)

Eval artifacts must be realistic and neutral: no obvious/fake logs, no filenames or resource names that hint at the problem, and no messages revealing simulation

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml
  • tests/llm/fixtures/test_ask_holmes/114_checkout_latency_tracing_rebuild/checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /traffic-generator.yaml
tests/llm/**/*.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Always use Kubernetes Secrets for scripts in evals; do not embed scripts inline in manifests or ConfigMaps

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml
  • tests/llm/fixtures/test_ask_holmes/114_checkout_latency_tracing_rebuild/checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /traffic-generator.yaml
tests/**

📄 CodeRabbit inference engine (CLAUDE.md)

Test layout should mirror the source structure under tests/

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml
  • tests/llm/fixtures/test_ask_holmes/114_checkout_latency_tracing_rebuild/checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /traffic-generator.yaml
tests/llm/**/test_case.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Do not include toolset configuration in test_case.yaml; if runbooks are specified, entries must point to .md files in the same directory

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /test_case.yaml
🧠 Learnings (4)
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to tests/llm/**/test_case.yaml : Do not include toolset configuration in test_case.yaml; if runbooks are specified, entries must point to .md files in the same directory

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to {holmes/plugins/toolsets/**/*.yaml,tests/llm/**/toolsets.yaml} : Valid top-level fields for toolset YAMLs are limited to: enabled, name, description, additional_instructions, prerequisites, tools, docs_url, icon_url, installation_instructions, config, url (MCP only)

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to tests/llm/**/toolsets.yaml : In evals, all toolset-specific configuration must be under a top-level 'config' field in toolsets.yaml; do not place toolset config directly at the top level

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml
📚 Learning: 2025-08-05T00:42:23.792Z
Learnt from: vishiy
PR: robusta-dev/holmesgpt#782
File: config.example.yaml:31-49
Timestamp: 2025-08-05T00:42:23.792Z
Learning: In robusta-dev/holmesgpt config.example.yaml, the azuremonitorlogs toolset configuration shows "enabled: true" as an example of how to enable the toolset, not as a default setting. The toolset is disabled by default and requires explicit enablement in user configurations.

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml
🪛 YAMLlint (1.37.1)
tests/llm/fixtures/test_ask_holmes/114_checkout_latency_tracing_rebuild/checkout-service.yaml

[error] 116-116: syntax error: could not find expected ':'

(syntax)

🪛 Checkov (3.2.334)
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /checkout-service.yaml

[medium] 116-180: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 116-180: Minimize the admission of root containers

(CKV_K8S_23)

tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /traffic-generator.yaml

[medium] 105-157: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 105-157: Minimize the admission of root containers

(CKV_K8S_23)

⏰ 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). (3)
  • GitHub Check: build (3.12)
  • GitHub Check: build (3.11)
  • GitHub Check: llm_evals
🔇 Additional comments (4)
tests/llm/fixtures/test_ask_holmes/114_checkout_latency_tracing_rebuild/checkout-service.yaml (2)

34-39: Verify OTLP endpoint aligns with the New Relic eval.

Endpoint points to Tempo (tempo.app-114…), while this PR is for New Relic evals. If Tempo is an intermediary, fine—otherwise update to the intended collector/ingest.

Would you confirm the expected path (Tempo → NR or direct NR OTLP)?


8-44: Good: script stored in a Secret and OTel Flask instrumentation.

Using a Secret for code and instrumenting Flask via OpenTelemetry align with the guidelines.

Please confirm no other manifests in this test embed scripts inline or via ConfigMaps.

tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /traffic-generator.yaml (1)

25-33: If tracing is re-enabled later, update OTLP endpoint to app-122 or make it configurable.

-#     endpoint="tempo.app-114.svc.cluster.local:4317",
+#     endpoint="tempo.app-122.svc.cluster.local:4317",

Or read from OTEL_EXPORTER_OTLP_ENDPOINT env var.

tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild /toolsets.yaml (1)

1-10: Approve — healthcheck is a supported grafana/tempo config key.

GrafanaConfig defines healthcheck (default "ready") and GrafanaTempoConfig inherits it; grafana_health_check uses config.healthcheck and the Tempo toolset additionally verifies the Tempo echo endpoint.
Locations: holmes/plugins/toolsets/grafana/common.py, holmes/plugins/toolsets/grafana/grafana_api.py, holmes/plugins/toolsets/grafana/toolset_grafana_tempo.py.

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

🧹 Nitpick comments (16)
tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/billing-service.yaml (2)

43-85: Synchronous log shipping can block on network; consider async buffering.

Current handler POSTs per log with 5s timeout. For higher rates, use a queue + background thread or batch sender. Fine for small evals, but worth a TODO.


151-157: Avoid reassigning tracer redundantly.

setup_telemetry already returns a tracer; the second get_tracer call is unnecessary.

-    tracer, logger = setup_telemetry("billing-atc", "billing-service")
+    tracer, logger = setup_telemetry("billing-atc", "billing-service")
@@
-    tracer = trace.get_tracer(__name__)
+    # tracer already set by setup_telemetry
tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/test_case.yaml (1)

25-26: Optional: add a post-deploy sanity curl to reduce flakes.

After waits, curl the Service once to ensure HTTP 200 before starting traffic.

 kubectl get pods -n app-123 -l app=billing-123
+kubectl run curl --rm -i -t --image=curlimages/curl:8.7.1 -n app-123 --restart=Never -- \
+  curl -sS http://billing-123.app-123.svc.cluster.local:8080/health || true

Also applies to: 35-35

tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/traffic-generator.yaml (2)

93-96: Avoid hard-coded namespace default in telemetry.

Mirror the change made in billing to not bake in nr-115.

-  ns = os.getenv("KUBERNETES_NAMESPACE") or os.getenv("K8S_NAMESPACE") or "nr-115"
+  ns = os.getenv("KUBERNETES_NAMESPACE") or os.getenv("K8S_NAMESPACE") or ""

212-223: Nit: Unused Flask instrumentation in generator requirements.

Generator doesn’t use Flask; you can drop opentelemetry-instrumentation-flask and Flask to slim the image.

-    opentelemetry-instrumentation-flask==0.41b0
-    Flask==2.3.3
tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml (1)

236-316: Harden the container security context.

Comply with baseline policies: non-root, no privilege escalation, drop caps, read-only FS.

       containers:
       - name: traffic-generator
         image: python:3.11-slim
+        securityContext:
+          runAsNonRoot: true
+          runAsUser: 10001
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          capabilities:
+            drop: ["ALL"]
@@
     spec:
+      securityContext:
+        fsGroup: 10001
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml (1)

9-13: Template EU flag from env with a safe default.

Current inline comment suggests env usage but the value is hardcoded.

   newrelic:
     enabled: true
     config:
       nr_account_id: "{{env.NEW_RELIC_ACCOUNT_ID}}"
       nr_api_key: "{{env.NEW_RELIC_API_KEY}}"
-      is_eu_datacenter: false # set "{{env.NEW_RELIC_IS_EU}}" with true to use eu
+      is_eu_datacenter: "{{ env.NEW_RELIC_IS_EU | default(false) }}"
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml (1)

45-47: Align cleanup to the namespace variable.

-after_test: |
-  kubectl delete namespace nr-114 || true
+after_test: |
+  kubectl delete namespace "${NS:-app-122}" || true
tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml (2)

44-46: Comment/sleep mismatch.

Message says 45s, code sleeps 20s. Align to avoid flakiness.

-  echo "⏰ Letting traffic generator run for 45 seconds to generate requests"
-  sleep 20
+  echo "⏰ Letting traffic generator run for 45 seconds to generate requests"
+  sleep 45

73-75: Cleanup should delete the chosen namespace.

-after_test: |
-  kubectl delete namespace nr-115 || true
+after_test: |
+  kubectl delete namespace "${NS:-app-121}" || true
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/payment-service.yaml (2)

3-6: Avoid hardcoding namespace in manifests applied with -n.

Drop metadata.namespace for portability and reusability (the test sets -n).

 metadata:
   name: payment-app
-  namespace: nr-114

312-327: Add container and pod security context.

Harden according to baseline policies.

         startupProbe:
           httpGet:
             path: /health
             port: 8080
           initialDelaySeconds: 60    # allow time for pip install
           periodSeconds: 5
           timeoutSeconds: 3
           successThreshold: 1
           failureThreshold: 60       # generous budget for slow networks
         resources:
+        securityContext:
+          runAsNonRoot: true
+          runAsUser: 10001
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          capabilities:
+            drop: ["ALL"]
           requests:
             memory: "128Mi"
             cpu: "50m"
           limits:
             memory: "256Mi"
             cpu: "200m"
@@
     spec:
+      securityContext:
+        fsGroup: 10001
tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml (1)

265-332: Harden the container security context.

Apply non-root, no privilege escalation, drop caps, read-only FS.

       - name: checkout
         image: python:3.11-slim
         command: ["/bin/bash", "-c"]
         args:
           - |
             pip install -r /app/requirements.txt && \
             python /app/app.py
+        securityContext:
+          runAsNonRoot: true
+          runAsUser: 10001
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          capabilities:
+            drop: ["ALL"]
@@
     spec:
+      securityContext:
+        fsGroup: 10001
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/traffic-generator.yaml (2)

243-250: Startup probe signals ready before dependencies install.

You touch /tmp/ready before pip install, causing premature success. Move touch after pip.

-          set -e
-          touch /tmp/ready && \
-          python -m pip install --no-cache-dir --disable-pip-version-check -r /app/requirements.txt && \
+          set -e
+          python -m pip install --no-cache-dir --disable-pip-version-check -r /app/requirements.txt && \
+          touch /tmp/ready && \
           python /app/app.py

240-307: Harden the container and pod security context.

Align with baseline policies.

       - name: traffic-generator
         image: python:3.11-slim
         command: ["/bin/bash", "-c"]
+        securityContext:
+          runAsNonRoot: true
+          runAsUser: 10001
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          capabilities:
+            drop: ["ALL"]
@@
     spec:
+      securityContext:
+        fsGroup: 10001
holmes/plugins/toolsets/newrelic/newrelic.jinja2 (1)

31-32: Tighten guidance and fix typos (“latnecy” → “latency”).

Current phrasing is awkward and has a typo.

- - When investigating a trace also look at attributes
- - ***When investigating latency ALWAYS look to deliver the specific component or attribute in the span causing significant latnecy*** your investigation is not complete without this
+ - When investigating a trace, also inspect relevant attributes.
+ - ***When investigating latency, identify the specific component or span attribute contributing the most latency***; the investigation isn’t complete without this.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f54d41 and 55cfeae.

📒 Files selected for processing (13)
  • holmes/plugins/prompts/_fetch_logs.jinja2 (2 hunks)
  • holmes/plugins/toolsets/newrelic/newrelic.jinja2 (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/payment-service.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/traffic-generator.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/billing-service.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/test_case.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/toolsets.yaml (1 hunks)
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/traffic-generator.yaml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/toolsets.yaml
🧰 Additional context used
📓 Path-based instructions (9)
tests/llm/**/test_case.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Do not include toolset configuration in test_case.yaml; if runbooks are specified, entries must point to .md files in the same directory

Files:

  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
tests/llm/fixtures/**/*.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

tests/llm/fixtures/**/*.yaml: Each LLM test must use a dedicated Kubernetes namespace 'app-' to prevent conflicts when running in parallel
All pod names in evals must be unique across tests; never reuse pod names

Files:

  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/payment-service.yaml
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/billing-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml
tests/llm/fixtures/**/*.{yaml,md,log,txt}

📄 CodeRabbit inference engine (CLAUDE.md)

Eval artifacts must be realistic and neutral: no obvious/fake logs, no filenames or resource names that hint at the problem, and no messages revealing simulation

Files:

  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/payment-service.yaml
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/billing-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml
tests/llm/**/*.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Always use Kubernetes Secrets for scripts in evals; do not embed scripts inline in manifests or ConfigMaps

Files:

  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/payment-service.yaml
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/billing-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml
tests/**

📄 CodeRabbit inference engine (CLAUDE.md)

Test layout should mirror the source structure under tests/

Files:

  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/payment-service.yaml
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml
  • tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/billing-service.yaml
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/traffic-generator.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml
  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml
holmes/plugins/prompts/**/*.jinja2

📄 CodeRabbit inference engine (CLAUDE.md)

Prompts must be stored as .jinja2 templates under holmes/plugins/prompts/{name}.jinja2

Files:

  • holmes/plugins/prompts/_fetch_logs.jinja2
tests/llm/**/toolsets.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

In evals, all toolset-specific configuration must be under a top-level 'config' field in toolsets.yaml; do not place toolset config directly at the top level

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml
{holmes/plugins/toolsets/**/*.yaml,tests/llm/**/toolsets.yaml}

📄 CodeRabbit inference engine (CLAUDE.md)

Valid top-level fields for toolset YAMLs are limited to: enabled, name, description, additional_instructions, prerequisites, tools, docs_url, icon_url, installation_instructions, config, url (MCP only)

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml
holmes/plugins/toolsets/**

📄 CodeRabbit inference engine (CLAUDE.md)

Toolsets must be organized under holmes/plugins/toolsets/ as either {name}.yaml files or directories

Files:

  • holmes/plugins/toolsets/newrelic/newrelic.jinja2
🧠 Learnings (7)
📚 Learning: 2025-05-15T05:13:43.169Z
Learnt from: nherment
PR: robusta-dev/holmesgpt#408
File: holmes/plugins/toolsets/kubernetes_logs.py:90-97
Timestamp: 2025-05-15T05:13:43.169Z
Learning: In the Kubernetes logs toolset for Holmes, both current and previous logs are intentionally fetched and combined for each pod, even though this requires more API calls. This design ensures all logs are captured even when pods restart but retain their name, providing complete diagnostic information.

Applied to files:

  • holmes/plugins/prompts/_fetch_logs.jinja2
📚 Learning: 2025-05-15T05:14:06.519Z
Learnt from: nherment
PR: robusta-dev/holmesgpt#408
File: holmes/plugins/toolsets/kubernetes_logs.py:100-102
Timestamp: 2025-05-15T05:14:06.519Z
Learning: The `fetch_logs` method in KubernetesLogsToolset is designed to apply the limit parameter after filtering and combining both current and previous logs, rather than using the API's tail_lines parameter, to ensure the limit applies to the final combined log set.

Applied to files:

  • holmes/plugins/prompts/_fetch_logs.jinja2
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to tests/llm/fixtures/**/*.yaml : Each LLM test must use a dedicated Kubernetes namespace 'app-<testid>' to prevent conflicts when running in parallel

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to {holmes/plugins/toolsets/**/*.yaml,tests/llm/**/toolsets.yaml} : Valid top-level fields for toolset YAMLs are limited to: enabled, name, description, additional_instructions, prerequisites, tools, docs_url, icon_url, installation_instructions, config, url (MCP only)

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to tests/llm/**/test_case.yaml : Do not include toolset configuration in test_case.yaml; if runbooks are specified, entries must point to .md files in the same directory

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to tests/llm/**/toolsets.yaml : In evals, all toolset-specific configuration must be under a top-level 'config' field in toolsets.yaml; do not place toolset config directly at the top level

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml
📚 Learning: 2025-08-05T00:42:23.792Z
Learnt from: vishiy
PR: robusta-dev/holmesgpt#782
File: config.example.yaml:31-49
Timestamp: 2025-08-05T00:42:23.792Z
Learning: In robusta-dev/holmesgpt config.example.yaml, the azuremonitorlogs toolset configuration shows "enabled: true" as an example of how to enable the toolset, not as a default setting. The toolset is disabled by default and requires explicit enablement in user configurations.

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/toolsets.yaml
🪛 Checkov (3.2.334)
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/payment-service.yaml

[medium] 244-333: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 244-333: Minimize the admission of root containers

(CKV_K8S_23)

tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/traffic-generator.yaml

[medium] 225-310: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 225-310: Minimize the admission of root containers

(CKV_K8S_23)

tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/billing-service.yaml

[medium] 259-348: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 259-348: Minimize the admission of root containers

(CKV_K8S_23)

tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/traffic-generator.yaml

[medium] 225-310: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 225-310: Minimize the admission of root containers

(CKV_K8S_23)

tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml

[medium] 251-337: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 251-337: Minimize the admission of root containers

(CKV_K8S_23)

tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml

[medium] 236-316: Containers should not run with allowPrivilegeEscalation

(CKV_K8S_20)


[medium] 236-316: Minimize the admission of root containers

(CKV_K8S_23)

🔇 Additional comments (12)
tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/billing-service.yaml (1)

1-7: Good: scripts are stored in a Secret, not inline manifests/ConfigMaps.

Complies with tests/llm/**/*.yaml guideline to use Secrets for scripts.

Please confirm other fixtures in this PR also use Secrets for embedded scripts.

tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/test_case.yaml (1)

4-7: Expectation wording is precise and testable. LGTM.

Keeps the model from passing by only mentioning promo codes. Good.

tests/llm/fixtures/test_ask_holmes/123_new_relic_checkout_errors_tracing/traffic-generator.yaml (1)

1-7: Good: scripts are stored in a Secret.

Compliant with evals guideline.

holmes/plugins/prompts/_fetch_logs.jinja2 (1)

70-71: OK to list ‘newrelic’ as an option here.

Naming is consistent with tests/llm toolsets (“newrelic”). No change needed.

tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/traffic-generator.yaml (2)

36-40: Fix OTLP gRPC endpoint: use host:port, not https://.

gRPC exporter expects host:port. The https scheme will break exports.

-        otlp = "https://otlp.eu01.nr-data.net:4317" if region == "eu" else "https://otlp.nr-data.net:4317"
+        otlp = "otlp.eu01.nr-data.net:4317" if region == "eu" else "otlp.nr-data.net:4317"
#!/bin/bash
# Find any remaining incorrect gRPC endpoints across the repo
rg -nP 'https://otlp\.[\w.-]+:4317' -C2

148-159: Avoid hardcoded namespace in CHECKOUT_URL.

Build service DNS from the pod namespace (Downward API) so this works in app-121 and future tests.

-    import time, random
+    import os, time, random
@@
-    CHECKOUT_URL = "http://checkout.nr-115.svc.cluster.local:8080/checkout"
+    NS = os.getenv("KUBERNETES_NAMESPACE", "default")
+    CHECKOUT_URL = f"http://checkout.{NS}.svc.cluster.local:8080/checkout"
tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/test_case.yaml (2)

17-25: Remove duplicate namespace creation and switch to app-121.

Second create is redundant; also adopt required namespace naming.

-before_test: |
+before_test: |
   [ -n "${NEW_RELIC_ACCOUNT_ID:-}" ] && [ -n "${NEW_RELIC_API_KEY:-}" ] && [ -n "${NEW_RELIC_LICENSE_KEY:-}" ] || { for v in NEW_RELIC_ACCOUNT_ID NEW_RELIC_API_KEY NEW_RELIC_LICENSE_KEY; do [ -n "${!v:-}" ] || echo "Missing env var: $v"; done; exit 1; }
-
-  echo "🚀 Setting up test 115 - Creating namespace nr-115"
-  kubectl create namespace nr-115 || true
-  echo "✅ Namespace nr-115 created successfully!"
+  NS=app-121
+  echo "🚀 Setting up test 121 - Creating namespace ${NS}"
+  kubectl create namespace "${NS}" || true
+  echo "✅ Namespace ${NS} created successfully!"
@@
-  kubectl apply -f ../../shared/tempo.yaml -n nr-115
+  kubectl apply -f ../../shared/tempo.yaml -n "${NS}"
-
-  kubectl create namespace nr-115
-  kubectl create secret generic newrelickey --from-literal=key="${NEW_RELIC_LICENSE_KEY}" -n nr-115
+  kubectl create secret generic newrelickey --from-literal=key="${NEW_RELIC_LICENSE_KEY}" -n "${NS}"

62-66: Fix log assertion to match actual app log line.

Use the correct message to avoid false failures.

-  if kubectl logs -n nr-115 -l app=checkout --tail=100 | grep -q "Processing checkout request"; then
+  if kubectl logs -n "${NS}" -l app=checkout --tail=100 | grep -q "Processing checkout for user"; then
tests/llm/fixtures/test_ask_holmes/121_new_relic_checkout_errors_tracing/checkout-service.yaml (1)

37-41: Fix OTLP gRPC endpoint: use host:port, not https://.

Same gRPC issue as noted before.

-        otlp = "https://otlp.eu01.nr-data.net:4317" if region == "eu" else "https://otlp.nr-data.net:4317"
+        otlp = "otlp.eu01.nr-data.net:4317" if region == "eu" else "otlp.nr-data.net:4317"
holmes/plugins/toolsets/newrelic/newrelic.jinja2 (3)

44-44: Typo: “even type” → “event type”.

Same nit was raised previously; applying it here too.

- - If you query any other even type (like Span or Transaction), don't use any embeds - return the results as is.
+ - If you query any other event type (like Span or Transaction), don't use any embeds—return the results as is.

35-35: Replace Prometheus tool with NRQL tool in New Relic example

holmes/plugins/toolsets/newrelic/newrelic.jinja2 (line 35) references execute_prometheus_range_query — replace it with the NRQL execution tool used in this toolset (e.g. newrelic_execute_nrql_query). I couldn't verify canonical names in the sandbox (search produced no definitive matches); confirm the embed "type" and tool_name across the repo and update the example.

- - You always need to embed the partial result in your response. Include the "tool_name" and "random_key". For example: << {"type": "newrelicql", "tool_name": "execute_prometheus_range_query", "random_key": "92jf2hf"} >>
+ - You always need to embed the partial result in your response. Include the "tool_name" and "random_key". For example: << {"type": "newrelicql", "tool_name": "newrelic_execute_nrql_query", "random_key": "92jf2hf"} >>

42-42: Minor grammar fix & DistributedTraceSummary fields verified

Grammar tweak below; the listed fields are present on DistributedTraceSummary per New Relic's attribute dictionary. (docs.newrelic.com)

-        - ALWAYS start by querying all fields using `SELECT * FROM DistributedTraceSummary`. We need as much fields as possible to visualize the traces to the user. However, the trade-off is that we might exceed the context size. In that case, if you need to narrow down your search, follow this strategy: First, select only the essential fields: trace.id, spanCount, root.entity.accountId, root.entity.guid, root.entity.name, root.span.name, timestamp, duration.ms. These are the absolute minimum fields required for the visualization. If that's still failing, add the `LIMIT` keyword to the query. `LIMIT` should always be the second option, we prefer to show the user as much traces as we can.
+        - ALWAYS start by querying all fields using `SELECT * FROM DistributedTraceSummary`. We need as many fields as possible to visualize traces for the user. However, you might exceed context size. If you need to narrow the result, first select only these essential fields: trace.id, spanCount, root.entity.accountId, root.entity.guid, root.entity.name, root.span.name, timestamp, duration.ms. If that still fails, add `LIMIT` (this is a secondary option).

Comment thread holmes/plugins/prompts/_fetch_logs.jinja2
Comment thread holmes/plugins/toolsets/newrelic/newrelic.jinja2
nherment
nherment previously approved these changes Sep 22, 2025
@Avi-Robusta
Avi-Robusta enabled auto-merge (squash) September 22, 2025 08:23

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

🧹 Nitpick comments (2)
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml (2)

15-16: Harden the setup script with strict mode.

Fail fast on errors for reproducible test runs.

Apply this diff:

 before_test: |
+  set -Eeuo pipefail
   [ -n "${NEW_RELIC_ACCOUNT_ID:-}" ] && [ -n "${NEW_RELIC_API_KEY:-}" ] && [ -n "${NEW_RELIC_LICENSE_KEY:-}" ] || { for v in NEW_RELIC_ACCOUNT_ID NEW_RELIC_API_KEY NEW_RELIC_LICENSE_KEY; do [ -n "${!v:-}" ] || echo "Missing env var: $v"; done; exit 1; }

45-46: Use the same app-122 namespace in cleanup.

Define NS locally to avoid drift between blocks.

Apply this diff:

 after_test: |
-  kubectl delete namespace nr-114 || true
+  NS=app-122
+  kubectl delete namespace "${NS}" || true
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dbcfec3 and 8b056ca.

📒 Files selected for processing (1)
  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
tests/llm/**/test_case.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Do not include toolset configuration in test_case.yaml; if runbooks are specified, entries must point to .md files in the same directory

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
tests/llm/fixtures/**/*.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

tests/llm/fixtures/**/*.yaml: Each LLM test must use a dedicated Kubernetes namespace 'app-' to prevent conflicts when running in parallel
All pod names in evals must be unique across tests; never reuse pod names

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
tests/llm/fixtures/**/*.{yaml,md,log,txt}

📄 CodeRabbit inference engine (CLAUDE.md)

Eval artifacts must be realistic and neutral: no obvious/fake logs, no filenames or resource names that hint at the problem, and no messages revealing simulation

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
tests/llm/**/*.yaml

📄 CodeRabbit inference engine (CLAUDE.md)

Always use Kubernetes Secrets for scripts in evals; do not embed scripts inline in manifests or ConfigMaps

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
tests/**

📄 CodeRabbit inference engine (CLAUDE.md)

Test layout should mirror the source structure under tests/

Files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
🧠 Learnings (1)
📚 Learning: 2025-09-15T07:09:16.052Z
Learnt from: CR
PR: robusta-dev/holmesgpt#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T07:09:16.052Z
Learning: Applies to tests/llm/fixtures/**/*.yaml : Each LLM test must use a dedicated Kubernetes namespace 'app-<testid>' to prevent conflicts when running in parallel

Applied to files:

  • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml
⏰ 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: Pre-commit checks
  • GitHub Check: llm_evals
🔇 Additional comments (4)
tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml (4)

4-7: Expected-output criteria look good.

Clear and testable acceptance rules.


1-3: Use the mandated per-test namespace in the user prompt (app-122).

Update the prompt to match the required 'app-' convention for test 122.

Apply this diff:

 user_prompt:
-- "The payment service in namespace nr-114 is experiencing high latency. Investigate why."
+- "The payment service in namespace app-122 is experiencing high latency. Investigate why."

15-44: Make namespace configurable (app-122) throughout setup and fix the sleep message.

Align with guidelines and keep logs truthful.

Apply this diff:

 before_test: |
-  [ -n "${NEW_RELIC_ACCOUNT_ID:-}" ] && [ -n "${NEW_RELIC_API_KEY:-}" ] && [ -n "${NEW_RELIC_LICENSE_KEY:-}" ] || { for v in NEW_RELIC_ACCOUNT_ID NEW_RELIC_API_KEY NEW_RELIC_LICENSE_KEY; do [ -n "${!v:-}" ] || echo "Missing env var: $v"; done; exit 1; }
-  echo "🚀 Setting up test 114 - Creating namespace nr-114"
-  kubectl create namespace nr-114 || true
-  kubectl create secret generic newrelickey --from-literal=key="${NEW_RELIC_LICENSE_KEY}" -n nr-114
-  echo "✅ Namespace nr-114 created successfully!"
+  [ -n "${NEW_RELIC_ACCOUNT_ID:-}" ] && [ -n "${NEW_RELIC_API_KEY:-}" ] && [ -n "${NEW_RELIC_LICENSE_KEY:-}" ] || { for v in NEW_RELIC_ACCOUNT_ID NEW_RELIC_API_KEY NEW_RELIC_LICENSE_KEY; do [ -n "${!v:-}" ] || echo "Missing env var: $v"; done; exit 1; }
+  NS=app-122
+  echo "🚀 Setting up test 122 - Creating namespace ${NS}"
+  kubectl create namespace "${NS}" || true
+  kubectl create secret generic newrelickey --from-literal=key="${NEW_RELIC_LICENSE_KEY}" -n "${NS}"
+  echo "✅ Namespace ${NS} created successfully!"
@@
-  kubectl apply -f payment-service.yaml -n nr-114
+  kubectl apply -f payment-service.yaml -n "${NS}"
@@
-  kubectl wait --for=condition=ready pod -l app=payment -n nr-114 --timeout=60s
+  kubectl wait --for=condition=ready pod -l app=payment -n "${NS}" --timeout=60s
@@
-  kubectl get pods -n nr-114 -l app=payment
+  kubectl get pods -n "${NS}" -l app=payment
@@
-  kubectl apply -f traffic-generator.yaml -n nr-114
+  kubectl apply -f traffic-generator.yaml -n "${NS}"
@@
-  kubectl wait --for=condition=ready pod -l app=traffic-generator -n nr-114 --timeout=60s
+  kubectl wait --for=condition=ready pod -l app=traffic-generator -n "${NS}" --timeout=60s
@@
-  kubectl get pods -n nr-114
+  kubectl get pods -n "${NS}"
@@
-  echo "⏰ Letting traffic generator run for 20 seconds to generate requests"
-  sleep 60
+  echo "⏰ Letting traffic generator run for 60 seconds to generate requests"
+  sleep 60

1-46: Fix namespace and resource-name collisions in test 122

  • Replace hard-coded namespace "nr-114" → "app-122" (dedicated namespace) in:

    • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/test_case.yaml (lines 2,17–20,23,26,29,32,35,38,46)
    • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/payment-service.yaml (lines 5,94,248,338)
    • tests/llm/fixtures/test_ask_holmes/122_new_relic_checkout_latency_tracing_rebuild/traffic-generator.yaml (lines 5,94,152,153,229)
  • Update hard-coded FQDNs: payment.nr-114.svc.cluster.local → payment.app-122.svc.cluster.local (traffic-generator.yaml:152–153).

  • Make metadata.name values test-unique (add suffix "-122" or similar) for:

    • payment-app, payment (x2) in payment-service.yaml
    • traffic-generator-app, traffic-generator in traffic-generator.yaml
  • Fix setup messaging: change "Setting up test 114" → "Setting up test 122" in test_case.yaml.

  • Re-run the duplicate-name scan after changes — current scan shows cross-test duplicates for "payment" and "traffic-generator" (must be resolved before parallel runs).

@Avi-Robusta
Avi-Robusta merged commit 85ce5b3 into master Sep 22, 2025
7 checks passed
@Avi-Robusta
Avi-Robusta deleted the evals-newrelic branch September 22, 2025 09:07
kylehounslow pushed a commit to kylehounslow/holmesgpt that referenced this pull request Sep 23, 2025
Co-authored-by: Tomer Keshet <tomer@robusta.dev>
Co-authored-by: mershal <shahal@robusta.dev>
Co-authored-by: Robusta Runner <aantny@gmail.com>
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.

6 participants