Conversation
This module provides the necessary models, views, and orchestration logic to manage database connections and data flow projects directly from the Odoo UI. Key features include: - `odf.connection` model to store database credentials. - `odf.flow.project` model to define and track data flow projects. - Orchestration logic to run projects via a scheduled action, using direct calls to the `odoo-data-flow` Python library. - User interface components (menus, forms, tree views) for managing connections and projects. - A scheduled action that runs hourly to execute active projects. - Basic security configuration to grant access to the new models.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a new Odoo module, odf_core, which provides the basic framework for a data flow tool. It adds models for connections and flow projects, along with UI components and a scheduled action to execute the flows.
My review has identified several critical and high-severity issues that should be addressed:
- Security: Passwords are being stored in plaintext, the cron job runs as the root user, and access controls are too permissive. These issues pose significant security risks.
- Correctness: The use of manual
commit()calls within a cron job breaks Odoo's transaction management, which can lead to data inconsistency.
I have provided detailed comments and suggestions for each of these points. Addressing them will greatly improve the security and robustness of the module.
| port = fields.Integer(required=True, default=5432) | ||
| dbname = fields.Char(required=True) | ||
| user = fields.Char(required=True) | ||
| password = fields.Char(password=True) |
There was a problem hiding this comment.
Storing passwords in plaintext in the database is a major security vulnerability. The password=True attribute only masks the password in the user interface but does not provide any encryption for storage. Anyone with database access can read these passwords.
You should use a secure method for storing credentials. Consider using Odoo's ir.config_parameter for sensitive data, which can be protected, or integrate with a secrets management tool like HashiCorp Vault. If you must store it in this model, the password should be encrypted before being stored and decrypted when used.
| for project in projects: | ||
| project.write({'status': 'running'}) | ||
| self.env.cr.commit() | ||
|
|
||
| try: | ||
| if not run_workflow: | ||
| raise ImportError("The 'odoo-data-flow' library is not available.") | ||
|
|
||
| if not project.flow_file_path: | ||
| raise ValueError(f"Flow file path is not set for project '{project.name}'") | ||
|
|
||
| # The odoo-data-flow library expects a path to a YAML config file. | ||
| run_workflow(project.flow_file_path) | ||
|
|
||
| project.write({'status': 'done'}) | ||
| self.env.cr.commit() | ||
|
|
||
| except Exception: | ||
| _logger.error( | ||
| "Failed to run data flow project '%s'.\n%s", | ||
| project.name, | ||
| traceback.format_exc() | ||
| ) | ||
| project.write({'status': 'failed'}) | ||
| self.env.cr.commit() |
There was a problem hiding this comment.
The use of self.env.cr.commit() inside a loop is highly discouraged in Odoo as it breaks transaction atomicity. This can lead to data inconsistencies that are hard to debug. For instance, if the server crashes after a commit, the project's state could be left as 'running' incorrectly. Odoo cron jobs run in a single transaction, ensuring that all changes are rolled back if any part of the job fails, which maintains data integrity.
If you need to process each project in an isolated transaction, the recommended approach in Odoo is to use a job queue module (like queue_job from the OCA).
I recommend refactoring this method to remove the manual commits and wrap the logic for a single project in a try...except block. This ensures that the entire cron run is atomic.
for project in projects:
try:
project.write({'status': 'running'})
if not run_workflow:
raise ImportError("The 'odoo-data-flow' library is not available.")
if not project.flow_file_path:
raise ValueError(f"Flow file path is not set for project '{project.name}'")
# The odoo-data-flow library expects a path to a YAML config file.
run_workflow(project.flow_file_path)
project.write({'status': 'done'})
except Exception:
_logger.error(
"Failed to run data flow project '%s'.\n%s",
project.name,
traceback.format_exc()
)
project.write({'status': 'failed'})| <field name="model_id" ref="model_odf_flow_project"/> | ||
| <field name="state">code</field> | ||
| <field name="code">model._run_projects()</field> | ||
| <field name="user_id" ref="base.user_root"/> |
| access_odf_connection,odf.connection access,model_odf_connection,base.group_user,1,1,1,1 | ||
| access_odf_flow_project,odf.flow.project access,model_odf_flow_project,base.group_user,1,1,1,1 |
There was a problem hiding this comment.
The current access control rules grant all internal users (base.group_user) full create, read, update, and delete (CRUD) permissions on odf.connection and odf.flow.project models. This is likely too permissive. Connection details, which may contain sensitive information, and the ability to run data flows should be restricted to authorized users.
I suggest restricting access to a more privileged group, for example, system administrators (base.group_system). For more granular control, you could create a dedicated security group (e.g., group_odf_manager) and assign access to that group instead.
access_odf_connection,odf.connection access,model_odf_connection,base.group_system,1,1,1,1
access_odf_flow_project,odf.flow.project access,model_odf_flow_project,base.group_system,1,1,1,1
| project.write({'status': 'done'}) | ||
| self.env.cr.commit() | ||
|
|
||
| except Exception: |
There was a problem hiding this comment.
Catching a broad Exception can hide unexpected errors and make debugging more difficult. It's better practice to catch more specific exceptions that you anticipate, such as ImportError and ValueError which you raise explicitly. If run_workflow can raise other known exceptions, they should also be caught specifically. This makes the error handling more robust and the code's intent clearer.
Fixes #10