Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
444115b
chore: cherry-pick lint config changes from PR #11
jeremi Feb 17, 2026
0289861
style: auto-format codebase with updated lint config
jeremi Feb 17, 2026
811a351
style: auto-format codebase and fix ESLint errors
jeremi Feb 17, 2026
0df50c2
docs: regenerate README files with oca-gen-addon-readme
jeremi Feb 17, 2026
56fba1c
fix: resolve OCA hook failures for module checks and README generation
jeremi Feb 17, 2026
c2e3119
style: re-run prettier on edited files
jeremi Feb 17, 2026
b475877
fix: revert incorrectly uncommented manifest entries and fix fastapi …
jeremi Feb 18, 2026
8ab04a7
fix: resolve all ruff lint errors across codebase
jeremi Feb 18, 2026
d5c3b96
fix: add setuptools dep for semgrep and fix fastapi demo tests
jeremi Feb 18, 2026
8979100
fix: add test timeout and remove --no-http from CI
jeremi Feb 18, 2026
7a7b17b
fix: pin setuptools<82 for semgrep and fix Odoo 19 TestCursor rename
jeremi Feb 18, 2026
f8ac3b9
fix: skip deadlocking endpoint_route_handler cross-env test on Odoo 19
jeremi Feb 18, 2026
7829bf4
fix: skip OCA module tests incompatible with Odoo 19
jeremi Feb 18, 2026
0ce2eb2
fix: move nosemgrep comments to sudo() lines for Semgrep suppression
jeremi Feb 18, 2026
560b348
fix: exclude scripts/ from security.yml Semgrep scan
jeremi Feb 18, 2026
9a34753
fix: use Generic[T] syntax for Python 3.11 compatibility
jeremi Feb 18, 2026
7bd3831
chore: migrate lint config and fix codebase-wide lint issues
jeremi Feb 18, 2026
25ee155
fix: remove ACL entries for non-existent models
jeremi Feb 18, 2026
952025c
fix: resolve Semgrep SARIF suppression and CodeQL sensitive-data alert
jeremi Feb 18, 2026
564f3f4
fix: remove debug log flagged by CodeQL as sensitive-data exposure
jeremi Feb 18, 2026
c328fa2
test: link Odoo 19 skips to tracking issues
jeremi Feb 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ jobs:
needs: [detect-changes, build]
if: needs.detect-changes.outputs.has_modules == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -203,7 +204,6 @@ jobs:
--db_user=odoo \
--db_password=odoo \
--stop-after-init \
--no-http \
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

CI test flag --no-http accidentally removed

High Severity

The --no-http flag was removed from the Odoo test command in CI. This flag prevents the HTTP server from starting during tests and is still present in ci-full.yml and scripts/test_single_module.sh. Without it, each test job starts an unnecessary HTTP server, wasting resources and risking port-conflict flakiness. In a lint-config-migration PR, this behavioral change looks unintentional.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No it was intended to test the rest API

--data-dir /tmp/odoo-data \
-i ${{ matrix.module }} \
--test-tags=/${{ matrix.module }} \
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ jobs:
--config p/python \
--config p/security-audit \
--config .semgrep/ \
--exclude scripts/ \
--sarif \
--output semgrep-results.sarif \
2>&1 || SEMGREP_EXIT=$?
Expand All @@ -176,6 +177,7 @@ jobs:
--config p/python \
--config p/security-audit \
--config .semgrep/ \
--exclude scripts/ \
2>&1 || true

exit ${SEMGREP_EXIT:-0}
Expand Down
5 changes: 5 additions & 0 deletions .openspp-lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ rules:
- "line_ids" # Generic line items (typically <20)
- "manager_ids" # Program managers (typically <10)
- "approver_ids" # Approval workflow (typically <5)
- "bank_ids" # Bank accounts (typically 1-5 per person)
- "phone_number_ids" # Phone numbers (typically 1-3 per person)
- "entitlement_manager_ids" # Entitlement managers (typically <10 per program)
- "payment_manager_ids" # Payment managers (typically <10 per program)
- "farm_machinery_ids" # Farm machinery (typically <20 per farm)

# Severity overrides (change default severity for rules)
# Valid values: error, warning, info
Expand Down
15 changes: 11 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ repos:
- id: pylint_odoo
args:
- --rcfile=.pylintrc-mandatory
exclude: ^spp$|^scripts/|^(base_user_role|endpoint_route_handler|extendable|extendable_fastapi|fastapi|openspp-vocabularies|openspp|theme_openspp_muk|queue_job)/
# ============================================================================
# OpenSPP Custom Linting Rules
# Based on docs/principles/ - see scripts/lint/README.md for details
Expand All @@ -147,7 +148,8 @@ repos:
# Phase 1: Simple pattern-based checks (pygrep)
- id: openspp-no-assertraises-tuple
name: "OpenSPP: No tuple in assertRaises"
description: "Odoo's assertRaises doesn't support tuple of exceptions like stdlib unittest"
description:
"Odoo's assertRaises doesn't support tuple of exceptions like stdlib unittest"
entry: 'self\.assertRaises\s*\(\s*\('
language: pygrep
types: [python]
Expand Down Expand Up @@ -202,7 +204,8 @@ repos:
# Phase 2: Compliance check (security spec validation)
- id: openspp-compliance-check
name: "OpenSPP: Security compliance check"
description: "Validate modules with compliance.yaml against actual security config"
description:
"Validate modules with compliance.yaml against actual security config"
entry: python -m scripts.compliance.checker --all
language: python
additional_dependencies:
Expand Down Expand Up @@ -236,7 +239,9 @@ repos:
# Phase 3: UI patterns check (warning only)
- id: openspp-check-ui
name: "OpenSPP: UI patterns"
description: "Check list limits, sample data, XPath syntax, statusbar location, extension points"
description:
"Check list limits, sample data, XPath syntax, statusbar location, extension
points"
entry: python scripts/lint/check_ui_patterns.py
language: python
additional_dependencies:
Expand Down Expand Up @@ -272,7 +277,8 @@ repos:
# API authentication enforcement
- id: openspp-check-api-auth
name: "OpenSPP: API endpoint authentication"
description: "Verify all API endpoints require authentication (allowlist for public)"
description:
"Verify all API endpoints require authentication (allowlist for public)"
entry: python scripts/audit-api-auth.py --strict
language: python
pass_filenames: false
Expand All @@ -293,6 +299,7 @@ repos:
hooks:
- id: semgrep
args: ["--config", ".semgrep/", "--error", "--quiet"]
additional_dependencies: ["setuptools<82"]
# Only scan OpenSPP spp_* modules (not scripts, endpoint handlers, etc.)
files: ^spp_
# Exclude test files, migrations, and demo-only modules
Expand Down
49 changes: 3 additions & 46 deletions .pylintrc-mandatory
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,14 @@ valid-odoo-versions=19.0
[MESSAGES CONTROL]
disable=all

# Mandatory checks: these block CI. High-volume cosmetic checks
# (attribute-string-redundant, except-pass, missing-return, etc.)
# are in the optional .pylintrc only, enforced via --exit-zero.
enable=anomalous-backslash-in-string,
api-one-deprecated,
api-one-multi-together,
assignment-from-none,
attribute-deprecated,
class-camelcase,
dangerous-default-value,
dangerous-view-replace-wo-priority,
development-status-allowed,
duplicate-id-csv,
duplicate-key,
duplicate-xml-fields,
duplicate-xml-record-id,
eval-referenced,
eval-used,
incoherent-interpreter-exec-perm,
license-allowed,
manifest-author-string,
manifest-deprecated-key,
Expand All @@ -37,58 +29,23 @@ enable=anomalous-backslash-in-string,
manifest-version-format,
method-compute,
method-inverse,
method-required-super,
method-search,
openerp-exception-warning,
pointless-statement,
pointless-string-statement,
print-used,
redundant-keyword-arg,
redundant-modulename-xml,
reimported,
relative-import,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Critical method-required-super check demoted to optional

Medium Severity

The method-required-super pylint check was removed from the mandatory (CI-blocking) configuration. The accompanying comment describes the moved checks as "high-volume cosmetic," but method-required-super is a critical correctness check that catches missing super() calls in ORM methods like create, write, and unlink. Without it blocking CI, code with missing super() calls can be merged, causing silent data corruption.

Fix in Cursor Fix in Web

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Critical method-required-super check removed from mandatory CI

Medium Severity

The method-required-super pylint check was removed from .pylintrc-mandatory, demoting it to the optional non-blocking .pylintrc (which runs with --exit-zero). This check catches missing super() calls in critical Odoo ORM methods like create(), write(), unlink(), and copy(). Without super(), these methods silently fail to persist changes — a serious data-integrity bug. The accompanying comment categorizes the removed checks as "high-volume cosmetic checks," but method-required-super is not cosmetic; it catches real bugs that cause data loss. This appears to be an inadvertent inclusion in the batch demotion.

Fix in Cursor Fix in Web

return-in-init,
rst-syntax-error,
sql-injection,
too-few-format-args,
translation-field,
translation-required,
unreachable,
use-vim-comment,
wrong-tabs-instead-of-spaces,
xml-syntax-error,
attribute-string-redundant,
character-not-valid-in-resource-link,
consider-merging-classes-inherited,
context-overridden,
create-user-wo-reset-password,
dangerous-filter-wo-user,
dangerous-qweb-replace-wo-priority,
deprecated-data-xml-node,
deprecated-openerp-xml-node,
duplicate-po-message-definition,
except-pass,
file-not-used,
invalid-commit,
manifest-maintainers-list,
missing-newline-extrafiles,
missing-readme,
missing-return,
odoo-addons-relative-import,
old-api7-method-defined,
po-msgstr-variables,
po-syntax-error,
renamed-field-parameter,
resource-not-exist,
str-format-used,
test-folder-imported,
translation-contains-variable,
translation-positional-used,
unnecessary-utf8-coding-comment,
website-manifest-key-not-valid-uri,
xml-attribute-translatable,
xml-deprecated-qweb-directive,
xml-deprecated-tree-attribute,
external-request-timeout

[REPORTS]
Expand Down
4 changes: 2 additions & 2 deletions .ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ extend-select = [
"UP", # pyupgrade
]
extend-safe-fixes = ["UP008"]
exclude = ["setup/*"]
exclude = ["setup/*", "fastapi/*", "base_user_role/*", "endpoint_route_handler/*", "extendable/*", "extendable_fastapi/*", "openspp-vocabularies/*", "openspp/*", "theme_openspp_muk/*", "queue_job/*"]

[format]
exclude = ["setup/*"]
exclude = ["setup/*", "fastapi/*", "base_user_role/*", "endpoint_route_handler/*", "extendable/*", "extendable_fastapi/*", "openspp-vocabularies/*", "openspp/*", "theme_openspp_muk/*", "queue_job/*"]

[lint.per-file-ignores]
"__init__.py" = ["F401", "I001"] # ignore unused and unsorted imports in __init__.py
Expand Down
23 changes: 9 additions & 14 deletions .semgrep/odoo-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,13 @@ rules:
owasp: "A03:2021 Injection"

- id: odoo-unsafe-safe-eval
patterns:
- pattern-either:
- pattern: safe_eval(...)
- pattern: odoo.tools.safe_eval.safe_eval(...)
- pattern: odoo.tools.safe_eval.test_expr(...)
# Suppress in compute methods and known-safe domain evaluation
# contexts where the input is developer-controlled, not user-controlled.
- pattern-not-inside: |
def _compute_$METHOD(...):
...
- pattern-not-inside: |
def action_domain_eval(...):
...
# NOTE: pattern-not-inside blocks removed - semgrep v1.90.0 cannot parse
# metavariable/ellipsis patterns in Python function definitions.
# Use nosemgrep inline annotations for known-safe usage.
pattern-either:
- pattern: safe_eval(...)
- pattern: odoo.tools.safe_eval.safe_eval(...)
- pattern: odoo.tools.safe_eval.test_expr(...)
message: |
safe_eval() is NOT safe with user input!
It can be bypassed to achieve code execution.
Expand Down Expand Up @@ -227,7 +221,8 @@ rules:
- pattern: _logger.$METHOD(..., $RECORD.national_id, ...)
- pattern: _logger.$METHOD(..., $RECORD.tax_id, ...)
- pattern: _logger.$METHOD(..., $RECORD.vat, ...)
message: "Potential PII (national/tax ID) in log message - CRITICAL privacy violation."
message:
"Potential PII (national/tax ID) in log message - CRITICAL privacy violation."
severity: ERROR
languages: [python]
metadata:
Expand Down
Loading
Loading