Skip to content

[ignore] test qodo config#1644

Open
fghanmi wants to merge 1 commit intomainfrom
testQodoConfig
Open

[ignore] test qodo config#1644
fghanmi wants to merge 1 commit intomainfrom
testQodoConfig

Conversation

@fghanmi
Copy link
Member

@fghanmi fghanmi commented Mar 6, 2026

No description provided.

@fghanmi
Copy link
Member Author

fghanmi commented Mar 6, 2026

/review

@fghanmi fghanmi closed this Mar 6, 2026
@fghanmi fghanmi reopened this Mar 9, 2026
@fghanmi
Copy link
Member Author

fghanmi commented Mar 9, 2026

/agentic_review

@fghanmi fghanmi closed this Mar 9, 2026
@fghanmi fghanmi reopened this Mar 12, 2026
@fghanmi
Copy link
Member Author

fghanmi commented Mar 12, 2026

/agentic_review

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 12, 2026

Code Review by Qodo

🐞 Bugs (5) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Nil ConsoleSpec deref 🐞 Bug ⛯ Reliability
Description
consoleAction.Handle dereferences instance.Spec.Console without a nil-check even though
SecuresignSpec.Console is optional, causing a panic when spec.console is omitted. This crashes
reconciliation for Securesign resources.
Code

internal/controller/securesign/actions/ensure_console.go[R57-60]

+		func(object *rhtasv1alpha1.Console) error {
+			object.Spec = *instance.Spec.Console
+			return nil
+		},
Evidence
SecuresignSpec.Console is a pointer and is tagged omitempty (may be absent), but the Console action
runs unconditionally and dereferences it, which will panic on nil.

internal/controller/securesign/actions/ensure_console.go[35-60]
api/v1alpha1/securesign_types.go[30-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`internal/controller/securesign/actions/ensure_console.go` dereferences `instance.Spec.Console` without checking for nil even though the field is optional, which can panic the controller.

### Issue Context
`SecuresignSpec.Console` is `*ConsoleSpec` with `json:"console,omitempty"`, so manifests may omit it.

### Fix Focus Areas
- internal/controller/securesign/actions/ensure_console.go[35-66]

### Implementation notes
- Change `CanHandle` to `return instance.Spec.Console != nil` (and optionally also check `instance.Spec.Console.Enabled`).
- Or in `Handle`, add:
 - `if instance.Spec.Console == nil { /* set ConsoleCondition NotDefined/Disabled and Continue */ }`
 - only assign `object.Spec = *instance.Spec.Console` when non-nil.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Nil condition deref 🐞 Bug ⛯ Reliability
Description
consoleAction.CopyStatus dereferences meta.FindStatusCondition(...).Reason without a nil-check,
which can panic if ConsoleCondition is missing from Securesign status. This can crash reconciliation
while syncing Console status.
Code

internal/controller/securesign/actions/ensure_console.go[R84-97]

+func (i consoleAction) CopyStatus(ctx context.Context, object *rhtasv1alpha1.Console, instance *rhtasv1alpha1.Securesign) *action.Result {
+	objectStatus := meta.FindStatusCondition(object.Status.Conditions, constants.ReadyCondition)
+	if objectStatus == nil {
+		// not initialized yet, wait for update
+		return i.Continue()
+	}
+	if meta.FindStatusCondition(instance.Status.Conditions, ConsoleCondition).Reason != objectStatus.Reason {
+		meta.SetStatusCondition(&instance.Status.Conditions, v1.Condition{
+			Type:   ConsoleCondition,
+			Status: objectStatus.Status,
+			Reason: objectStatus.Reason,
+		})
+		return i.StatusUpdate(ctx, instance)
+	}
Evidence
CopyStatus only nil-checks the Console object's Ready condition; it does not nil-check the
Securesign instance's ConsoleCondition before reading .Reason.

internal/controller/securesign/actions/ensure_console.go[84-97]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`CopyStatus` can panic by accessing `.Reason` on a nil condition pointer returned by `meta.FindStatusCondition`.

### Issue Context
`meta.FindStatusCondition` returns `*Condition` and may return nil when the condition is absent.

### Fix Focus Areas
- internal/controller/securesign/actions/ensure_console.go[84-97]

### Implementation notes
- Replace the direct deref with:
 - `current := meta.FindStatusCondition(instance.Status.Conditions, ConsoleCondition)`
 - if `current == nil` then set the condition (or treat as different) and `StatusUpdate`.
 - otherwise compare `current.Reason`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. TUF URL shell injection 🐞 Bug ⛨ Security
Description
Console API deployment initContainer builds a /bin/sh -c script by interpolating
spec.api.tuf.address into a curl command, enabling shell command injection via crafted addresses.
This allows arbitrary command execution in the initContainer when a user can create/patch the
Console resource.
Code

internal/controller/console/actions/api/deployment.go[R112-131]

+		initContainer := kubernetes.FindInitContainerByNameOrCreate(&template.Spec, "wait-for-console-db-tuf")
+		initContainer.Image = images.Registry.Get(images.ConsoleDb)
+
+		initContainer.Command = []string{
+			"/bin/sh",
+			"-c",
+			fmt.Sprintf(`
+                echo "Waiting for rekor-server...";
+                until mysqladmin ping -h%s --silent > /dev/null 2>&1; do
+                    echo "Waiting for the console database to be ready...";
+                    sleep 5;
+                done;
+                echo "Waiting for TUF server...";
+                until curl %s > /dev/null 2>&1; do
+                    echo "TUF server not ready...";
+                    sleep 5;
+                done;
+                echo "tuf-init completed."
+            `, actions.DbDeploymentName, tufServerHost),
+		}
Evidence
The TUF address is taken directly from the Console spec and inserted into a shell script executed
via /bin/sh -c, so any shell metacharacters in the address are interpreted by the shell.

internal/controller/console/actions/api/deployment.go[112-131]
internal/controller/console/actions/api/deployment.go[199-206]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The initContainer uses `/bin/sh -c` with a `fmt.Sprintf` script that directly embeds `spec.api.tuf.address`, allowing shell injection.

### Issue Context
`resolveTufUrl()` returns the raw user-provided address and it is inserted into `until curl %s ...`.

### Fix Focus Areas
- internal/controller/console/actions/api/deployment.go[112-131]
- internal/controller/console/actions/api/deployment.go[199-208]

### Implementation notes
Prefer one of:
1) Remove the shell and use an exec-form command that cannot be injected:
  - e.g. run a small loop script where the URL is read from an env var but always referenced as `"$TUF_URL"`.
2) Strictly validate `spec.api.tuf.address` with `net/url` and reject anything not `http/https` and containing whitespace/control characters.
3) If keeping shell, pass URL via env var and always quote it: `curl -sf "${TUF_URL}"`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. Unquoted password breaks probes 🐞 Bug ⛯ Reliability
Description
DB readiness/liveness probes run bash -c commands that include unquoted ${MYSQL_PASSWORD}, while
generated passwords include shell metacharacters like '&' and '$'. This can make probes fail
unpredictably and keep the DB pod unready or restart-looping.
Code

internal/controller/console/actions/db/deployment.go[R32-35]

+const (
+	livenessCommand  = "mariadb-admin -u ${MYSQL_USER} -p${MYSQL_PASSWORD} ping"
+	readinessCommand = "mariadb -u ${MYSQL_USER} -p${MYSQL_PASSWORD} -e \"SELECT 1;\""
+)
Evidence
Passwords are generated from a charset containing shell metacharacters and then expanded unquoted in
a bash command string used by probes; shell metacharacters can change command parsing/semantics.

internal/utils/password.go[9-18]
internal/controller/console/actions/db/deployment.go[32-35]
internal/controller/console/actions/db/deployment.go[194-212]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The DB probes execute `bash -c` with unquoted `${MYSQL_PASSWORD}`; since generated passwords include characters like `&` and `$`, probes can break and cause restart loops.

### Issue Context
`GeneratePassword()` includes `!@#$%&*`, and probes use `bash -c`.

### Fix Focus Areas
- internal/controller/console/actions/db/deployment.go[32-35]
- internal/controller/console/actions/db/deployment.go[194-212]

### Implementation notes
- Update probe command strings to quote variables, e.g. `-p"${MYSQL_PASSWORD}"`.
- Prefer using an exec-form probe without a shell if possible (e.g., `[]string{"mariadb-admin","-u","$(MYSQL_USER)","-p$(MYSQL_PASSWORD)","ping"}` is still expansion-dependent; the safest is a small wrapper script with strict quoting).
- Optionally, constrain generated passwords to a shell-safe charset if you must keep `bash -c` probes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Stdout debug prints 🐞 Bug ✧ Quality
Description
Console UI service action uses fmt.Println in CanHandle and Handle, emitting unstructured stdout
logs and bypassing controller-runtime logging context. This pollutes operator logs and makes
reconciliation harder to trace.
Code

internal/controller/console/actions/ui/service.go[R38-46]

