-
Notifications
You must be signed in to change notification settings - Fork 42
[18.0][ADD] cetmix_tower_jet_isolation: base module add new module #486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 18.0
Are you sure you want to change the base?
Changes from 1 commit
577eee9
bb589d6
c0066cd
834ea5d
6582561
2fe26fc
1028b27
7c1970e
1126d98
6c96323
385a528
f74940a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| from . import models | ||
| from . import wizards |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| { | ||
| "name": "Cetmix Tower Jet Isolation", | ||
| "version": "18.0.1.0.0", | ||
| "category": "Tower", | ||
| "summary": "Adds strict isolation mode for Jets, preventing users from altering command visibility.", | ||
| "author": "Antigravity", | ||
| "depends": [ | ||
| "cetmix_tower_server", | ||
| ], | ||
| "data": [ | ||
| "views/cx_tower_jet_template_views.xml", | ||
| "views/cx_tower_command_run_wizard_views.xml", | ||
| "views/cx_tower_plan_run_wizard_views.xml", | ||
| ], | ||
| "installable": True, | ||
| "license": "AGPL-3", | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| from . import cx_tower_jet_template |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| from odoo import models, fields | ||
|
|
||
| class CxTowerJetTemplate(models.Model): | ||
| _inherit = 'cx.tower.jet.template' | ||
|
|
||
| isolation_mode = fields.Boolean( | ||
| string='Isolation Mode', | ||
| help='When active, prevents users from changing applicability or tags when running commands/plans.' | ||
| ) | ||
| forced_applicability = fields.Selection([ | ||
| ('this', 'For selected server(s)'), | ||
| ('shared', 'Non server restricted') | ||
| ], string='Forced Applicability') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Enforce The XML view declares 🤖 Prompt for AI Agents🧹 Nitpick | 🔵 Trivial Avoid duplicating the
forced_applicability = fields.Selection(
selection=lambda self: self.env["cx.tower.plan.run.wizard"]._fields["applicability"].selection,
string="Forced Applicability",
)🤖 Prompt for AI Agents |
||
|
|
||
| forced_command_tag_ids = fields.Many2many( | ||
| comodel_name='cx.tower.tag', | ||
| relation='cx_tower_template_forced_command_tag_rel', | ||
| string='Forced Command Tags', | ||
| ) | ||
|
|
||
| forced_plan_tag_ids = fields.Many2many( | ||
| comodel_name='cx.tower.tag', | ||
| relation='cx_tower_template_forced_plan_tag_rel', | ||
| string='Forced Flight Plan Tags', | ||
| ) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Missing module/class docstring and style inconsistencies. This file uses single quotes and omits a class docstring, diverging from the 🤖 Prompt for AI Agents
Comment on lines
+14
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Specify Other 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,23 @@ | ||||||||||||||||||||
| <?xml version="1.0" encoding="utf-8"?> | ||||||||||||||||||||
| <odoo> | ||||||||||||||||||||
| <record id="cx_tower_command_run_wizard_view_form_isolation" model="ir.ui.view"> | ||||||||||||||||||||
| <field name="name">cx.tower.command.run.wizard.view.form.isolation</field> | ||||||||||||||||||||
| <field name="model">cx.tower.command.run.wizard</field> | ||||||||||||||||||||
| <field name="inherit_id" ref="cetmix_tower_server.cx_tower_command_run_wizard_view_form"/> | ||||||||||||||||||||
| <field name="arch" type="xml"> | ||||||||||||||||||||
| <xpath expr="//field[@name='tag_ids']" position="before"> | ||||||||||||||||||||
| <field name="is_isolated_context" invisible="1"/> | ||||||||||||||||||||
| </xpath> | ||||||||||||||||||||
|
|
||||||||||||||||||||
| <xpath expr="//field[@name='applicability']" position="attributes"> | ||||||||||||||||||||
| <attribute name="readonly">is_isolated_context</attribute> | ||||||||||||||||||||
| <attribute name="force_save">1</attribute> | ||||||||||||||||||||
| </xpath> | ||||||||||||||||||||
|
Comment on lines
+19
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Overriding The parent view sets 🔧 Proposed fix <xpath expr="//field[`@name`='applicability']" position="attributes">
- <attribute name="readonly">is_isolated_context</attribute>
+ <attribute name="readonly">is_isolated_context or show_servers</attribute>
<attribute name="force_save">1</attribute>
</xpath>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
|
|
||||||||||||||||||||
| <xpath expr="//field[@name='tag_ids']" position="attributes"> | ||||||||||||||||||||
| <attribute name="readonly">is_isolated_context</attribute> | ||||||||||||||||||||
| <attribute name="force_save">1</attribute> | ||||||||||||||||||||
| </xpath> | ||||||||||||||||||||
|
Comment on lines
+24
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify static group narrowing on tag_ids versus dynamic restriction logic.
rg -n -C4 'name="tag_ids"|is_restricted_context|manager_ids|has_group\("cetmix_tower_server.group_manager"\)' \
cetmix_tower_jet_isolation/views/cx_tower_command_run_wizard_views.xml \
cetmix_tower_jet_isolation/wizards/cx_tower_command_run_wizard.pyRepository: cetmix/cetmix-tower Length of output: 7612 Remove static group restriction on tag_ids field. Line 25 unnecessarily restricts Proposed fix <xpath expr="//field[`@name`='tag_ids']" position="attributes">
- <attribute name="groups">cetmix_tower_server.group_manager</attribute>
<attribute name="invisible">is_restricted_context or result</attribute>
<attribute name="force_save">1</attribute>
</xpath>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
| </field> | ||||||||||||||||||||
| </record> | ||||||||||||||||||||
| </odoo> | ||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <odoo> | ||
| <record id="cx_tower_jet_template_view_form_isolation" model="ir.ui.view"> | ||
| <field name="name">cx.tower.jet.template.view.form.isolation</field> | ||
| <field name="model">cx.tower.jet.template</field> | ||
| <field name="inherit_id" ref="cetmix_tower_server.cx_tower_jet_template_view_form"/> | ||
| <field name="arch" type="xml"> | ||
| <xpath expr="//group[@name='general']" position="after"> | ||
| <group name="isolation" string="Execution Security (Isolation Mode)"> | ||
| <field name="isolation_mode" widget="boolean_toggle"/> | ||
| <field name="forced_applicability" invisible="not isolation_mode" required="isolation_mode"/> | ||
| <field name="forced_command_tag_ids" widget="many2many_tags" invisible="not isolation_mode"/> | ||
| <field name="forced_plan_tag_ids" widget="many2many_tags" invisible="not isolation_mode"/> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Clear forced values when isolation is disabled.
🤖 Prompt for AI Agents |
||
| </group> | ||
| </xpath> | ||
| </field> | ||
| </record> | ||
| </odoo> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <odoo> | ||
| <record id="cx_tower_plan_run_wizard_view_form_isolation" model="ir.ui.view"> | ||
| <field name="name">cx.tower.plan.run.wizard.view.form.isolation</field> | ||
| <field name="model">cx.tower.plan.run.wizard</field> | ||
| <field name="inherit_id" ref="cetmix_tower_server.cx_tower_plan_run_wizard_view_form"/> | ||
| <field name="arch" type="xml"> | ||
| <xpath expr="//field[@name='tag_ids']" position="before"> | ||
| <field name="is_isolated_context" invisible="1"/> | ||
| </xpath> | ||
|
|
||
| <xpath expr="//field[@name='applicability']" position="attributes"> | ||
| <attribute name="readonly">is_isolated_context</attribute> | ||
| <attribute name="force_save">1</attribute> | ||
| </xpath> | ||
|
Comment on lines
+19
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
fd -t f 'cx_tower_plan_run_wizard_view.xml' | xargs -I{} rg -n -C2 "name=['\"]applicability['\"]" {}Repository: cetmix/cetmix-tower Length of output: 299 🏁 Script executed: # Find the parent view by examining the file and locating the parent reference
fd -t f '*.xml' -p 'cetmix_tower_jet_isolation/views/*' | head -20Repository: cetmix/cetmix-tower Length of output: 184 🏁 Script executed: # Search for the parent view name referenced in the file being reviewed
rg -A5 -B5 "cx_tower_plan_run_wizard_view" cetmix_tower_jet_isolation/views/cx_tower_plan_run_wizard_views.xml | head -40Repository: cetmix/cetmix-tower Length of output: 658 🏁 Script executed: # Look for any parent view definition files that might contain applicability field
fd -t f '*.xml' cetmix_tower_jet_isolation/views/ | xargs grep -l "applicability" | head -10Repository: cetmix/cetmix-tower Length of output: 347 🏁 Script executed: # List all XML files to understand the structure
find . -name "*.xml" -type f | grep -E "(cetmix_tower_server|cetmix_tower_jet)" | head -20Repository: cetmix/cetmix-tower Length of output: 1292 🏁 Script executed: # Search for the parent view definition across the entire repo
rg -l "cx_tower_plan_run_wizard_view_form" --type xmlRepository: cetmix/cetmix-tower Length of output: 192 🏁 Script executed: # Search for applicability field with readonly attribute
rg "readonly.*applicability|applicability.*readonly" --type xml -A2 -B2Repository: cetmix/cetmix-tower Length of output: 45 🏁 Script executed: # Read the parent view file to find applicability field definition
cat -n cetmix_tower_server/wizards/cx_tower_plan_run_wizard_view.xml | grep -A10 -B10 "applicability"Repository: cetmix/cetmix-tower Length of output: 1462 Combine readonly conditions instead of replacing: The parent view already sets 🤖 Prompt for AI Agents |
||
|
|
||
| <xpath expr="//field[@name='tag_ids']" position="attributes"> | ||
| <attribute name="readonly">is_isolated_context</attribute> | ||
| <attribute name="force_save">1</attribute> | ||
| </xpath> | ||
| </field> | ||
| </record> | ||
| </odoo> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| from . import cx_tower_command_run_wizard | ||
| from . import cx_tower_plan_run_wizard |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,29 @@ | ||||||||||||||||||||||||||||
| from odoo import models, fields, api | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| class CxTowerCommandRunWizardFilter(models.TransientModel): | ||||||||||||||||||||||||||||
| _inherit = 'cx.tower.command.run.wizard' | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| is_isolated_context = fields.Boolean(compute='_compute_is_isolated_context') | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| @api.depends('jet_ids') | ||||||||||||||||||||||||||||
| def _compute_is_isolated_context(self): | ||||||||||||||||||||||||||||
| for record in self: | ||||||||||||||||||||||||||||
| if record.jet_ids and any(j.jet_template_id.isolation_mode for j in record.jet_ids): | ||||||||||||||||||||||||||||
| record.is_isolated_context = True | ||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||
| record.is_isolated_context = False | ||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Simplify compute and guard against NewId/unsaved templates. Minor cleanup: the ♻️ Proposed refactor- `@api.depends`('jet_ids')
- def _compute_is_isolated_context(self):
- for record in self:
- if record.jet_ids and any(j.jet_template_id.isolation_mode for j in record.jet_ids):
- record.is_isolated_context = True
- else:
- record.is_isolated_context = False
+ `@api.depends`('jet_ids.jet_template_id.isolation_mode')
+ def _compute_is_isolated_context(self):
+ for record in self:
+ record.is_isolated_context = any(
+ record.jet_ids.jet_template_id.mapped('isolation_mode')
+ )Note the added dependency on 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| @api.model | ||||||||||||||||||||||||||||
| def default_get(self, fields_list): | ||||||||||||||||||||||||||||
| res = super().default_get(fields_list) | ||||||||||||||||||||||||||||
| if 'default_jet_ids' in self.env.context: | ||||||||||||||||||||||||||||
| jet_ids = self.env['cx.tower.jet'].browse(self.env.context['default_jet_ids']) | ||||||||||||||||||||||||||||
| if jet_ids: | ||||||||||||||||||||||||||||
| template = jet_ids[0].jet_template_id | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if template.isolation_mode: | ||||||||||||||||||||||||||||
| if template.forced_applicability: | ||||||||||||||||||||||||||||
| res['applicability'] = template.forced_applicability | ||||||||||||||||||||||||||||
| if template.forced_command_tag_ids: | ||||||||||||||||||||||||||||
| res['tag_ids'] = [(6, 0, template.forced_command_tag_ids.ids)] | ||||||||||||||||||||||||||||
| return res | ||||||||||||||||||||||||||||
|
Comment on lines
+40
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inconsistency between
Iterate over all jets and apply the strictest forced values, or otherwise define a deterministic selection rule (e.g., the first isolated template). 🛠️ Proposed fix- if 'default_jet_ids' in self.env.context:
- jet_ids = self.env['cx.tower.jet'].browse(self.env.context['default_jet_ids'])
- if jet_ids:
- template = jet_ids[0].jet_template_id
-
- if template.isolation_mode:
- if template.forced_applicability:
- res['applicability'] = template.forced_applicability
- if template.forced_command_tag_ids:
- res['tag_ids'] = [(6, 0, template.forced_command_tag_ids.ids)]
+ jet_ids_ctx = self.env.context.get('default_jet_ids')
+ if jet_ids_ctx:
+ jets = self.env['cx.tower.jet'].browse(jet_ids_ctx)
+ isolated_templates = jets.jet_template_id.filtered('isolation_mode')
+ if isolated_templates:
+ template = isolated_templates[0]
+ if template.forced_applicability:
+ res['applicability'] = template.forced_applicability
+ forced_tags = isolated_templates.mapped('forced_command_tag_ids')
+ if forced_tags:
+ res['tag_ids'] = [(6, 0, forced_tags.ids)]🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,29 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from odoo import models, fields, api | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class CxTowerPlanRunWizardFilter(models.TransientModel): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _inherit = 'cx.tower.plan.run.wizard' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| is_isolated_context = fields.Boolean(compute='_compute_is_isolated_context') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @api.depends('jet_ids') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _compute_is_isolated_context(self): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for record in self: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if record.jet_ids and any(j.jet_template_id.isolation_mode for j in record.jet_ids): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| record.is_isolated_context = True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| record.is_isolated_context = False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Style/consistency nits.
Proposed simplification- `@api.depends`('jet_ids')
- def _compute_is_isolated_context(self):
- for record in self:
- if record.jet_ids and any(j.jet_template_id.isolation_mode for j in record.jet_ids):
- record.is_isolated_context = True
- else:
- record.is_isolated_context = False
+ `@api.depends`("jet_ids.jet_template_id.isolation_mode")
+ def _compute_is_isolated_context(self):
+ for record in self:
+ record.is_isolated_context = any(
+ record.jet_ids.mapped("jet_template_id.isolation_mode")
+ )📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @api.model | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def default_get(self, fields_list): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res = super().default_get(fields_list) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if 'default_jet_ids' in self.env.context: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jet_ids = self.env['cx.tower.jet'].browse(self.env.context['default_jet_ids']) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if jet_ids: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| template = jet_ids[0].jet_template_id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using only the first jet's template is fragile.
Also, 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if template.isolation_mode: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if template.forced_applicability: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res['applicability'] = template.forced_applicability | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if template.forced_plan_tag_ids: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res['tag_ids'] = [(6, 0, template.forced_plan_tag_ids.ids)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Privilege-escalation risk: isolation may override the base wizard's non-privileged The base Consider respecting the base restriction (e.g., only widen to 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+40
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Server-side enforcement is missing — isolation is bypassable.
Enforce the isolation constraints on the server side by overriding 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.