Skip to content

Conversation

@arikalon1
Copy link
Contributor

No description provided.

@coderabbitai
Copy link

coderabbitai bot commented Oct 29, 2025

Walkthrough

Adds kubectl-based CRD inspection features (new playbook actions and implementation), kubectl installation and Release.key handling in the Docker image, Helm values and RBAC updates, a new KUBECTL_CMD_TIMEOUT_SEC env var, and both user-facing and internal CRD documentation.

Changes

Cohort / File(s) Change Summary
Docker / Runtime
Dockerfile
Move Release.key retrieval earlier in builder, reintroduce ENV_TYPE=DEV later in builder; copy Release.key into final stage, add Kubernetes apt keyring/source steps, install kubectl, add apt-transport-https and gnupg2 to final-stage APT packages, perform cleanup; CMD unchanged.
Configuration
helm/robusta/values.yaml, src/robusta/core/model/env_vars.py
values.yaml: add five new lightActions: kubectl_describe, fetch_resource_yaml, fetch_resource_events, fetch_crds, fetch_cr_instances. env_vars.py: add KUBECTL_CMD_TIMEOUT_SEC (int, default 180).
Documentation (site)
docs/index.rst, docs/setup-robusta/crds.rst
Add docs/setup-robusta/crds.rst and register it in the Robusta Pro Features toctree; document CRD monitoring, prerequisites, Helm configuration snippets, automation, and troubleshooting.
Documentation (internal API)
src/robusta/core/playbooks/internal/CRD_API_DOCUMENTATION.md
New internal documentation describing the kubectl-based CRD actions, parameters, response block types, examples, error handling, usage scenarios, and limitations.
CRD Actions Implementation
src/robusta/core/playbooks/internal/crds.py
New module implementing run_kubectl_command() and five actions (kubectl_describe, fetch_resource_yaml, fetch_resource_events, fetch_crds, fetch_cr_instances); constructs kubectl commands with timeout, parses outputs into File/Table/Json/Markdown Blocks, attaches Findings, and raises ActionException on failures.
RBAC / Helm templates
helm/robusta/templates/runner-service-account.yaml
Add ClusterRole rule granting list and get on customresourcedefinitions in the apiextensions.k8s.io API group.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Event as Execution Event
    participant Runner as Robusta Runner
    participant Action as CRD Action
    participant Kubectl as kubectl (subprocess)
    participant Output as Finding / Block

    Event->>Runner: trigger action (params)
    Runner->>Action: invoke handler
    Action->>Action: build kubectl args (include timeout)
    Action->>Kubectl: run command
    alt success
        Kubectl-->>Action: stdout
        Action->>Action: parse & format into Block(s)
        Action->>Output: create Finding & attach Block
        Output-->>Runner: enriched event
    else failure / timeout
        Kubectl-->>Action: stderr / exit code
        Action->>Runner: raise ActionException (error message)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • Areas to focus on:
    • src/robusta/core/playbooks/internal/crds.py — command construction, timeout handling, parsing logic, field-path extraction, and error/exception messages.
    • Dockerfile — Release.key handling, apt keyring/source steps, and ensuring no sensitive artifacts remain in final image.
    • helm/robusta/templates/runner-service-account.yaml & helm/robusta/values.yaml — RBAC scope correctness and values alignment with new actions.
    • src/robusta/core/model/env_vars.py — environment parsing and default behavior for timeout.

Suggested reviewers

  • moshemorad
  • RoiGlinik
  • pavangudiwada

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description Check ❓ Inconclusive No pull request description was provided by the author. Without a description, it is impossible to evaluate whether the author intended to relate the PR to the changeset or whether the PR explains the reasoning behind the changes. The absence of a description makes it impossible to determine conclusively whether the check should pass or fail based on the evaluation criteria provided. Consider adding a pull request description that explains the purpose, motivation, and high-level approach of the CRDs backend support feature. This will help reviewers understand the context and ensure the PR description relates to the changeset.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "Backend support for CRDs visualization" accurately reflects the core changes in the PR. The changeset introduces a comprehensive set of backend features for handling Custom Resource Definitions, including a new Python module implementing kubectl-based CRD inspection actions (kubectl_describe, fetch_resource_yaml, fetch_resource_events, fetch_crds, fetch_cr_instances), updated Helm configuration to expose these actions, RBAC permissions for CRD operations, Docker image updates with kubectl, and supporting documentation. The title is concise, specific, and clearly communicates the primary objective of the changes.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch crds-support

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae28640 and 37dc619.