+func (i createServiceAction) CanHandle(ctx context.Context, instance *rhtasv1alpha1.Console) bool {
+	fmt.Println("***********-------- INSIDE UI SERVICE CanHandle")
+	return instance.Spec.Enabled && state.FromInstance(instance, constants.ReadyCondition) >= state.Creating
+}
+
+func (i createServiceAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Console) *action.Result {
+
+	fmt.Println("***********-------- INSIDE UI SERVICE Handle")
+	var (
Evidence
The action prints directly to stdout during reconciliation instead of using the injected logger
(i.Logger).

internal/controller/console/actions/ui/service.go[38-46]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The UI service action prints to stdout via `fmt.Println` during reconciliation.

### Issue Context
Controllers should use the injected structured logger for consistent, contextual logs.

### Fix Focus Areas
- internal/controller/console/actions/ui/service.go[38-46]

### Implementation notes
- Delete the `fmt.Println` calls.
- Replace with `i.Logger.V(2).Info("...")` if the messages are still needed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@qodo-code-review qodo-code-review bot added enhancement New feature or request Tests labels Mar 12, 2026
@qodo-code-review
Copy link

qodo-code-review bot commented Mar 12, 2026

Review Summary by Qodo

Implement Console component controller with database, API, and UI management

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Implements complete Console controller for managing console-ui, console-api, and console-db
  components within Securesign operator
• Adds Console custom resource definition (CRD) with comprehensive spec and status types supporting
  TLS, external access, and resource configuration
• Implements database component with secret management, PVC creation, TLS configuration, service,
  deployment, and initialization logic
• Implements API component with TLS configuration, service, deployment, monitoring (ServiceMonitor),
  RBAC, and initialization logic
• Implements UI component with service, deployment, ingress for external access, RBAC, and
  initialization logic
• Integrates Console resource creation and status synchronization into Securesign controller via
  ensure_console action
• Adds comprehensive test coverage for Console controller reconciliation including database, API,
  UI, and status condition verification
• Updates RBAC configuration with Console resource permissions and viewer/editor ClusterRoles
• Registers Console images (console-ui, console-api, console-db) in operator configuration and
  kustomization
• Updates Securesign CRD with optional Console specification and status tracking
• Provides sample Console configuration in Securesign manifest

Grey Divider

File Changes

1. internal/controller/console/actions/db/deployment.go ✨ Enhancement +262/-0

Console database deployment configuration and management

• New file implementing database deployment action for Console component
• Configures MariaDB deployment with environment variables, probes, and volume mounts
• Supports TLS configuration for secure database connections
• Handles liveness and readiness probes with optional SSL parameters

internal/controller/console/actions/db/deployment.go


2. api/v1alpha1/zz_generated.deepcopy.go Code generation +190/-0

Auto-generated deepcopy methods for Console types

• Auto-generated deepcopy functions for Console-related types
• Adds deepcopy support for Console, ConsoleList, ConsoleSpec, ConsoleStatus, ConsoleUI,
 ConsoleApi, ConsoleDB
• Adds deepcopy support for SecuresignConsoleStatus and updates SecuresignSpec and
 SecuresignStatus

api/v1alpha1/zz_generated.deepcopy.go


3. internal/controller/console/console_controller_test.go 🧪 Tests +196/-0

Console controller integration tests

• New test file for Console controller reconciliation
• Tests database secret, PVC, service, and deployment creation
• Verifies status conditions and deployment readiness
• Tests controller's ability to restore desired state

internal/controller/console/console_controller_test.go


View more (45)
4. internal/controller/console/actions/api/deployment.go ✨ Enhancement +208/-0

Console API deployment configuration and setup

• New file implementing API deployment action for Console
• Configures console-api deployment with TUF server connectivity
• Sets up environment variables for database and TLS configuration
• Includes init container for waiting on database and TUF server readiness

internal/controller/console/actions/api/deployment.go


5. internal/controller/console/console_controller.go ✨ Enhancement +165/-0

Console controller main reconciliation logic

• New main controller for Console resource reconciliation
• Orchestrates actions for database, API, and UI components
• Manages phase transitions from Pending to Creating to Initialize to Ready
• Handles namespace deletion checks and action execution

internal/controller/console/console_controller.go


6. internal/controller/console/actions/ui/deployment.go ✨ Enhancement +166/-0

Console UI deployment configuration and setup

• New file implementing UI deployment action for Console
• Configures console-ui deployment with API connectivity
• Sets up environment variables for API URL and version
• Includes init container for waiting on console-api readiness

internal/controller/console/actions/ui/deployment.go


7. internal/controller/console/actions/db/handle_secret.go ✨ Enhancement +162/-0

Database secret creation and management

• New file managing database secret creation and lifecycle
• Generates database credentials with random passwords
• Creates DSN connection string for database access
• Handles secret cleanup and reuse logic

internal/controller/console/actions/db/handle_secret.go


8. api/v1alpha1/console_types.go ✨ Enhancement +143/-0

Console custom resource definition types

• New file defining Console CRD types and schemas
• Defines ConsoleSpec, ConsoleStatus, ConsoleUI, ConsoleApi, ConsoleDB structures
• Includes condition management and trusted CA reference support
• Implements GetConditions, SetCondition, and GetTrustedCA methods

api/v1alpha1/console_types.go


9. internal/controller/console/actions/ui/service.go ✨ Enhancement +98/-0

Console UI service creation and configuration

• New file implementing UI service creation action
• Creates Kubernetes service for console-ui deployment
• Configures service ports for HTTP and metrics
• Handles TLS annotations for OpenShift environments

internal/controller/console/actions/ui/service.go


10. internal/controller/securesign/actions/ensure_console.go ✨ Enhancement +99/-0

Securesign Console resource creation and status sync

• New file implementing Console resource creation from Securesign spec
• Creates Console resource as child of Securesign
• Copies status conditions from Console to Securesign
• Manages controller references and label inheritance

internal/controller/securesign/actions/ensure_console.go


11. internal/controller/console/actions/api/service.go ✨ Enhancement +97/-0

Console API service creation and configuration

• New file implementing API service creation action
• Creates Kubernetes service for console-api deployment
• Configures service ports for HTTP and metrics
• Handles TLS annotations for OpenShift environments

internal/controller/console/actions/api/service.go


12. internal/controller/console/actions/ui/ingress.go ✨ Enhancement +78/-0

Console UI ingress creation for external access

• New file implementing ingress creation for UI external access
• Creates ingress resource when external access is enabled
• Applies route selector labels and TLS configuration
• Manages ingress lifecycle and status conditions

internal/controller/console/actions/ui/ingress.go


13. internal/controller/console/actions/db/svc.go ✨ Enhancement +86/-0

Console database service creation and configuration

• New file implementing database service creation action
• Creates Kubernetes service for console-db deployment
• Configures service port for MySQL/MariaDB (3306)
• Handles TLS annotations for OpenShift environments

internal/controller/console/actions/db/svc.go


14. api/v1alpha1/securesign_types.go ✨ Enhancement +11/-5

Securesign spec and status extended with Console support

• Adds Console field to SecuresignSpec for optional Console configuration
• Adds ConsoleStatus field to SecuresignStatus for tracking Console state
• Updates field alignment and adds new status type SecuresignConsoleStatus

api/v1alpha1/securesign_types.go


15. cmd/main.go ✨ Enhancement +5/-0

Main operator setup with Console controller registration

• Registers console controller with manager
• Adds related image flags for console-ui, console-api, and console-db images
• Integrates Console reconciler into main operator setup

cmd/main.go


16. internal/controller/console/actions/api/monitoring.go ✨ Enhancement +76/-0

Console API monitoring and ServiceMonitor creation

• New file implementing ServiceMonitor creation for API metrics
• Creates monitoring resources for prometheus integration
• Supports both HTTP and HTTPS endpoints based on TLS configuration
• Manages monitoring lifecycle and status conditions

internal/controller/console/actions/api/monitoring.go


17. internal/controller/console/actions/db/tls.go ✨ Enhancement +74/-0

Database TLS configuration and resolution

• New file implementing TLS configuration resolution for database
• Handles TLS setup from spec or generates default OpenShift TLS
• Manages TLS status conditions and certificate references

internal/controller/console/actions/db/tls.go


18. internal/controller/console/actions/api/tls.go ✨ Enhancement +71/-0

API TLS configuration and resolution

• New file implementing TLS configuration resolution for API
• Handles TLS setup from spec or generates default OpenShift TLS
• Manages TLS status conditions and certificate references

internal/controller/console/actions/api/tls.go


19. internal/controller/console/actions/ui/ingress_test.go 🧪 Tests +62/-0

UI ingress action unit tests

• New test file for UI ingress action
• Tests CanHandle logic for various console states and external access settings
• Validates ingress creation conditions

internal/controller/console/actions/ui/ingress_test.go


20. internal/controller/console/actions/db/initialize.go ✨ Enhancement +58/-0

Database initialization and readiness verification

• New file implementing database initialization action
• Waits for database deployment to be ready
• Manages initialization phase and ready condition transitions

internal/controller/console/actions/db/initialize.go


21. internal/controller/console/actions/ui/initialize.go ✨ Enhancement +56/-0

UI initialization and readiness verification

• New file implementing UI initialization action
• Waits for UI deployment to be ready
• Manages initialization phase and ready condition transitions

internal/controller/console/actions/ui/initialize.go


22. internal/controller/console/actions/api/initialize.go ✨ Enhancement +55/-0

API initialization and readiness verification

• New file implementing API initialization action
• Waits for API deployment to be ready
• Manages initialization phase and ready condition transitions

internal/controller/console/actions/api/initialize.go


23. internal/controller/console/actions/constants.go ⚙️ Configuration changes +43/-0

Console component constants and configuration values

• New file defining constants for Console component
• Defines deployment names, component names, TLS secret names, RBAC names
• Defines port numbers and secret key names for database configuration

internal/controller/console/actions/constants.go


24. internal/controller/console/suite_test.go 🧪 Tests +46/-0

Console controller test suite initialization

• New test suite setup file for Console controller tests
• Initializes test environment with Ginkgo and controller runtime
• Configures logging and test timeouts

internal/controller/console/suite_test.go


25. internal/images/images.go ⚙️ Configuration changes +6/-0

Console component image definitions

• Adds three new image constants: ConsoleUi, ConsoleApi, ConsoleDb
• Registers new images in the Images slice for initialization

internal/images/images.go


26. internal/controller/console/actions/db/pvc.go ✨ Enhancement +32/-0

Database persistent volume claim creation

• New file implementing PVC creation action for database
• Wraps generic PVC action with Console-specific configuration
• Manages persistent volume claim lifecycle for database storage

internal/controller/console/actions/db/pvc.go


27. internal/controller/console/actions/db/rbac.go ✨ Enhancement +24/-0

Database RBAC and service account setup

• New file implementing RBAC action for database component
• Creates service account and role bindings for database
• Configures permissions based on component state

internal/controller/console/actions/db/rbac.go


28. internal/controller/securesign/actions/initialize_status.go ✨ Enhancement +1/-1

Securesign status initialization with Console condition

• Adds ConsoleCondition to the list of conditions to initialize

internal/controller/securesign/actions/initialize_status.go


29. internal/controller/securesign/actions/update_status.go ✨ Enhancement +1/-1

Securesign status update with Console condition ordering

• Adds ConsoleCondition to the sorted conditions list for status updates

internal/controller/securesign/actions/update_status.go


30. internal/controller/console/utils/tls.go ✨ Enhancement +25/-0

Console database TLS usage utility function

• New file implementing TLS usage detection for database
• Checks if managed database has TLS or external database has trusted CA
• Provides utility function for TLS configuration decisions

internal/controller/console/utils/tls.go


31. internal/controller/console/actions/db/helper.go ✨ Enhancement +21/-0

Database action helper functions

• New file with helper functions for database actions
• Provides enabled(), specTLS(), statusTLS(), setStatusTLS() utilities
• Simplifies TLS and enabled state management

internal/controller/console/actions/db/helper.go


32. internal/controller/securesign/actions/constants.go ⚙️ Configuration changes +1/-0

Securesign Console condition constant

• Adds ConsoleCondition constant for Console availability tracking

internal/controller/securesign/actions/constants.go


33. internal/controller/securesign/securesign_controller.go ✨ Enhancement +1/-0

Securesign controller Console action integration

• Registers Console action in the reconciliation action list
• Adds NewConsoleAction() to the actions pipeline

internal/controller/securesign/securesign_controller.go


34. internal/controller/console/actions/api/rbac.go ✨ Enhancement +12/-0

API RBAC and service account setup

• New file implementing RBAC action for API component
• Creates service account and role bindings for API

internal/controller/console/actions/api/rbac.go


35. internal/controller/console/actions/ui/rbac.go ✨ Enhancement +12/-0

UI RBAC and service account setup

• New file implementing RBAC action for UI component
• Creates service account and role bindings for UI

internal/controller/console/actions/ui/rbac.go


36. internal/controller/console/actions/api/helper.go ✨ Enhancement +15/-0

API action helper functions

• New file with helper functions for API actions
• Provides specTLS(), statusTLS(), setStatusTLS() utilities
• Simplifies TLS state management for API component

internal/controller/console/actions/api/helper.go


37. internal/controller/console/actions/ui/helper.go Miscellaneous +13/-0

UI action helper functions (placeholder)

• New file with commented-out helper functions for UI TLS
• Placeholder for future UI TLS configuration support

internal/controller/console/actions/ui/helper.go


38. config/default/images.env ⚙️ Configuration changes +18/-15

Image registry updates and Console image additions

• Updates image registry URLs from registry.redhat.io/rhtas/ to quay.io/securesign/
• Adds three new console image entries: RELATED_IMAGE_CONSOLE_UI, RELATED_IMAGE_CONSOLE_API,
 RELATED_IMAGE_CONSOLE_DB
• Updates netcat image SHA256 hash

config/default/images.env


39. config/crd/kustomization.yaml ⚙️ Configuration changes +3/-0

Console CRD kustomization configuration

• Adds rhtas.redhat.com_consoles.yaml to CRD resources
• Adds commented webhook and CA injection patches for Console CRD

config/crd/kustomization.yaml


40. config/default/kustomization.yaml ⚙️ Configuration changes +34/-0

Console image replacements in kustomization

• Adds three replacement entries for console image environment variables
• Maps RELATED_IMAGE_CONSOLE_UI, RELATED_IMAGE_CONSOLE_API, RELATED_IMAGE_CONSOLE_DB to
 deployment

config/default/kustomization.yaml


41. config/rbac/role.yaml ⚙️ Configuration changes +3/-0

RBAC role updates for Console resources

• Adds consoles to resource list for rhtas.redhat.com API group
• Adds consoles/finalizers and consoles/status to respective rule lists

config/rbac/role.yaml


42. config/rbac/console_viewer_role.yaml ⚙️ Configuration changes +27/-0

Console viewer ClusterRole for RBAC

• New file creating ClusterRole for Console resource viewing
• Grants get, list, watch permissions on consoles and consoles/status

config/rbac/console_viewer_role.yaml


43. config/crd/bases/rhtas.redhat.com_securesigns.yaml ⚙️ Configuration changes +2329/-0

Add Console component CRD specification and status

• Added comprehensive console specification to the Securesign CRD with support for Console API and
 UI services
• Included configuration for database management with PVC support and TLS encryption options
• Added pod affinity, resource requirements, tolerations, and external access (Ingress/Route)
 settings
• Added console status field to track the console URL in the Securesign status

config/crd/bases/rhtas.redhat.com_securesigns.yaml


44. config/rbac/console_editor_role.yaml ⚙️ Configuration changes +31/-0

Create RBAC ClusterRole for Console editor permissions

• Created new ClusterRole for console resource management
• Defined permissions for create, delete, get, list, patch, update, and watch operations on
 consoles resources
• Added permissions for reading console status

config/rbac/console_editor_role.yaml


45. config/default/manager_images_patch.yaml ⚙️ Configuration changes +6/-0

Add Console container image environment variables

• Added three new environment variable placeholders for console-related container images
• Added RELATED_IMAGE_CONSOLE_UI, RELATED_IMAGE_CONSOLE_API, and RELATED_IMAGE_CONSOLE_DB
 variables

config/default/manager_images_patch.yaml


46. config/samples/rhtas_v1alpha1_securesign.yaml ⚙️ Configuration changes +8/-0

Add Console sample configuration to Securesign

• Added sample console configuration with enabled flag set to true
• Configured database creation and UI external access settings in the sample

config/samples/rhtas_v1alpha1_securesign.yaml


47. config/samples/kustomization.yaml ⚙️ Configuration changes +1/-0

Register Console sample in kustomization

• Added reference to new console sample manifest file rhtas_v1alpha1_console.yaml

config/samples/kustomization.yaml


48. config/crd/bases/rhtas.redhat.com_consoles.yaml Additional files +4697/-0

...

config/crd/bases/rhtas.redhat.com_consoles.yaml


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 12, 2026

PR Reviewer Guide 🔍

(Review updated until commit bda35a1)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🔒 No security concerns identified
⚡ Recommended focus areas for review

📄 References
  1. No matching references available

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 12, 2026

PR Code Suggestions ✨

Latest suggestions up to bda35a1

CategorySuggestion                                                                                                                                    Impact
Possible issue
Prevent nil dereference crashes

Add a nil check for instance.Spec.Console before dereferencing it to prevent a
potential panic.

internal/controller/securesign/actions/ensure_console.go [39-69]

 func (i consoleAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Securesign) *action.Result {
+	if instance.Spec.Console == nil {
+		// Console not requested/configured; nothing to reconcile.
+		return i.Continue()
+	}
+
 	var (
 		err     error
 		result  controllerutil.OperationResult
 		l       = labels.For("console", instance.Name, instance.Name)
 		console = &rhtasv1alpha1.Console{
 			ObjectMeta: v1.ObjectMeta{
 				Name:      instance.Name,
 				Namespace: instance.Namespace,
 			},
 		}
 	)
 
 	if result, err = kubernetes.CreateOrUpdate(ctx, i.Client,
 		console,
 		ensure.ControllerReference[*rhtasv1alpha1.Console](instance, i.Client),
 		ensure.Labels[*rhtasv1alpha1.Console](slices.Collect(maps.Keys(l)), l),
 		ensure.Annotations[*rhtasv1alpha1.Console](annotations.InheritableAnnotations, instance.Annotations),
 		func(object *rhtasv1alpha1.Console) error {
 			object.Spec = *instance.Spec.Console
 			return nil
 		},
 	); err != nil {
 		return i.Error(ctx, fmt.Errorf("could not create Console: %w", err), instance,
 			v1.Condition{
 				Type:    ConsoleCondition,
 				Status:  v1.ConditionFalse,
 				Reason:  state.Failure.String(),
 				Message: err.Error(),
 			})
 	}
 ...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical bug where dereferencing a potentially nil instance.Spec.Console would cause the controller to panic and crash.

High
Correct DSN generation format

Correct the MySQL DSN string format in defaultDBData to
user:password@tcp(host:port)/db to prevent database connection failures.

internal/controller/console/actions/db/handle_secret.go [137-153]

 func (i handleSecretAction) defaultDBData() map[string][]byte {
-	// Define a new Secret object
 	var rootPass []byte
 	var mysqlPass []byte
 	rootPass = utils2.GeneratePassword(12)
 	mysqlPass = utils2.GeneratePassword(12)
-	dsn := fmt.Sprintf("mysql:%s@tcp(%s:%d)/%s", mysqlPass, host, port, databaseName)
+
+	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", user, mysqlPass, host, port, databaseName)
 	return map[string][]byte{
 		console.SecretRootPassword: rootPass,
 		console.SecretPassword:     mysqlPass,
 		console.SecretDatabaseName: []byte(databaseName),
 		console.SecretUser:         []byte(user),
 		console.SecretPort:         []byte(strconv.Itoa(port)),
 		console.SecretHost:         []byte(host),
 		console.SecretDsn:          []byte(dsn),
 	}
 }
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a bug in the MySQL DSN string format, which would cause database connection failures at runtime for the console API.

High
Return valid URL with scheme

Ensure the TUF URL returned by resolveTufUrl always includes a scheme (e.g.,
http://) to prevent curl failures in the init container.

internal/controller/console/actions/api/deployment.go [199-208]

 func (i deployAction) resolveTufUrl(instance *rhtasv1alpha1.Console) string {
 	if instance.Spec.Api.Tuf.Address != "" {
 		url := instance.Spec.Api.Tuf.Address
 		if instance.Spec.Api.Tuf.Port != nil {
 			url = fmt.Sprintf("%s:%d", url, *instance.Spec.Api.Tuf.Port)
 		}
+		if !slices.Contains([]string{"http://", "https://"}, url[:min(len(url), 8)]) && !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
+			url = "http://" + url
+		}
 		return url
 	}
 	return fmt.Sprintf("http://tuf.%s.svc", instance.Namespace)
 }
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies that the curl command in the init container will fail if a URL scheme is not provided, which is a valid bug that would prevent pod startup.

Medium
Guard against null in validation

Add a null check to the CEL validation for routeSelectorLabels to prevent
evaluation errors when the field is being set for the first time.

config/crd/bases/rhtas.redhat.com_consoles.yaml [2235-2242]

 routeSelectorLabels:
   additionalProperties:
     type: string
   description: Set Route Selector Labels for ingress sharding.
   type: object
   x-kubernetes-validations:
   - message: RouteSelectorLabels can't be modified
-    rule: (oldSelf.size() == 0 || self == oldSelf)
+    rule: (oldSelf == null || oldSelf.size() == 0 || self == oldSelf)
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a bug in the CEL validation rule that would cause an error when adding routeSelectorLabels to an existing resource, and provides a correct fix.

Medium
General
Clean up schema descriptions

Remove the Go code comments and struct definition from the description of the
pvc field in the CRD. This content is not part of the schema and can confuse
downstream tooling.

config/crd/bases/rhtas.redhat.com_securesigns.yaml [1171-1229]

 pvc:
   default:
     retain: true
     size: 5Gi
   description: |-
-    // Secret with values to be used to connect to an existing DB or to be used with the creation of a new DB
-    // mysql-host: The host of the MySQL server
-    // mysql-port: The port of the MySQL server
-    // mysql-user: The user to connect to the MySQL server
-    // mysql-password: The password to connect to the MySQL server
-    // mysql-database: The database to connect to
-    //+optional
-    DatabaseSecretRef *LocalObjectReference `json:"databaseSecretRef,omitempty"`
-    PVC configuration
+    PersistentVolumeClaim configuration for the Console database.
   properties:
     accessModes:
       default:
       - ReadWriteOnce
       description: PVC AccessModes
       items:
         enum:
         - ReadWriteOnce
         - ReadOnlyMany
         - ReadWriteMany
         - ReadWriteOncePod
         type: string
       minItems: 1
       type: array
     name:
       description: Name of the PVC
       maxLength: 253
       minLength: 1
       pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
       type: string
     retain:
       default: true
       description: Retain policy for the PVC
       type: boolean
       x-kubernetes-validations:
       - message: Field is immutable
         rule: (self == oldSelf)
     size:
       anyOf:
       - type: integer
       - type: string
       default: 5Gi
       description: |-
         The requested size of the persistent volume attached to Pod.
         The format of this field matches that defined by kubernetes/apimachinery.
         See https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity for more info on the format of this field.
       pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
       x-kubernetes-int-or-string: true
     storageClass:
       description: The name of the StorageClass to claim a PersistentVolume
         from.
       type: string
   required:
   - retain
   type: object
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies that the description for the pvc field contains Go code comments and struct definitions, which is inappropriate for a CRD schema and improves the API's clarity.

Low
Fix sample YAML formatting

Remove the trailing whitespace-only line from the sample manifest. This change
addresses a formatting issue that could cause problems with some YAML tools and
CI checks.

config/samples/rhtas_v1alpha1_securesign.yaml [74-80]

  • Apply / Chat
Suggestion importance[1-10]: 2

__

Why: This is a minor but correct formatting suggestion to remove a trailing whitespace-only line, which improves code style and prevents potential issues with YAML parsing tools.

Low
  • More

Previous suggestions

Suggestions up to commit bda35a1
CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix incorrect controller test suite

Update the test suite in console_controller_test.go to test the Console
controller instead of the Trillian controller, as it appears to be an incorrect
copy-paste.

internal/controller/console/console_controller_test.go [41-103]

-var _ = Describe("Trillian controller", func() {
-	Context("Trillian controller test", func() {
+var _ = Describe("Console controller", func() {
+	Context("Console controller test", func() {
 ...
-		trillian := &v1alpha1.Trillian{}
+		console := &v1alpha1.Console{}
 ...
-		It("should successfully reconcile a custom resource for Trillian", func() {
-			By("creating the custom resource for the Kind Trillian")
-			err := suite.Client().Get(ctx, typeNamespaceName, trillian)
+		It("should successfully reconcile a custom resource for Console", func() {
+			By("creating the custom resource for the Kind Console")
+			err := suite.Client().Get(ctx, typeNamespaceName, console)
 			if err != nil && errors.IsNotFound(err) {
 				// Let's mock our custom resource at the same way that we would
 				// apply on the cluster the manifest under config/samples
-				trillian := &v1alpha1.Trillian{
+				console := &v1alpha1.Console{
 					ObjectMeta: metav1.ObjectMeta{
 						Name:      Name,
 						Namespace: Namespace,
 					},
-					Spec: v1alpha1.TrillianSpec{
-						Db: v1alpha1.TrillianDB{
-							Create: utils.Pointer(true),
-						},
+					Spec: v1alpha1.ConsoleSpec{
+						Enabled: true,
 					},
 				}
 ...
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies that the entire test suite for the new console controller was copied from the Trillian controller and not adapted, leaving the new component without any test coverage.

High
Include user in DSN string

Fix the DSN connection string in defaultDBData by including the user variable,
as it is currently missing.

internal/controller/console/actions/db/handle_secret.go [137-153]

 func (i handleSecretAction) defaultDBData() map[string][]byte {
 	// Define a new Secret object
 	var rootPass []byte
 	var mysqlPass []byte
 	rootPass = utils2.GeneratePassword(12)
 	mysqlPass = utils2.GeneratePassword(12)
-	dsn := fmt.Sprintf("mysql:%s@tcp(%s:%d)/%s", mysqlPass, host, port, databaseName)
+	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", user, mysqlPass, host, port, databaseName)
 	return map[string][]byte{
 		console.SecretRootPassword: rootPass,
 		console.SecretPassword:     mysqlPass,
 		console.SecretDatabaseName: []byte(databaseName),
 		console.SecretUser:         []byte(user),
 		console.SecretPort:         []byte(strconv.Itoa(port)),
 		console.SecretHost:         []byte(host),
 		console.SecretDsn:          []byte(dsn),
 	}
 }
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies that the DSN string is malformed because it omits the username, which would cause database connection failures.

Medium
Add missing secret‐ref property

Define a databaseSecretRef property under pvc.properties to replace the Go-style
declaration in the description, enabling schema validation for the secret
reference.

config/crd/bases/rhtas.redhat.com_consoles.yaml [1151-1164]

 pvc:
-  description: |-
-    // Secret with values to be used to connect to an existing DB or to be used with the creation of a new DB
-    // mysql-host: The host of the MySQL server
-    // mysql-port: The port of the MySQL server
-    // mysql-user: The user to connect to the MySQL server
-    // mysql-password: The password to connect to the MySQL server
-    // mysql-database: The database to connect to
-    //+optional
-    DatabaseSecretRef *LocalObjectReference `json:"databaseSecretRef,omitempty"`
+  properties:
+    databaseSecretRef:
+      description: Reference to an existing database secret
+      type: object
+      properties:
+        name:
+          description: Name of the secret to use for database connection
+          type: string
+      required:
+        - name
+  description: >-
     PVC configuration
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that a databaseSecretRef is mentioned in comments but not defined in the schema, and fixing this improves the CRD's structural correctness and enables validation.

Medium
Enforce consistent TLS configuration validation

Add a validation rule to ensure that if privateKeyRef is specified,
certificateRef must also be present, and improve the validation messages for
clarity.

config/crd/bases/rhtas.redhat.com_consoles.yaml [1078-1080]

 x-kubernetes-validations:
-- message: privateKeyRef cannot be empty
+- message: privateKeyRef must be provided when certificateRef is provided
   rule: (!has(self.certificateRef) || has(self.privateKeyRef))
+- message: certificateRef must be provided when privateKeyRef is provided
+  rule: (!has(self.privateKeyRef) || has(self.certificateRef))
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies an incomplete validation rule for TLS configuration and proposes a fix that makes the CRD schema more robust by enforcing mutual presence of certificate and private key references.

Low
Remove Go code from YAML

Replace the Go code in the description field for spec.console.database.pvc with
a proper human-readable explanation.

config/crd/bases/rhtas.redhat.com_securesigns.yaml [1175-1184]

 description: |-
-  // Secret with values to be used to connect to an existing DB or to be used with the creation of a new DB
-  // mysql-host: The host of the MySQL server
-  // mysql-port: The port of the MySQL server
-  // mysql-user: The user to connect to the MySQL server
-  // mysql-password: The password to connect to the MySQL server
-  // mysql-database: The database to connect to
-  //+optional
-  DatabaseSecretRef *LocalObjectReference `json:"databaseSecretRef,omitempty"`
-  PVC configuration
+  Configuration for the PersistentVolumeClaim (PVC) used by the database.
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies Go code mistakenly placed in a YAML description field, and the proposed fix improves the CRD's clarity and correctness.

Low
General
Enforce strict schema validation

Add preserveUnknownFields: false to the openAPIV3Schema to enforce strict
validation and reject undeclared fields in the custom resource.

config/crd/bases/rhtas.redhat.com_consoles.yaml [8-24]

 spec:
   versions:
   - name: v1alpha1
     schema:
       openAPIV3Schema:
+        preserveUnknownFields: false
         description: Console is the Schema for the consoles API
         properties:
           apiVersion:
             ...
Suggestion importance[1-10]: 7

__

Why: This suggestion correctly recommends setting preserveUnknownFields: false which is a best practice for CRDs to enforce strict schema validation and prevent unknown fields, improving the CRD's robustness.

Medium
Dynamically construct the API URL

Replace the hardcoded CONSOLE_API_URL with a dynamically constructed URL that
accounts for the service name, port, and whether TLS is enabled.

internal/controller/console/actions/ui/deployment.go [135-136]

 		apiUrlEnv := kubernetes.FindEnvByNameOrCreate(container, "CONSOLE_API_URL")
-		apiUrlEnv.Value = "http://console-api:8080" // TODO
+		scheme := "http"
+		if instance.Spec.Api.TLS.CertRef != nil || (kubernetes.IsOpenShift() && instance.Spec.Api.TLS.CertRef == nil) {
+			scheme = "https"
+		}
+		apiUrlEnv.Value = fmt.Sprintf("%s://%s:%d", scheme, actions.ApiDeploymentName, actions.ApiServerPort)
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly points out a hardcoded URL marked with a TODO and provides a robust solution to construct it dynamically, improving configurability and handling TLS correctly.

Low
Remove debug print statements

Remove the debugging fmt.Println statements from the CanHandle and Handle
functions.

internal/controller/console/actions/ui/service.go [38-49]

 func (i createServiceAction) CanHandle(ctx context.Context, instance *rhtasv1alpha1.Console) bool {
-	fmt.Println("***********-------- INSIDE UI SERVICE CanHandle")
 	return instance.Spec.Enabled && state.FromInstance(instance, constants.ReadyCondition) >= state.Creating
 }
 
 func (i createServiceAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Console) *action.Result {
-	fmt.Println("***********-------- INSIDE UI SERVICE Handle")
 	var (
 		err    error
 		result controllerutil.OperationResult
 	)
 	// ...
 }
Suggestion importance[1-10]: 4

__

Why: The suggestion correctly identifies and proposes the removal of leftover debugging fmt.Println statements, which is a good practice for code cleanliness and production readiness.

Low

@fghanmi
Copy link
Member Author

fghanmi commented Mar 12, 2026

/review

@qodo-code-review
Copy link

Persistent review updated to latest commit bda35a1

Comment on lines +57 to +60
func(object *rhtasv1alpha1.Console) error {
object.Spec = *instance.Spec.Console
return nil
},

Choose a reason for hiding this comment

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

Action required

1. Nil consolespec deref 🐞 Bug ⛯ Reliability

consoleAction.Handle dereferences instance.Spec.Console without a nil-check even though
SecuresignSpec.Console is optional, causing a panic when spec.console is omitted. This crashes
reconciliation for Securesign resources.
Agent Prompt
### Issue description
`internal/controller/securesign/actions/ensure_console.go` dereferences `instance.Spec.Console` without checking for nil even though the field is optional, which can panic the controller.

### Issue Context
`SecuresignSpec.Console` is `*ConsoleSpec` with `json:"console,omitempty"`, so manifests may omit it.

### Fix Focus Areas
- internal/controller/securesign/actions/ensure_console.go[35-66]

### Implementation notes
- Change `CanHandle` to `return instance.Spec.Console != nil` (and optionally also check `instance.Spec.Console.Enabled`).
- Or in `Handle`, add:
  - `if instance.Spec.Console == nil { /* set ConsoleCondition NotDefined/Disabled and Continue */ }`
  - only assign `object.Spec = *instance.Spec.Console` when non-nil.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +84 to +97
func (i consoleAction) CopyStatus(ctx context.Context, object *rhtasv1alpha1.Console, instance *rhtasv1alpha1.Securesign) *action.Result {
objectStatus := meta.FindStatusCondition(object.Status.Conditions, constants.ReadyCondition)
if objectStatus == nil {
// not initialized yet, wait for update
return i.Continue()
}
if meta.FindStatusCondition(instance.Status.Conditions, ConsoleCondition).Reason != objectStatus.Reason {
meta.SetStatusCondition(&instance.Status.Conditions, v1.Condition{
Type: ConsoleCondition,
Status: objectStatus.Status,
Reason: objectStatus.Reason,
})
return i.StatusUpdate(ctx, instance)
}

Choose a reason for hiding this comment

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

Action required

2. Nil condition deref 🐞 Bug ⛯ Reliability

consoleAction.CopyStatus dereferences meta.FindStatusCondition(...).Reason without a nil-check,
which can panic if ConsoleCondition is missing from Securesign status. This can crash reconciliation
while syncing Console status.
Agent Prompt
### Issue description
`CopyStatus` can panic by accessing `.Reason` on a nil condition pointer returned by `meta.FindStatusCondition`.

### Issue Context
`meta.FindStatusCondition` returns `*Condition` and may return nil when the condition is absent.

### Fix Focus Areas
- internal/controller/securesign/actions/ensure_console.go[84-97]

### Implementation notes
- Replace the direct deref with:
  - `current := meta.FindStatusCondition(instance.Status.Conditions, ConsoleCondition)`
  - if `current == nil` then set the condition (or treat as different) and `StatusUpdate`.
  - otherwise compare `current.Reason`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +112 to +131
initContainer := kubernetes.FindInitContainerByNameOrCreate(&template.Spec, "wait-for-console-db-tuf")
initContainer.Image = images.Registry.Get(images.ConsoleDb)

initContainer.Command = []string{
"/bin/sh",
"-c",
fmt.Sprintf(`
echo "Waiting for rekor-server...";
until mysqladmin ping -h%s --silent > /dev/null 2>&1; do
echo "Waiting for the console database to be ready...";
sleep 5;
done;
echo "Waiting for TUF server...";
until curl %s > /dev/null 2>&1; do
echo "TUF server not ready...";
sleep 5;
done;
echo "tuf-init completed."
`, actions.DbDeploymentName, tufServerHost),
}

Choose a reason for hiding this comment

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

Action required

3. Tuf url shell injection 🐞 Bug ⛨ Security

Console API deployment initContainer builds a /bin/sh -c script by interpolating
spec.api.tuf.address into a curl command, enabling shell command injection via crafted addresses.
This allows arbitrary command execution in the initContainer when a user can create/patch the
Console resource.
Agent Prompt
### Issue description
The initContainer uses `/bin/sh -c` with a `fmt.Sprintf` script that directly embeds `spec.api.tuf.address`, allowing shell injection.

### Issue Context
`resolveTufUrl()` returns the raw user-provided address and it is inserted into `until curl %s ...`.

### Fix Focus Areas
- internal/controller/console/actions/api/deployment.go[112-131]
- internal/controller/console/actions/api/deployment.go[199-208]

### Implementation notes
Prefer one of:
1) Remove the shell and use an exec-form command that cannot be injected:
   - e.g. run a small loop script where the URL is read from an env var but always referenced as `"$TUF_URL"`.
2) Strictly validate `spec.api.tuf.address` with `net/url` and reject anything not `http/https` and containing whitespace/control characters.
3) If keeping shell, pass URL via env var and always quote it: `curl -sf "${TUF_URL}"`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +32 to +35
const (
livenessCommand = "mariadb-admin -u ${MYSQL_USER} -p${MYSQL_PASSWORD} ping"
readinessCommand = "mariadb -u ${MYSQL_USER} -p${MYSQL_PASSWORD} -e \"SELECT 1;\""
)

Choose a reason for hiding this comment

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

Action required

4. Unquoted password breaks probes 🐞 Bug ⛯ Reliability

DB readiness/liveness probes run bash -c commands that include unquoted ${MYSQL_PASSWORD}, while
generated passwords include shell metacharacters like '&' and '$'. This can make probes fail
unpredictably and keep the DB pod unready or restart-looping.
Agent Prompt
### Issue description
The DB probes execute `bash -c` with unquoted `${MYSQL_PASSWORD}`; since generated passwords include characters like `&` and `$`, probes can break and cause restart loops.

### Issue Context
`GeneratePassword()` includes `!@#$%&*`, and probes use `bash -c`.

### Fix Focus Areas
- internal/controller/console/actions/db/deployment.go[32-35]
- internal/controller/console/actions/db/deployment.go[194-212]

### Implementation notes
- Update probe command strings to quote variables, e.g. `-p"${MYSQL_PASSWORD}"`.
- Prefer using an exec-form probe without a shell if possible (e.g., `[]string{"mariadb-admin","-u","$(MYSQL_USER)","-p$(MYSQL_PASSWORD)","ping"}` is still expansion-dependent; the safest is a small wrapper script with strict quoting).
- Optionally, constrain generated passwords to a shell-safe charset if you must keep `bash -c` probes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@fghanmi fghanmi closed this Mar 12, 2026
@fghanmi fghanmi reopened this Mar 18, 2026
@fghanmi
Copy link
Member Author

fghanmi commented Mar 18, 2026

/agentic_describe --pr_description.final_update_message=false

@qodo-code-review
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

The generated DSN format looks incorrect: it appears to place the generated MySQL password where the username should be, and does not include the username explicitly. This may lead to broken DB connectivity for the API (and anything else consuming the DSN secret) and should be validated against the intended DSN format for the driver in use.

func (i handleSecretAction) defaultDBData() map[string][]byte {
	// Define a new Secret object
	var rootPass []byte
	var mysqlPass []byte
	rootPass = utils2.GeneratePassword(12)
	mysqlPass = utils2.GeneratePassword(12)
	dsn := fmt.Sprintf("mysql:%s@tcp(%s:%d)/%s", mysqlPass, host, port, databaseName)
	return map[string][]byte{
		console.SecretRootPassword: rootPass,
		console.SecretPassword:     mysqlPass,
		console.SecretDatabaseName: []byte(databaseName),
		console.SecretUser:         []byte(user),
		console.SecretPort:         []byte(strconv.Itoa(port)),
		console.SecretHost:         []byte(host),
		console.SecretDsn:          []byte(dsn),
	}
Nil Dereference

The deployment setup reads instance.Status.DatabaseSecretRef.Name without guarding for a nil DatabaseSecretRef. If reconciliation reaches this action before the secret action sets status, this can panic. Consider adding an explicit nil check and returning a reconcile error/condition that waits for the DB secret to exist.

func (i deployAction) ensureAPIDeployment(instance *rhtasv1alpha1.Console, sa string, labels map[string]string,
) func(*apps.Deployment) error {

	return func(dp *apps.Deployment) error {
		tufServerHost := i.resolveTufUrl(instance)

		spec := &dp.Spec
		spec.Selector = &metav1.LabelSelector{
			MatchLabels: labels,
		}

		replicas := int32(1)
		spec.Replicas = &replicas

		template := &spec.Template
		template.Labels = labels
		template.Spec.ServiceAccountName = sa

		initContainer := kubernetes.FindInitContainerByNameOrCreate(&template.Spec, "wait-for-console-db-tuf")
		initContainer.Image = images.Registry.Get(images.ConsoleDb)

		initContainer.Command = []string{
			"/bin/sh",
			"-c",
			fmt.Sprintf(`
                echo "Waiting for rekor-server...";
                until mysqladmin ping -h%s --silent > /dev/null 2>&1; do
                    echo "Waiting for the console database to be ready...";
                    sleep 5;
                done;
                echo "Waiting for TUF server...";
                until curl %s > /dev/null 2>&1; do
                    echo "TUF server not ready...";
                    sleep 5;
                done;
                echo "tuf-init completed."
            `, actions.DbDeploymentName, tufServerHost),
		}

		container := kubernetes.FindContainerByNameOrCreate(&template.Spec, actions.ApiDeploymentName)
		container.Image = images.Registry.Get(images.ConsoleApi)

		tufRepoUrlEnv := kubernetes.FindEnvByNameOrCreate(container, "TUF_REPO_URL")
		tufRepoUrlEnv.Value = tufServerHost

		dsnEnv := kubernetes.FindEnvByNameOrCreate(container, "DB_DSN")
		dsnEnv.ValueFrom = &core.EnvVarSource{
			SecretKeyRef: &core.SecretKeySelector{
				Key: actions.SecretDsn,
				LocalObjectReference: core.LocalObjectReference{
					Name: instance.Status.DatabaseSecretRef.Name,
				},
			},
		}

		userEnv := kubernetes.FindEnvByNameOrCreate(container, "MYSQL_USER")
		userEnv.ValueFrom = &core.EnvVarSource{
			SecretKeyRef: &core.SecretKeySelector{
				Key: actions.SecretUser,
				LocalObjectReference: core.LocalObjectReference{
					Name: instance.Status.DatabaseSecretRef.Name,
				},
			},
		}

		passwordEnv := kubernetes.FindEnvByNameOrCreate(container, "MYSQL_PASSWORD")
		passwordEnv.ValueFrom = &core.EnvVarSource{
			SecretKeyRef: &core.SecretKeySelector{
				Key: actions.SecretPassword,
				LocalObjectReference: core.LocalObjectReference{
					Name: instance.Status.DatabaseSecretRef.Name,
				},
			},
		}
Debug Logging

Direct stdout logging via fmt.Println was added in CanHandle/Handle. This is noisy in controllers, bypasses structured logging, and can affect test output. Prefer using the injected logger (i.Logger) at an appropriate verbosity, or remove these statements entirely.

func (i createServiceAction) CanHandle(ctx context.Context, instance *rhtasv1alpha1.Console) bool {
	fmt.Println("***********-------- INSIDE UI SERVICE CanHandle")
	return instance.Spec.Enabled && state.FromInstance(instance, constants.ReadyCondition) >= state.Creating
}

func (i createServiceAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Console) *action.Result {

	fmt.Println("***********-------- INSIDE UI SERVICE Handle")
	var (
📄 References
  1. No matching references available

@fghanmi
Copy link
Member Author

fghanmi commented Mar 18, 2026

/improve

@qodo-code-review
Copy link

Persistent suggestions updated to latest commit bda35a1

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix incorrect resource type in tests

Update the test file to use v1alpha1.Console resources instead of
v1alpha1.Trillian resources to correctly test the Console controller's
functionality.

internal/controller/console/console_controller_test.go [68-75]

-		By("removing the custom resource for the Kind Trillian")
-		found := &v1alpha1.Trillian{}
+		By("removing the custom resource for the Kind Console")
+		found := &v1alpha1.Console{}
 		err := suite.Client().Get(ctx, typeNamespaceName, found)
 		Expect(err).To(Not(HaveOccurred()))
 
 		Eventually(func() error {
 			return suite.Client().Delete(context.TODO(), found)
 		}, 2*time.Minute, time.Second).Should(Succeed())
  • Apply / Chat
Suggestion importance[1-10]: 10

__

Why: The suggestion correctly identifies that the entire test file was copy-pasted and incorrectly references Trillian resources instead of Console resources, rendering the tests for the new controller completely invalid.

High
Fix incorrect shell command in probes

Fix the liveness and readiness probe commands by correctly placing the --ssl
flag within the shell command string, ensuring it is passed to the mariadb and
mariadb-admin clients.

internal/controller/console/actions/db/deployment.go [232-241]

-		container.ReadinessProbe.Exec.Command = []string{"bash", "-c", readinessCommand + " --ssl"}
+		container.ReadinessProbe.Exec.Command = []string{"bash", "-c", "mariadb --ssl -u ${MYSQL_USER} -p${MYSQL_PASSWORD} -e \"SELECT 1;\""}
 
 ...
 
-		container.LivenessProbe.Exec.Command = []string{"bash", "-c", livenessCommand + " --ssl"}
+		container.LivenessProbe.Exec.Command = []string{"bash", "-c", "mariadb-admin --ssl -u ${MYSQL_USER} -p${MYSQL_PASSWORD} ping"}

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a shell command construction bug where the --ssl flag would be passed to bash instead of the mariadb client, causing the probes to fail and making the deployment appear unhealthy.

High
correct DSN user:password order

Correct the DSN string format in defaultDBData to include the username, ensuring
the format is user:password@....

internal/controller/console/actions/db/handle_secret.go [137-153]

 func (i handleSecretAction) defaultDBData() map[string][]byte {
     // Define a new Secret object
     var rootPass []byte
     var mysqlPass []byte
     rootPass = utils2.GeneratePassword(12)
     mysqlPass = utils2.GeneratePassword(12)
-    dsn := fmt.Sprintf("mysql:%s@tcp(%s:%d)/%s", mysqlPass, host, port, databaseName)
+    dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", user, mysqlPass, host, port, databaseName)
     return map[string][]byte{
         console.SecretRootPassword: rootPass,
         console.SecretPassword:     mysqlPass,
         console.SecretDatabaseName: []byte(databaseName),
         console.SecretUser:         []byte(user),
         console.SecretPort:         []byte(strconv.Itoa(port)),
         console.SecretHost:         []byte(host),
         console.SecretDsn:          []byte(dsn),
     }
 }
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a bug in the DSN string format, which would cause database connection failures, and provides the correct format.

High
Add missing database secret reference

Add the missing databaseSecretRef field to spec.console.database.properties and
correct the malformed pvc description to allow configuration of an external
database.

config/crd/bases/rhtas.redhat.com_securesigns.yaml [1153-1287]

 ...
               database:
                 default:
                   create: true
                   pvc:
                     accessModes:
                     - ReadWriteOnce
                     retain: true
                     size: 5Gi
                 description: Define your database connection
                 properties:
                   create:
                     default: true
                     description: Create Database if a database is not created
                       one must be defined using the DatabaseSecret field
                     type: boolean
                     x-kubernetes-validations:
                     - message: Field is immutable
                       rule: (self == oldSelf)
+                  databaseSecretRef:
+                    description: |-
+                      Secret with values to be used to connect to an existing DB.
+                      The secret must contain the following keys:
+                      mysql-host, mysql-port, mysql-user, mysql-password, mysql-database.
+                    properties:
+                      name:
+                        description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
+                        type: string
+                    type: object
+                    x-kubernetes-map-type: atomic
                   pvc:
                     default:
                       retain: true
                       size: 5Gi
-                    description: |-
-                      // Secret with values to be used to connect to an existing DB or to be used with the creation of a new DB
-                      // mysql-host: The host of the MySQL server
-                      // mysql-port: The port of the MySQL server
-                      // mysql-user: The user to connect to the MySQL server
-                      // mysql-password: The password to connect to the MySQL server
-                      // mysql-database: The database to connect to
-                      //+optional
-                      DatabaseSecretRef *LocalObjectReference `json:"databaseSecretRef,omitempty"`
-                      PVC configuration
+                    description: PVC configuration for the database.
                     properties:
                       accessModes:
 ...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a functional gap where a user cannot specify an external database, despite an option to disable automatic creation, and it also points out a confusing, malformed description.

High
require secret and PVC before deploy

Update the CanHandle function for the database deployment action to ensure it
only proceeds after the database secret and PVC have been created.

internal/controller/console/actions/db/deployment.go [49-51]

 func (i deployAction) CanHandle(ctx context.Context, instance *rhtasv1alpha1.Console) bool {
-    return enabled(instance) && state.FromInstance(instance, constants.ReadyCondition) >= state.Creating
+    return enabled(instance) &&
+           state.FromInstance(instance, constants.ReadyCondition) >= state.Creating &&
+           instance.Status.DatabaseSecretRef != nil &&
+           instance.Status.Db.Pvc.Name != ""
 }
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies that the deployment action can run before its dependencies (secret and PVC) are ready, which would cause a failure, and proposes adding the necessary checks to prevent this race condition.

Medium
Fix missing database secret reference

Add the missing databaseSecretRef field under spec.database.properties to allow
specifying an external database. Also, correct the descriptions for
spec.database.create and spec.database.pvc which are currently incorrect and
misleading.

config/crd/bases/rhtas.redhat.com_consoles.yaml [1133-1265]

                   database:
                 default:
                   create: true
                   pvc:
                     accessModes:
                     - ReadWriteOnce
                     retain: true
                     size: 5Gi
             description: Define your database connection
                 properties:
                   create:
                     default: true
                 description: Create Database if a database is not created one
-                      must be defined using the DatabaseSecret field
+                      must be defined using the databaseSecretRef field
                     type: boolean
                     x-kubernetes-validations:
                     - message: Field is immutable
                       rule: (self == oldSelf)
+                  databaseSecretRef:
+                description: |-
+                      Secret with values to be used to connect to an existing DB or to be used with the creation of a new DB.
+                      The secret must contain the following keys:
+                      mysql-host: The host of the MySQL server
+                      mysql-port: The port of the MySQL server
+                      mysql-user: The user to connect to the MySQL server
+                      mysql-password: The password to connect to the MySQL server
+                      mysql-database: The database to connect to
+                    properties:
+                      name:
+                    description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
+                        type: string
+                    type: object
                   pvc:
                     default:
                       retain: true
                       size: 5Gi
-                description: |-
-                      // Secret with values to be used to connect to an existing DB or to be used with the creation of a new DB
-                      // mysql-host: The host of the MySQL server
-                      // mysql-port: The port of the MySQL server
-                      // mysql-user: The user to connect to the MySQL server
-                      // mysql-password: The password to connect to the MySQL server
-                      // mysql-database: The database to connect to
-                      //+optional
-                      DatabaseSecretRef *LocalObjectReference `json:"databaseSecretRef,omitempty"`
-                      PVC configuration
+                description: PVC configuration for the database.
                     properties:
 ...
                 required:
                 - create
                 type: object

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a major flaw in the CRD where specifying an external database is impossible, despite being an intended feature. It also points out and corrects a misplaced Go code snippet in a description field, significantly improving the CRD's correctness and usability.

Medium
Improve TLS configuration validation rule

Update the TLS validation rule for spec.api.tls and spec.database.tls to be
symmetric, ensuring both certificateRef and privateKeyRef are provided together.
Also, correct the "manged service" typo in the description.

config/crd/bases/rhtas.redhat.com_consoles.yaml [1035-1080]

                       tls:
                 description: Configuration for enabling TLS (Transport Layer Security)
-                      encryption for manged service.
+                      encryption for managed service.
                     properties:
                       certificateRef:
                     description: Reference to the certificate secret used for
                           TLS encryption.
                         properties:
                           key:
                         description: The key of the secret to select from. Must
                               be a valid secret key.
                             pattern: ^[-._a-zA-Z0-9]+$
                             type: string
                           name:
                         description: |-
                               Name of the referent.
                               More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                             type: string
                         required:
                         - key
                         - name
                         type: object
                         x-kubernetes-map-type: atomic
                       privateKeyRef:
                     description: Reference to the private key secret used for
                           TLS encryption.
                         properties:
                           key:
                         description: The key of the secret to select from. Must
                               be a valid secret key.
                             pattern: ^[-._a-zA-Z0-9]+$
                             type: string
                           name:
                         description: |-
                               Name of the referent.
                               More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                             type: string
                         required:
                         - key
                         - name
                         type: object
                         x-kubernetes-map-type: atomic
                     type: object
                     x-kubernetes-validations:
-                    - message: privateKeyRef cannot be empty
-                      rule: (!has(self.certificateRef) || has(self.privateKeyRef))
+                    - message: Both certificateRef and privateKeyRef must be provided
+                      rule: (has(self.certificateRef) == has(self.privateKeyRef))

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies an incomplete validation rule for TLS configuration and a typo in a description. The proposed change to (has(self.certificateRef) == has(self.privateKeyRef)) is a more robust and correct way to ensure both certificate and private key are provided together.

Low
Security
mount TLS secret into pod

In the ensureTLS function, add logic to mount the TLS secret as a volume into
the database container, making the certificate and key files available at the
specified paths.

internal/controller/console/actions/db/deployment.go [217-261]

 func (i deployAction) ensureTLS(tlsConfig rhtasv1alpha1.TLS) func(deployment *v2.Deployment) error {
     return func(dp *v2.Deployment) error {
         if err := deployment.TLS(tlsConfig, actions.DbDeploymentName)(dp); err != nil {
             return err
         }
 
+        // mount TLS secret
+        volume := kubernetes.FindVolumeByNameOrCreate(&dp.Spec.Template.Spec, "tls-secret")
+        volume.Secret = &v1.SecretVolumeSource{SecretName: tlsConfig.CertRef.Name}
+
         container := kubernetes.FindContainerByNameOrCreate(&dp.Spec.Template.Spec, actions.DbDeploymentName)
+        volumeMount := kubernetes.FindVolumeMountByNameOrCreate(container, "tls-secret")
+        volumeMount.MountPath = path.Dir(tls.TLSCertPath)
+
         ...
         if i := slices.Index(container.Args, "--ssl-key"); i == -1 {
             container.Args = append(container.Args, "--ssl-key", tls.TLSKeyPath)
         } else {
             ...
         }
         return nil
     }
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 10

__

Why: The suggestion identifies a critical omission where the TLS secret was referenced in container arguments but not mounted into the pod, which would cause the container to fail to start.

High
General
Refine logic for handling database secrets

Refactor the CanHandle logic for the database secret action to only run if
instance.Status.DatabaseSecretRef is nil, preventing unintended modifications to
existing secret configurations.

internal/controller/console/actions/db/handle_secret.go [58-65]

 func (i handleSecretAction) CanHandle(_ context.Context, instance *rhtasv1alpha1.Console) bool {
-	switch {
-	case instance.Status.DatabaseSecretRef == nil:
-		return true
-	default:
-		return !meta.IsStatusConditionTrue(instance.GetConditions(), console.DbCondition)
-	}
+	return instance.Status.DatabaseSecretRef == nil
 }
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a logic flaw in CanHandle that could lead to unintended recreation of database secrets, which is a significant bug, and proposes a correct and safer implementation.

Medium
Enforce host DNS validation

Add a regex pattern to the spec.ui.externalAccess.host field to validate that it
is a proper DNS hostname.

config/crd/bases/rhtas.redhat.com_consoles.yaml [2232-2234]

 host:
   description: Set hostname for your Ingress/Route.
   type: string
+  pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: This suggestion improves the CRD by adding a validation pattern for the host field, which helps prevent invalid hostnames and improves configuration robustness.

Low
High-level
Refactor duplicated component management logic

Abstract the duplicated management logic for the new UI, API, and DB
sub-components into generic, reusable actions. This will reduce code redundancy
and improve maintainability.

Examples:

internal/controller/console/actions/api/initialize.go [33-55]
func (i initializeAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Console) *action.Result {
	labels := labels.ForComponent(actions.ApiComponentName, instance.Name)
	ok, err := commonUtils.DeploymentIsRunning(ctx, i.Client, instance.Namespace, labels)
	switch {
	case errors.Is(err, commonUtils.ErrDeploymentNotReady):
		i.Logger.Info("deployment is not ready", "error", err.Error())
	case err != nil:
		return i.Error(ctx, err, instance)
	}
	if !ok {

 ... (clipped 13 lines)
internal/controller/console/actions/ui/initialize.go [33-56]
func (i initializeAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Console) *action.Result {
	labels := labels.ForComponent(actions.UIComponentName, instance.Name)
	ok, err := commonUtils.DeploymentIsRunning(ctx, i.Client, instance.Namespace, labels)
	switch {
	case errors.Is(err, commonUtils.ErrDeploymentNotReady):
		i.Logger.Info("deployment is not ready", "error", err.Error())
	case err != nil:
		return i.Error(ctx, err, instance)
	}
	if !ok {

 ... (clipped 14 lines)

Solution Walkthrough:

Before:

// internal/controller/console/actions/api/initialize.go
func (i initializeAction) Handle(ctx, instance) *action.Result {
  labels := labels.ForComponent(actions.ApiComponentName, instance.Name)
  ok, err := commonUtils.DeploymentIsRunning(ctx, i.Client, instance.Namespace, labels)
  // ... error handling ...
  if !ok {
    meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{
      Type:    actions.ApiCondition,
      Reason:  state.Initialize.String(),
      // ...
    })
    return i.StatusUpdate(ctx, instance)
  }
  meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{Type: actions.ApiCondition, Status: metav1.ConditionTrue, Reason: state.Ready.String()})
  return i.StatusUpdate(ctx, instance)
}

// internal/controller/console/actions/ui/initialize.go is nearly identical

After:

// internal/controller/console/actions/common/initialize.go
func NewInitializeAction(componentName, conditionType string) action.Action[*rhtasv1alpha1.Console] {
  // ... return a new generic initializeAction
}

type initializeAction struct {
  // ... fields for componentName, conditionType
}

func (i initializeAction) Handle(ctx, instance) *action.Result {
  labels := labels.ForComponent(i.componentName, instance.Name)
  ok, err := commonUtils.DeploymentIsRunning(ctx, i.Client, instance.Namespace, labels)
  // ... error handling ...
  if !ok {
    meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{
      Type:    i.conditionType,
      Reason:  state.Initialize.String(),
      // ...
    })
    return i.StatusUpdate(ctx, instance)
  }
  meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{Type: i.conditionType, Status: metav1.ConditionTrue, Reason: state.Ready.String()})
  return i.StatusUpdate(ctx, instance)
}
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies significant code duplication across the new UI, API, and DB component actions, and addressing it would substantially improve code quality and future maintainability.

Medium
  • More

@fghanmi
Copy link
Member Author

fghanmi commented Mar 18, 2026

/agentic_improve

@fghanmi
Copy link
Member Author

fghanmi commented Mar 18, 2026

/config

@qodo-code-review
Copy link

🛠️ Wiki configuration file settings:

🛠️ Local configuration file settings:
 [config]
git_provider="github"
ignore_pr_authors =REDACTED

[jira]
jira_api_token =REDACTED
jira_base_url = "https://issues.redhat.com"

[github_app]
handle_pr_actions = ['opened', 'reopened', 'ready_for_review']

# What runs automatically when PR is opened
pr_commands = [
    "/describe --pr_description.final_update_message=false",
    "/review",
    "/improve"
]

# Do NOT auto-trigger on push (avoid noise)
handle_push_trigger = false

# If you later want re-review on new commits, enable:
# handle_push_trigger = true
# push_commands = ["/review"]

[pr_reviewer] # /review #
persistent_comment = true
require_tests_review = false
require_security_review = true
require_ticket_analysis_review = true
require_estimate_effort_to_review = true
require_can_be_split_review = false
enable_review_labels_security = true
enable_review_labels_effort = true
final_update_message = true

[pr_description] # /describe #
publish_labels = true
add_original_user_description = false
generate_ai_title = false
use_bullet_points = true
enable_pr_type = true # Enhancement, Feature, Documentation,...
enable_pr_diagram = false
publish_description_as_comment = true
publish_description_as_comment_persistent = true
final_update_message = true
enable_help_text = false

[pr_code_suggestions]
commitable_code_suggestions = false
persistent_comment = true

[rag_arguments]
enable_rag=true

🛠️ Global configuration file settings:

🛠️ PR-Agent final configurations:
==================== CONFIG ====================
config.pr_compliance = {'ENABLE_RULES_PLATFORM': True}  
config.model_reasoning = 'vertex_ai/gemini-2.5-pro'  
config.model = 'openai/gpt-5.2'  
config.model_turbo = 'anthropic/claude-haiku-4-5-20251001'  
config.fallback_models = ['anthropic/claude-sonnet-4-6', 'openai/gpt-5.2', 'bedrock/us.anthropic.claude-sonnet-4-6']  
config.second_model_for_exhaustive_mode = 'o4-mini'  
config.git_provider = 'github'  
config.publish_output = True  
config.publish_output_no_suggestions = True  
config.publish_output_progress = True  
config.verbosity_level = 0  
config.publish_logs = False  
config.debug_mode = False  
config.use_wiki_settings_file = True  
config.use_repo_settings_file = True  
config.use_global_settings_file = True  
config.use_global_wiki_settings_file = False  
config.disable_auto_feedback = False  
config.ai_timeout = 150  
config.response_language = 'en-US'  
config.clone_repo_instead_of_fetch = True  
config.always_clone = False  
config.add_repo_metadata = True  
config.clone_repo_time_limit = 300  
config.publish_inline_comments_fallback_batch_size = 5  
config.publish_inline_comments_fallback_sleep_time = 2  
config.max_model_tokens = 32000  
config.custom_model_max_tokens = -1  
config.patch_extension_skip_types = ['.md', '.txt']  
config.extra_allowed_extensions = []  
config.allow_dynamic_context = True  
config.allow_forward_dynamic_context = True  
config.max_extra_lines_before_dynamic_context = 12  
config.patch_extra_lines_before = 5  
config.patch_extra_lines_after = 1  
config.ai_handler = 'litellm'  
config.cli_mode = False  
config.fetch_github_apps_from_platform = False  
config.trial_git_org_max_invokes_per_month = 30  
config.trial_ratio_close_to_limit = 0.8  
config.invite_only_mode = False  
config.enable_request_access_msg_on_new_pr = False  
config.check_also_invites_field = False  
config.allowed_users = []  
config.calculate_context = True  
config.disable_checkboxes = False  
config.output_relevant_configurations = False  
config.large_patch_policy = 'clip'  
config.seed = -1  
config.temperature = 0.2  
config.allow_dynamic_context_ab_testing = False  
config.choose_dynamic_context_ab_testing_ratio = 0.5  
config.ignore_pr_title = ['^\\[Auto\\]', '^Auto']  
config.ignore_pr_target_branches = []  
config.ignore_pr_source_branches = []  
config.ignore_pr_labels = []  
config.ignore_ticket_labels = []  
config.allow_only_specific_folders = []  
config.ignore_pr_authors = 'REDACTED'  
config.ignore_repositories = []  
config.ignore_language_framework = []  
config.is_auto_command = False  
config.is_new_pr = False  
config.enable_ai_metadata = True  
config.present_reasoning = True  
config.max_tickets = 10  
config.max_tickets_chars = 8000  
config.prevent_any_approval = False  
config.enable_comment_approval = False  
config.enable_auto_approval = False  
config.auto_approve_for_low_review_effort = -1  
config.auto_approve_for_no_suggestions = False  
config.ensure_ticket_compliance = False  
config.new_diff_format = True  
config.new_diff_format_add_external_references = True  
config.tasks_queue_ttl_from_dequeue_in_seconds = 900  
config.enable_custom_labels = False  

==================== PR_REVIEWER ====================
pr_reviewer.require_score_review = False  
pr_reviewer.require_tests_review = False  
pr_reviewer.require_estimate_effort_to_review = True  
pr_reviewer.require_can_be_split_review = False  
pr_reviewer.require_security_review = True  
pr_reviewer.require_todo_scan = False  
pr_reviewer.require_ticket_analysis_review = True  
pr_reviewer.require_ticket_labels = False  
pr_reviewer.require_no_ticket_labels = False  
pr_reviewer.check_pr_additional_content = False  
pr_reviewer.persistent_comment = True  
pr_reviewer.extra_instructions = ''  
pr_reviewer.final_update_message = True  
pr_reviewer.enable_review_labels_security = True  
pr_reviewer.enable_review_labels_effort = True  
pr_reviewer.enable_help_text = False  

==================== PR_COMPLIANCE ====================
pr_compliance.enabled = True  
pr_compliance.enable_rules_platform = True  
pr_compliance.rule_providers = []  
pr_compliance.enable_security_section = True  
pr_compliance.enable_ticket_section = True  
pr_compliance.enable_codebase_duplication_section = True  
pr_compliance.enable_custom_compliance_section = True  
pr_compliance.require_ticket_analysis_review = True  
pr_compliance.allow_repo_pr_compliance = True  
pr_compliance.enable_global_pr_compliance = True  
pr_compliance.max_lines_allowed = 2000  
pr_compliance.local_wiki_compliance_str = ''  
pr_compliance.global_wiki_pr_compliance = ''  
pr_compliance.local_repo_compliance_str = ''  
pr_compliance.global_repo_pr_compliance_str = ''  
pr_compliance.global_compliance_str = ''  
pr_compliance.enable_generic_custom_compliance_checklist = True  
pr_compliance.persist_generic_custom_compliance_checklist = False  
pr_compliance.display_no_compliance_only = False  
pr_compliance.enable_security_compliance = True  
pr_compliance.enable_update_pr_compliance_checkbox = True  
pr_compliance.enable_todo_scan = False  
pr_compliance.enable_ticket_labels = False  
pr_compliance.enable_no_ticket_labels = False  
pr_compliance.check_pr_additional_content = False  
pr_compliance.enable_compliance_labels_security = True  
pr_compliance.enable_user_defined_compliance_labels = True  
pr_compliance.enable_estimate_effort_to_review = True  
pr_compliance.max_rag_components_to_analyze = 5  
pr_compliance.min_component_size = 5  
pr_compliance.persistent_comment = True  
pr_compliance.enable_help_text = False  
pr_compliance.extra_instructions = ''  

==================== PR_DESCRIPTION ====================
pr_description.publish_labels = True  
pr_description.add_original_user_description = False  
pr_description.generate_ai_title = False  
pr_description.extra_instructions = ''  
pr_description.enable_pr_type = True  
pr_description.final_update_message = True  
pr_description.enable_help_text = False  
pr_description.enable_help_comment = False  
pr_description.bring_latest_tag = False  
pr_description.enable_pr_diagram = False  
pr_description.publish_description_as_comment = True  
pr_description.publish_description_as_comment_persistent = True  
pr_description.enable_semantic_files_types = True  
pr_description.collapsible_file_list = 'adaptive'  
pr_description.collapsible_file_list_threshold = 8  
pr_description.inline_file_summary = False  
pr_description.use_description_markers = False  
pr_description.include_generated_by_header = True  
pr_description.enable_large_pr_handling = True  
pr_description.max_ai_calls = 4  
pr_description.auto_create_ticket = False  
pr_description.use_bullet_points = True  

==================== PR_QUESTIONS ====================
pr_questions.aware_ai_handler = False  
pr_questions.enable_help_text = False  

==================== PR_CODE_SUGGESTIONS ====================
pr_code_suggestions.suggestions_depth = 'exhaustive'  
pr_code_suggestions.commitable_code_suggestions = False  
pr_code_suggestions.decouple_hunks = False  
pr_code_suggestions.dual_publishing_score_threshold = -1  
pr_code_suggestions.focus_only_on_problems = True  
pr_code_suggestions.allow_thumbs_up_down = False  
pr_code_suggestions.enable_suggestion_type_reuse = False  
pr_code_suggestions.enable_more_suggestions_checkbox = True  
pr_code_suggestions.high_level_suggestions_enabled = True  
pr_code_suggestions.extra_instructions = ''  
pr_code_suggestions.enable_help_text = False  
pr_code_suggestions.show_extra_context = False  
pr_code_suggestions.persistent_comment = True  
pr_code_suggestions.max_history_len = 5  
pr_code_suggestions.apply_suggestions_checkbox = True  
pr_code_suggestions.enable_chat_in_code_suggestions = True  
pr_code_suggestions.apply_limit_scope = True  
pr_code_suggestions.suggestions_score_threshold = 0  
pr_code_suggestions.new_score_mechanism = True  
pr_code_suggestions.new_score_mechanism_th_high = 9  
pr_code_suggestions.new_score_mechanism_th_medium = 7  
pr_code_suggestions.discard_unappliable_suggestions = False  
pr_code_suggestions.num_code_suggestions_per_chunk = 3  
pr_code_suggestions.num_best_practice_suggestions = 2  
pr_code_suggestions.max_number_of_calls = 3  
pr_code_suggestions.final_clip_factor = 0.8  
pr_code_suggestions.demand_code_suggestions_self_review = False  
pr_code_suggestions.code_suggestions_self_review_text = '**Author self-review**: I have reviewed the PR code suggestions, and addressed the relevant ones.'  
pr_code_suggestions.approve_pr_on_self_review = False  
pr_code_suggestions.fold_suggestions_on_self_review = True  
pr_code_suggestions.publish_post_process_suggestion_impact = True  
pr_code_suggestions.wiki_page_accepted_suggestions = True  
pr_code_suggestions.enable_local_self_reflect_in_large_prs = False  
pr_code_suggestions.simplify_response = True  

==================== PR_CUSTOM_PROMPT ====================
pr_custom_prompt.prompt = 'The code suggestions should focus only on the following:\n- ...\n- ...\n...\n'  
pr_custom_prompt.suggestions_score_threshold = 0  
pr_custom_prompt.num_code_suggestions_per_chunk = 4  
pr_custom_prompt.self_reflect_on_custom_suggestions = True  
pr_custom_prompt.enable_help_text = False  

==================== PR_ADD_DOCS ====================
pr_add_docs.extra_instructions = ''  
pr_add_docs.docs_style = 'Sphinx'  
pr_add_docs.file = ''  
pr_add_docs.class_name = ''  

==================== PR_UPDATE_CHANGELOG ====================
pr_update_changelog.push_changelog_changes = False  
pr_update_changelog.extra_instructions = ''  
pr_update_changelog.add_pr_link = True  
pr_update_changelog.skip_ci_on_push = True  

==================== PR_ANALYZE ====================
pr_analyze.enable_help_text = False  

==================== PR_TEST ====================
pr_test.enable = True  
pr_test.extra_instructions = ''  
pr_test.testing_framework = ''  
pr_test.num_tests = 3  
pr_test.avoid_mocks = True  
pr_test.file = ''  
pr_test.class_name = ''  
pr_test.enable_help_text = False  

==================== PR_IMPROVE_COMPONENT ====================
pr_improve_component.num_code_suggestions = 4  
pr_improve_component.extra_instructions = ''  
pr_improve_component.file = ''  
pr_improve_component.class_name = ''  

==================== REVIEW_AGENT ====================
review_agent.enabled = True  
review_agent.publish_output = True  
review_agent.enable_extended_mode = False  
review_agent.enable_context_collector = False  
review_agent.enable_issues_agent = True  
review_agent.enable_compliance_agent = True  
review_agent.enable_spec_agent = True  
review_agent.enable_deduplication = True  
review_agent.enable_conversion_agent = False  
review_agent.enable_past_bugs_collector = False  
review_agent.persistent_comment = True  
review_agent.enable_database_persistence = False  
review_agent.enable_incremental_review = True  
review_agent.rules_enabled = True  
review_agent.requirements_gap_enabled = True  
review_agent.llm_call_timeout = 180  
review_agent.context_collector_llm_model = 'turbo'  
review_agent.llm_model = 'openai/gpt-5.2_thinking'  
review_agent.ensemble_models = ['openai/gpt-5.2_thinking', 'anthropic/claude-opus-4-6_thinking']  
review_agent.feedback_tool_llm_model = 'turbo'  
review_agent.spec_llm_model = ''  
review_agent.conversion_llm_model = 'openai/gpt-5.2'  
review_agent.conversion_batching_mode = 'batch'  
review_agent.conversion_batch_size = 10  
review_agent.langsmith_project_name = 'review-agent'  
review_agent.max_tokens_for_file = 'REDACTED'  
review_agent.single_unified_diff_tokens_limit = 'REDACTED'  
review_agent.max_llm_calls = 100  
review_agent.context_collector_max_llm_calls = 6  
review_agent.compliance_batch_size = 0  
review_agent.past_bugs_max_results = 10  
review_agent.past_bugs_dedup = True  
review_agent.past_bugs_enable_similar_search = True  
review_agent.deduplication_llm_max_tokens = 'REDACTED'  
review_agent.publishing_action_level_rank_threshold = 0  
review_agent.comments_location_policy = 'both'  
review_agent.inline_comments_severity_threshold = 3  
review_agent.prefer_single_line_comments = False  
review_agent.issues_user_guidelines = ''  
review_agent.compliance_user_guidelines = ''  
review_agent.demand_self_review = False  
review_agent.self_review_text = '**Author self-review**: I have reviewed the code review findings, and addressed the relevant ones.'  
review_agent.approve_pr_on_self_review = False  

==================== PR_HELP ====================
pr_help.force_local_db = False  
pr_help.num_retrieved_snippets = 5  

==================== PR_NEW_ISSUE ====================
pr_new_issue.label_to_prompt_part = {'general': 'general question', 'feature': 'feature request (may already be addressed in the documentation)', 'bug': 'possible bug report (may be a by design behavior)'}  
pr_new_issue.supported_repos = ['qodo-ai/pr-agent']  

==================== PR_HELP_DOCS ====================
pr_help_docs.repo_url = ''  
pr_help_docs.repo_default_branch = 'main'  
pr_help_docs.docs_path = 'docs'  
pr_help_docs.exclude_root_readme = False  
pr_help_docs.supported_doc_exts = ['.md', '.mdx', '.rst']  
pr_help_docs.enable_help_text = False  

==================== PR_SIMILAR_ISSUE ====================
pr_similar_issue.skip_comments = False  
pr_similar_issue.force_update_dataset = False  
pr_similar_issue.max_issues_to_scan = 500  
pr_similar_issue.vectordb = 'pinecone'  

==================== PR_FIND_SIMILAR_COMPONENT ====================
pr_find_similar_component.class_name = ''  
pr_find_similar_component.file = ''  
pr_find_similar_component.search_from_org = False  
pr_find_similar_component.allow_fallback_less_words = True  
pr_find_similar_component.number_of_keywords = 5  
pr_find_similar_component.number_of_results = 5  

==================== BEST_PRACTICES ====================
best_practices.auto_best_practices_str = ''  
best_practices.wiki_best_practices_str = ''  
best_practices.global_wiki_best_practices = ''  
best_practices.local_repo_best_practices_str = ''  
best_practices.global_repo_best_practices_str = ''  
best_practices.global_best_practices_str = ''  
best_practices.organization_name = ''  
best_practices.max_lines_allowed = 2000  
best_practices.enable_global_best_practices = True  
best_practices.allow_repo_best_practices = True  
best_practices.enabled = True  

==================== AUTO_BEST_PRACTICES ====================
auto_best_practices.enable_auto_best_practices = True  
auto_best_practices.utilize_auto_best_practices = True  
auto_best_practices.extra_instructions = ''  
auto_best_practices.min_suggestions_to_auto_best_practices = 10  
auto_best_practices.number_of_days_to_update = 30  
auto_best_practices.max_patterns = 5  
auto_best_practices.minimal_date_to_update = '2025-01-26'  

==================== JIRA ====================
jira.jira_client_id = 'REDACTED'  
jira.jira_app_secret = 'REDACTED'  
jira.jira_api_token = 'REDACTED'  
jira.jira_base_url = 'https://issues.redhat.com'  

==================== LINEAR ====================
linear.linear_client_id = 'REDACTED'  

==================== PR_TO_TICKET ====================
pr_to_ticket.default_base_url = ''  
pr_to_ticket.default_project_key = 'REDACTED'  
pr_to_ticket.fallback_to_git_provider_issues = True  
pr_to_ticket.direct_update_compliance = False  

==================== github_app ====================
github_app.bot_user = 'github-actions[bot]'  
github_app.override_deployment_type = True  
github_app.handle_pr_actions = ['opened', 'reopened', 'ready_for_review']  
github_app.pr_commands = ['/describe --pr_description.final_update_message=false', '/review', '/improve']  
github_app.feedback_on_draft_pr = False  
github_app.handle_push_trigger = False  
github_app.push_commands = ['/agentic_review']  
github_app.ignore_pr_title = []  
github_app.ignore_bot_pr = True  

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant