ROX-34665: Add Scans per Day by Namespace panel to cluster overview - #340
ROX-34665: Add Scans per Day by Namespace panel to cluster overview#340ebensh wants to merge 3 commits into
Conversation
…ashboard Add table panel showing daily scan counts broken down by namespace to rhacs-cluster-overview dashboard, placed after Scanner Overview Table. Uses increase(rox_central_scan_duration_count[1d]) with matrix transform to display dates as columns.
|
Could we also chart this to allow spotting spikes quickly? |
| @@ -0,0 +1,12 @@ | |||
| { | |||
There was a problem hiding this comment.
Can we add this file to .gitignore?
|
Agree with @GrimmiMeloni , a chart would be more representative than a table |
I originally had a continuous plot of the metric and asked about this but the answer I got was:
So I converted to a table aligned to midnight for the daily counts. I can of course go back to a simple increase()[1d] for the rolling amount. Do we want the table and the plot or just the plot? |
|
I think just the plot would be fine. It's ok if it only shows the daily number like in the table. The whole idea was to simply have something to "eyeball" the usage patterns. |
|
How about a stacked bar chart with dates on the X-axis? |
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe Grafana dashboard now includes daily scan counts grouped by namespace. Existing Certificate Expiry panels move down to make space. A local Claude settings file adds workspace read access and selected command permissions. ChangesGrafana scan panel
Local Claude permissions
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@resources/grafana/sources/.claude/settings.local.json`:
- Line 6: Update the permissions configuration entry for Bash(jj rebase *) to
remove the broad rule or replace it with a narrowly scoped permission such as
Bash(jj rebase --continue *) that permits only the intended workflow.
- Line 9: Update the Bash permission rule in the local Claude settings so the
commit-message quote is properly closed before the wildcard suffix, making the
pattern match the intended quoted jj commit command exactly.
In `@resources/grafana/sources/rhacs-cluster-overview.json`:
- Line 2227: Update the Prometheus expression in the scan-count panel to filter
rox_central_scan_duration_count by the selected $instance_id label before
aggregating by namespace, matching the namespace scoping used by existing
dashboard panels.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: 8d1e4ecb-efac-43fb-99fb-e715a43b6790
⛔ Files ignored due to path filters (1)
resources/grafana/generated/dashboards/rhacs-cluster-overview.yamlis excluded by!**/generated/**
📒 Files selected for processing (2)
resources/grafana/sources/.claude/settings.local.jsonresources/grafana/sources/rhacs-cluster-overview.json
| "allow": [ | ||
| "Read(//home/ebenshet/workspaces/rox-34665-grafana-display-scans-per-day/github.com/stackrox/rhacs-observability-resources/**)", | ||
| "Bash(jj status *)", | ||
| "Bash(jj rebase *)", |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python - <<'PY'
import json
path = "resources/grafana/sources/.claude/settings.local.json"
with open(path, encoding="utf-8") as stream:
rules = json.load(stream)["permissions"]["allow"]
matches = [rule for rule in rules if rule.startswith("Bash(jj rebase")]
if not matches:
raise SystemExit("No jj rebase rule found")
for rule in matches:
print(rule)
if rule == "Bash(jj rebase *)":
raise SystemExit("Unscoped jj rebase permission found")
PYRepository: stackrox/rhacs-observability-resources
Length of output: 230
🌐 Web query:
Claude Code permissions allow rules Bash command glob prefix Bash command:*
💡 Result:
In Claude Code, Bash permission rules support glob pattern matching using the asterisk (*) character [1][2]. These rules allow you to specify which shell commands Claude is permitted to execute, blocked from executing (deny), or required to ask about (ask) [3][4]. Key details regarding the use of glob patterns in Bash rules: Positioning and Matching: Wildcards can be placed at the beginning, middle, or end of a command string [1][3]. - Bash(npm ) matches any command starting with "npm " [1][3]. - Bash( install) matches any command ending in " install" [1][3]. - Bash(git * main) matches commands like "git checkout main" or "git log --oneline main" [1][3]. Word Boundaries: The placement of a space before the asterisk is significant because it enforces word boundaries [1][2]. - Bash(ls ) matches "ls -la" but does not match "lsof" [1][2]. - Bash(ls) matches both "ls -la" and "lsof" [1][2]. Alternative Suffix: The:* suffix is functionally equivalent to a trailing wildcard [1][2]. For example, Bash(ls:*) matches the same commands as Bash(ls *) [1][2]. Important Behaviors: - Compound Commands: Claude Code parses compound commands (e.g., those using && or ||) individually. A Bash rule such as Bash(safe-cmd *) does not automatically permit a command like "safe-cmd && rm -rf." because each subcommand must match the permission rules independently [3]. - Rule Evaluation: Rules are evaluated in the order of deny, then ask, then allow [4]. The first matching rule determines the outcome [4]. A deny rule is the strongest and will block a command even if a more specific allow rule exists [4]. - Tool Removal vs. Scoping: A deny rule specified with just the tool name (e.g., "Bash") removes the tool entirely from Claude's context [1][3]. A scoped deny rule (e.g., "Bash(rm *)") keeps the tool available but blocks only the matching command pattern [3][4]. These rules are typically configured in your.claude/settings.json or ~/.claude/settings.json files [5][6].
Citations:
- 1: https://code.claude.com/docs/en/permissions
- 2: https://code.claude.com/docs/en/permissions.md
- 3: https://getclaudekit.com/blog/guide/mechanics/permission-model
- 4: https://usingclaude.com/en/claude-code/install/claude-code-permissions
- 5: https://code.claude.com/docs/en/settings
- 6: https://cc.bruniaux.com/cheatsheets/t04-permissions-glob-patterns/
Narrow the jj rebase permission.
Bash(jj rebase *) permits arbitrary jj rebase options and subcommands. Remove this rule or replace it with a specific command such as Bash(jj rebase --continue *) for the exact workflow.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@resources/grafana/sources/.claude/settings.local.json` at line 6, Update the
permissions configuration entry for Bash(jj rebase *) to remove the broad rule
or replace it with a narrowly scoped permission such as Bash(jj rebase
--continue *) that permits only the intended workflow.
Source: Path instructions
| "Bash(jj rebase *)", | ||
| "Bash(rm -f resources/grafana/generated/dashboards/new-panel.yaml resources/grafana/sources/.claude/settings.local.json)", | ||
| "Bash(rmdir resources/grafana/sources/.claude)", | ||
| "Bash(jj commit -m 'ROX-34665: Add Scans per Day by Namespace panel to cluster overview dashboard *)" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python - <<'PY'
import json
path = "resources/grafana/sources/.claude/settings.local.json"
with open(path, encoding="utf-8") as stream:
rules = json.load(stream)["permissions"]["allow"]
rule = next(rule for rule in rules if rule.startswith("Bash(jj commit"))
body = rule[len("Bash("):-1]
if body.count("'") % 2:
raise SystemExit("Commit permission has unbalanced single quotes")
if body.endswith(" *"):
raise SystemExit("Commit permission is broader than the exact command")
PYRepository: stackrox/rhacs-observability-resources
Length of output: 223
🌐 Web query:
Claude Code IAM Bash rules exact Bash(command) prefix Bash(command:*)
💡 Result:
Claude Code uses flexible pattern matching for Bash command permissions, supporting exact matches, wildcard patterns, and a specialized cmd: specifier [1][2]. ### Bash Permission Matching Syntax Claude Code evaluates rules based on the following patterns: * Exact Matches: Bash(npm run build) allows only that specific command [3][2]. * Wildcard Patterns: Use * to match arbitrary characters [3]. * Bash(npm *): Matches any command starting with npm . * Bash(* install): Matches any command ending with install [3][4]. * Bash(git * main): Matches commands with mid-string wildcards, such as git checkout main [3]. * Note: The presence of a space before the * is significant. Bash(ls *) matches ls -la but not lsof, whereas Bash(ls*) matches both [3][2]. * Legacy Prefix Syntax: The :* suffix (e.g., Bash(git:*)) is a legacy, deprecated syntax equivalent to using a wildcard space pattern [1][2]. ### The cmd: Specifier The cmd: prefix matches against the base command name, providing resilience against quoted arguments, shell operators, and special characters [2]. * Bash(cmd:git): Matches any invocation where the base command is git, regardless of arguments [2]. * Bash(cmd:git *): Matches any git command followed by any arguments [2]. * Bash(cmd:*): Matches all Bash commands (functionally equivalent to Bash) [2]. ### Important Considerations * Compound Commands: Claude Code recognizes shell operators (&&, ||, ;, |, |&, &, newlines). Rules must match each subcommand independently; a rule like Bash(safe-cmd *) does not grant permission to execute safe-cmd && dangerous-cmd [3][1]. * Security Warning: Bash permission patterns are fragile and should not be relied upon as a primary security boundary [5]. They can often be bypassed by flag reordering, protocol changes, or using shell variables [5]. * Automatic Stripping: Safe wrapper commands (e.g., timeout, nice) and safe environment variable assignments are automatically stripped before matching so that permission rules apply to the core command [1].
Citations:
- 1: https://www.mintlify.com/VineeTagarwaL-code/claude-code/reference/tools/bash
- 2: [DOCS] Permissions docs missing Bash cmd: specifier syntax for permission rules anthropics/claude-code#34277
- 3: https://code.claude.com/docs/en/permissions
- 4: [DOCS] Documentation Contradiction: Bash Permission Matching Logic (Prefix vs Wildcard) anthropics/claude-code#18961
- 5: [DOCS] Inconsistent Security Guidance Regarding Bash Permission Prefix Matching anthropics/claude-code#19133
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,40p' resources/grafana/sources/.claude/settings.local.json | cat -nRepository: stackrox/rhacs-observability-resources
Length of output: 789
Fix the commit permission pattern.
The rule opens a single quote before the commit message but never closes it before *). It will not match the intended quoted commit command.
Use an exact rule:
Proposed fix
- "Bash(jj commit -m 'ROX-34665: Add Scans per Day by Namespace panel to cluster overview dashboard *)"
+ "Bash(jj commit -m 'ROX-34665: Add Scans per Day by Namespace panel to cluster overview dashboard')"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "Bash(jj commit -m 'ROX-34665: Add Scans per Day by Namespace panel to cluster overview dashboard *)" | |
| "Bash(jj commit -m 'ROX-34665: Add Scans per Day by Namespace panel to cluster overview dashboard')" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@resources/grafana/sources/.claude/settings.local.json` at line 9, Update the
Bash permission rule in the local Claude settings so the commit-message quote is
properly closed before the wildcard suffix, making the pattern match the
intended quoted jj commit command exactly.
| }, | ||
| "editorMode": "code", | ||
| "exemplar": false, | ||
| "expr": "sum by (namespace) (increase(rox_central_scan_duration_count[1d]))", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Restrict the query to the dashboard namespace scope.
Line 2227 aggregates scans from every namespace in the datasource. It ignores the $instance_id selection that existing dashboard panels use. This can show unrelated scan counts and increases query cost.
Proposed fix
- "expr": "sum by (namespace) (increase(rox_central_scan_duration_count[1d]))",
+ "expr": "sum by (namespace) (increase(rox_central_scan_duration_count{namespace=~\"rhacs-$instance_id\"}[1d]))",As per path instructions, focus on “major issues impacting performance, readability, maintainability and security.”
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "expr": "sum by (namespace) (increase(rox_central_scan_duration_count[1d]))", | |
| "expr": "sum by (namespace) (increase(rox_central_scan_duration_count{namespace=~\"rhacs-$instance_id\"}[1d]))", |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@resources/grafana/sources/rhacs-cluster-overview.json` at line 2227, Update
the Prometheus expression in the scan-count panel to filter
rox_central_scan_duration_count by the selected $instance_id label before
aggregating by namespace, matching the namespace scoping used by existing
dashboard panels.
Source: Path instructions
Summary
rhacs-cluster-overviewGrafana dashboardincrease(rox_central_scan_duration_count[1d])with matrix transform to show daily scan counts per namespace as date columnsDetails
The panel uses the existing
$_relativeTimeand$_timeShiftdashboard variables to control the time window. Results are formatted as a pivot table with namespaces as rows and dates (YYYY-MM-DD) as columns.Test plan
🔗 ROX-34665