📒 Files selected for processing (2)
  • Dockerfile (3 hunks)
  • src/robusta/core/playbooks/internal/crds.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/robusta/core/playbooks/internal/crds.py (8)
src/robusta/core/reporting/consts.py (1)
  • SlackAnnotations (80-82)
src/robusta/core/playbooks/common.py (1)
  • get_resource_events_table (18-79)
src/robusta/core/model/base_params.py (1)
  • ActionParams (60-71)
src/robusta/core/playbooks/actions_registry.py (1)
  • action (16-21)
src/robusta/core/model/events.py (2)
  • ExecutionBaseEvent (49-175)
  • add_finding (129-138)
src/robusta/core/reporting/blocks.py (2)
  • FileBlock (72-133)
  • JsonBlock (303-314)
src/robusta/core/reporting/base.py (2)
  • Finding (248-406)
  • EnrichmentType (115-126)
src/robusta/utils/error_codes.py (2)
  • ActionException (42-47)
  • ErrorCodes (5-40)
🪛 Ruff (0.14.2)
src/robusta/core/playbooks/internal/crds.py

20-20: subprocess call: check for execution of untrusted input

(S603)


27-27: Consider moving this statement to an else block

(TRY300)


35-35: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


36-36: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


39-39: Use raise without specifying exception name

Remove exception name

(TRY201)

⏰ 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: run_tests
  • GitHub Check: run_tests
🔇 Additional comments (2)
src/robusta/core/playbooks/internal/crds.py (2)

1-15: Imports look good.

The import path issues and unused imports flagged in previous reviews have been correctly addressed.


258-322: Well-designed field extraction with JSONPath-style filtering.

The field extraction logic correctly handles both simple dot notation and JSONPath-style array filtering. The regex pattern and traversal logic are sound.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (9)
src/robusta/core/model/env_vars.py (1)

143-145: Expose timeout looks good; add docs and minor style nit.

Keep default 180; please document how to set KUBECTL_CMD_TIMEOUT_SEC in CRDs docs and consider spacing for consistency.

docs/setup-robusta/crds.rst (1)

86-96: Add note on kubectl timeout configuration.

Document KUBECTL_CMD_TIMEOUT_SEC so operators can tune long-running CR listings.

Example:

.. note::
   You can control kubectl action timeouts via the KUBECTL_CMD_TIMEOUT_SEC environment variable (default: 180 seconds).
src/robusta/core/playbooks/internal/CRD_API_DOCUMENTATION.md (4)

39-51: Specify a language for fenced code blocks.

Add a language to this fenced block to pass MD040.

-```
+```text
 File: production_deployment_nginx-deployment_describe.txt
 ---
 Name:                   nginx-deployment
 ...

75-89: Use yaml language for YAML examples.

Improves syntax highlighting and lints cleanly.

-```
+```yaml
 File: default_configmap_app-config.yaml
 ---
 apiVersion: v1
 ...

115-121: Surround tables with blank lines.

Add a blank line before and after to satisfy MD058.

-#### Example Response
-| Type | Reason | Age | From | Message |
+#### Example Response
+
+| Type | Reason | Age | From | Message |
 |------|--------|-----|------|---------|
 ...
+

191-196: Surround the second table with blank lines and set header context.

Keeps consistent formatting and passes MD058.

-**Table Summary:**
-| Kind | API Version | Scope | Plural |
+**Table Summary:**
+
+| Kind | API Version | Scope | Plural |
 |------|------------|-------|--------|
 ...
+
src/robusta/core/playbooks/internal/crds.py (3)

116-176: Use modern Event fields and show a precise timestamp instead of date-only "Age".

events.k8s.io/v1 uses reportingController/reportingInstance; source is deprecated. Show lastTimestamp/eventTime ISO or compute relative if desired.

-            headers = ["Type", "Reason", "Age", "From", "Message"]
+            headers = ["Type", "Reason", "Time", "From", "Message"]
@@
-                last_timestamp = item.get("lastTimestamp") or item.get("eventTime", "")
-                age = last_timestamp.split("T")[0] if last_timestamp else "Unknown"
+                last_timestamp = item.get("lastTimestamp") or item.get("eventTime") or item.get("firstTimestamp", "")
+                time_str = last_timestamp or "Unknown"
@@
-                source = item.get("source", {})
-                from_str = source.get("component", "Unknown")
-                if source.get("host"):
-                    from_str += f" ({source.get('host')})"
+                # Prefer modern fields, fallback to deprecated 'source'
+                reporting_controller = item.get("reportingController")
+                reporting_instance = item.get("reportingInstance")
+                if reporting_controller:
+                    from_str = reporting_controller
+                    if reporting_instance:
+                        from_str += f" ({reporting_instance})"
+                else:
+                    source = item.get("source", {}) or item.get("deprecatedSource", {})
+                    from_str = source.get("component", "Unknown")
+                    if source.get("host"):
+                        from_str += f" ({source.get('host')})"
@@
-                rows.append([event_type, reason, age, from_str, message])
+                rows.append([event_type, reason, time_str, from_str, message])
@@
-    except Exception:
+    except ActionException:
+        raise
+    except Exception as e:
         msg = f"Error running fetch_resource_events for {params}"
         logging.exception(msg)
-        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, msg)
+        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, msg) from e

179-242: Minor cleanups: remove unused variable and chain exception.

Keep exception variable used and re-raise with cause.

-    except Exception as e:
-        msg = "Error running fetch_crds"
-        logging.exception(msg)
-        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, msg)
+    except ActionException:
+        raise
+    except Exception as e:
+        msg = "Error running fetch_crds"
+        logging.exception(msg)
+        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, msg) from e

249-310: Preserve ActionException; optional: normalize kind and chain cause.

Prevents double-wrapping and improves robustness for mixed-case kinds.

-        cmd = ["kubectl", "get", params.kind, "-o", "json"]
+        kind = params.kind
+        cmd = ["kubectl", "get", kind, "-o", "json"]
@@
-    except Exception:
+    except ActionException:
+        raise
+    except Exception as e:
         msg = f"Error running fetch_cr_instances for {params}"
         logging.exception(msg)
-        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, msg)
+        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, msg) from e
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ace013 and 4d718f6.

📒 Files selected for processing (7)
  • Dockerfile (3 hunks)
  • docs/index.rst (1 hunks)
  • docs/setup-robusta/crds.rst (1 hunks)
  • helm/robusta/values.yaml (1 hunks)
  • src/robusta/core/model/env_vars.py (1 hunks)
  • src/robusta/core/playbooks/internal/CRD_API_DOCUMENTATION.md (1 hunks)
  • src/robusta/core/playbooks/internal/crds.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/robusta/core/playbooks/internal/crds.py (7)
tests/conftest.py (1)
  • robusta (94-108)
src/robusta/core/model/base_params.py (1)
  • ActionParams (60-71)
src/robusta/core/playbooks/actions_registry.py (1)
  • action (16-21)
src/robusta/core/model/events.py (2)
  • ExecutionBaseEvent (49-175)
  • add_finding (129-138)
src/robusta/core/reporting/blocks.py (4)
  • FileBlock (72-133)
  • JsonBlock (303-314)
  • TableBlock (321-448)
  • MarkdownBlock (42-61)
src/robusta/core/reporting/base.py (1)
  • Finding (248-406)
src/robusta/utils/error_codes.py (2)
  • ActionException (42-47)
  • ErrorCodes (5-40)
🪛 Flake8 (7.3.0)
src/robusta/core/playbooks/internal/crds.py

[error] 238-238: local variable 'e' is assigned to but never used

(F841)

🪛 markdownlint-cli2 (0.18.1)
src/robusta/core/playbooks/internal/CRD_API_DOCUMENTATION.md

39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


115-115: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


191-191: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🪛 Ruff (0.14.2)
src/robusta/core/playbooks/internal/crds.py

17-17: subprocess call: check for execution of untrusted input

(S603)


24-24: Consider moving this statement to an else block

(TRY300)


32-32: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


33-33: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


36-36: Use raise without specifying exception name

Remove exception name

(TRY201)


77-77: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


112-112: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


175-175: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


238-238: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


241-241: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


310-310: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

⏰ 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: run_tests
  • GitHub Check: run_tests
  • GitHub Check: Deploy docs
  • GitHub Check: Deploy docs
🔇 Additional comments (1)
docs/index.rst (1)

90-90: LGTM: navigation entry added.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (3)
src/robusta/core/playbooks/internal/crds.py (3)

16-37: Critical exception handling gaps in kubectl wrapper.

Past review correctly identified that this function needs to:

  1. Handle subprocess.TimeoutExpired separately with clear messaging
  2. Handle FileNotFoundError for missing kubectl binary
  3. Use logging.exception() instead of logging.error() (line 33)
  4. Chain exceptions with from e (lines 34, 37)

These issues affect debugging and error visibility across all kubectl-based actions.

Apply the fix from the past review:

 def run_kubectl_command(command: List[str]) -> str:
     try:
         result = subprocess.run(
             command,
             capture_output=True,
             text=True,
             check=True,
             timeout=KUBECTL_CMD_TIMEOUT_SEC
         )
         return result.stdout
     except subprocess.CalledProcessError as e:
         error_msg = f"kubectl command failed with exit code {e.returncode}\n"
         error_msg += f"Command: {' '.join(command)}\n"
         if e.stderr:
             error_msg += f"Error: {e.stderr}"
         else:
             error_msg += f"Error: {e.stdout}"
-        logging.error(error_msg)
-        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, error_msg)
-    except Exception as e:
+        logging.exception(error_msg)
+        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, error_msg) from e
+    except subprocess.TimeoutExpired as e:
+        logging.exception(f"kubectl command timed out after {KUBECTL_CMD_TIMEOUT_SEC}s: {' '.join(command)}")
+        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, "kubectl command timed out") from e
+    except FileNotFoundError as e:
+        logging.exception("kubectl not found in PATH")
+        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, "kubectl binary not found") from e
+    except Exception as e:
         logging.exception(f"Unexpected error running kubectl command {command}")
-        raise e
+        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, str(e)) from e

75-78: Avoid double-wrapping ActionException.

The current code catches all exceptions including ActionException and wraps them again. Preserve ActionException as-is and only wrap unknown exceptions.

Apply this diff:

+    except ActionException:
+        raise
     except Exception:
         msg = f"Error running kubectl_describe for {params}"
         logging.exception(msg)
-        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, msg)
+        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, msg) from e

81-113: CRITICAL: Block Secret YAML fetches to prevent credential leakage.

This function currently allows fetching YAML for any resource, including Secrets, which would expose sensitive credentials. This is a critical security vulnerability.

Apply this fix to block Secrets and support a configurable blocklist:

 @action
 def fetch_resource_yaml(event: ExecutionBaseEvent, params: ResourceParams):
     """
     Fetch resource YAML using kubectl get -o yaml.
     Output format is a FileBlock containing the YAML.
     """
+    # Block secrets to prevent credential leakage
+    if params.kind.lower() in {"secret", "secrets"}:
+        raise ActionException(ErrorCodes.RESOURCE_NOT_PERMITTED, "Fetching Secret YAML is not permitted")
+    
     finding = Finding(
         title=f"YAML for {params.kind}/{params.name}",
         aggregation_key="fetch_resource_yaml",
     )

     try:
         cmd = ["kubectl", "get", params.kind, params.name, "-o", "yaml"]
         if params.namespace:
             cmd.extend(["-n", params.namespace])

         output = run_kubectl_command(cmd)

         filename = f"{params.kind}_{params.name}.yaml"
         if params.namespace:
             filename = f"{params.namespace}_{filename}"

         file_block = FileBlock(
             filename=filename,
             contents=output.encode()
         )

         finding.add_enrichment([file_block])
         event.add_finding(finding)

+    except ActionException:
+        raise
-    except Exception:
+    except Exception as e:
         msg = f"Error running fetch_resource_yaml for {params}"
         logging.exception(msg)
-        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, msg)
+        raise ActionException(ErrorCodes.ACTION_UNEXPECTED_ERROR, msg) from e
🧹 Nitpick comments (4)
docs/setup-robusta/crds.rst (1)

39-39: Add language identifier to fenced code block.

Specify text or another appropriate language identifier for the code block to improve rendering and accessibility.

Apply this diff:

-.. code-block::
+.. code-block:: text

Based on static analysis hints.

src/robusta/core/playbooks/internal/CRD_API_DOCUMENTATION.md (3)

39-50: Add language identifier to fenced code block.

Specify yaml as the language identifier for better syntax highlighting.

Apply this diff:

-```
+```text
 File: production_deployment_nginx-deployment_describe.txt

Based on static analysis hints.


115-122: Add blank lines around table.

Tables should be surrounded by blank lines per markdown best practices.

Apply this diff:

 #### Example Response
+
 | Type | Reason | Age | From | Message |

Based on static analysis hints.


193-198: Add blank lines around table.

Tables should be surrounded by blank lines per markdown best practices.

Apply this diff:

 **Table Summary:**
+
 | Kind | API Version | Scope | Plural | Created At |

Based on static analysis hints.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d718f6 and effae32.

📒 Files selected for processing (4)
  • docs/setup-robusta/crds.rst (1 hunks)
  • helm/robusta/templates/runner-service-account.yaml (1 hunks)
  • src/robusta/core/playbooks/internal/CRD_API_DOCUMENTATION.md (1 hunks)
  • src/robusta/core/playbooks/internal/crds.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/robusta/core/playbooks/internal/crds.py (6)
src/robusta/core/model/base_params.py (1)
  • ActionParams (60-71)
src/robusta/core/playbooks/actions_registry.py (1)
  • action (16-21)
src/robusta/core/model/events.py (2)
  • ExecutionBaseEvent (49-175)
  • add_finding (129-138)
src/robusta/core/reporting/blocks.py (4)
  • FileBlock (72-133)
  • JsonBlock (303-314)
  • TableBlock (321-448)
  • MarkdownBlock (42-61)
src/robusta/core/reporting/base.py (1)
  • Finding (248-406)
src/robusta/utils/error_codes.py (2)
  • ActionException (42-47)
  • ErrorCodes (5-40)
🪛 Flake8 (7.3.0)
src/robusta/core/playbooks/internal/crds.py

[error] 241-241: local variable 'e' is assigned to but never used

(F841)

🪛 markdownlint-cli2 (0.18.1)
src/robusta/core/playbooks/internal/CRD_API_DOCUMENTATION.md

39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


115-115: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


193-193: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🪛 Ruff (0.14.2)
src/robusta/core/playbooks/internal/crds.py

18-18: subprocess call: check for execution of untrusted input

(S603)


25-25: Consider moving this statement to an else block

(TRY300)


33-33: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


34-34: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


37-37: Use raise without specifying exception name

Remove exception name

(TRY201)


78-78: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


113-113: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


176-176: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


241-241: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


244-244: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


360-360: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🔇 Additional comments (2)
helm/robusta/templates/runner-service-account.yaml (1)

10-17: LGTM! Appropriate RBAC permissions for CRD monitoring.

The read-only permissions (list, get) on customresourcedefinitions are correctly scoped for the CRD monitoring feature and follow the principle of least privilege.

src/robusta/core/playbooks/internal/crds.py (1)

288-331: Type coercion issue identified: filter_value always treated as string.

The code extracts filter_value as a string from the regex pattern and performs a direct == comparison. This fails for non-string field values: comparing 123 == "123" returns False. If filter fields contain integers, booleans, or other types, filters will silently fail to match.

The other two edge cases are handled correctly:

  • Missing filter fields return None via .get(), which doesn't match string filter_value, so no exception occurs.
  • Nested arrays are traversed via the loop at lines 307–311, supporting arbitrary depth.

Consider converting filter_value to match the actual field type before comparison, or document that filter values must be strings matching the string representation of the field.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/robusta/core/playbooks/internal/crds.py (1)

258-322: Consider using a JSONPath library for more robust field extraction.

The custom regex-based JSONPath parsing (lines 266-322) implements a subset of JSONPath functionality. While it works for the current use cases, it may be fragile for edge cases and harder to maintain than using an established library like jsonpath-ng.

If you'd like, a JSONPath library would provide:

  • More comprehensive JSONPath syntax support
  • Better error handling for malformed expressions
  • Reduced maintenance burden
  • Better test coverage

Example using jsonpath-ng:

from jsonpath_ng import parse

# For simple paths
jsonpath_expr = parse(clean_field)
matches = jsonpath_expr.find(item)
value = matches[0].value if matches else None

# For filter expressions  
jsonpath_expr = parse(field)  # e.g., "status.conditions[?type='Reconciled'].status"
matches = jsonpath_expr.find(item)
value = matches[0].value if matches else None

However, the current implementation is functional and may be adequate for your needs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between effae32 and 1821bfe.

📒 Files selected for processing (2)
  • docs/setup-robusta/crds.rst (1 hunks)
  • src/robusta/core/playbooks/internal/crds.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/robusta/core/playbooks/internal/crds.py (8)
src/robusta/core/reporting/consts.py (1)
  • SlackAnnotations (80-82)
src/robusta/core/playbooks/common.py (1)
  • get_resource_events_table (18-79)
src/robusta/core/model/base_params.py (1)
  • ActionParams (60-71)
src/robusta/core/playbooks/actions_registry.py (1)
  • action (16-21)
src/robusta/core/model/events.py (2)
  • ExecutionBaseEvent (49-175)
  • add_finding (129-138)
src/robusta/core/reporting/blocks.py (4)
  • FileBlock (72-133)
  • JsonBlock (303-314)
  • TableBlock (321-448)
  • MarkdownBlock (42-61)
src/robusta/core/reporting/base.py (2)
  • Finding (248-406)
  • EnrichmentType (115-126)
src/robusta/utils/error_codes.py (2)
  • ActionException (42-47)
  • ErrorCodes (5-40)
🪛 Flake8 (7.3.0)
src/robusta/core/playbooks/internal/crds.py

[error] 13-13: 'robusta.core.reporting.blocks.TableBlock' imported but unused

(F401)


[error] 13-13: 'robusta.core.reporting.blocks.MarkdownBlock' imported but unused

(F401)


[error] 216-216: local variable 'e' is assigned to but never used

(F841)

🪛 Ruff (0.14.2)
src/robusta/core/playbooks/internal/crds.py

20-20: subprocess call: check for execution of untrusted input

(S603)


27-27: Consider moving this statement to an else block

(TRY300)


35-35: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


36-36: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


39-39: Use raise without specifying exception name

Remove exception name

(TRY201)


80-80: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


115-115: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


151-151: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


216-216: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


219-219: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


335-335: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

⏰ 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: run_tests
  • GitHub Check: run_tests
  • GitHub Check: Deploy docs

@arikalon1 arikalon1 merged commit 060705b into master Nov 2, 2025
6 checks passed
@arikalon1 arikalon1 deleted the crds-support branch November 2, 2025 16:25
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.

3 participants