Tool bao ve source code module Odoo theo huong an toan.
Project description
jProtect
Protect your Odoo module's business logic by extracting method bodies into compiled binaries (.so/.pyd) โ the module still installs and runs normally on Odoo.
๐ What It Does
jProtect takes an Odoo module and:
- Keeps the public file intact โ class definitions, fields, decorators, and
_name/_inheritstay in place so Odoo registers the model normally. - Extracts method bodies into a hidden
models/_protected/package as standalone functions. - Replaces each method body with a thin delegation call to
_protected. - Compiles
_protected/into.so/.pydbinaries (optional--compileflag).
The result: a module that looks and behaves exactly like the original โ but the business logic is gone from the source files.
โจ Features
- ๐ Dry-run mode โ preview what will be protected before writing anything
- โ๏ธ Selective protection โ include/exclude files with glob patterns
- ๐ Cython compilation โ compile protected code to native binaries
- ๐
super()rewriting โ zero-argsuper()is automatically rewritten tosuper(cls, self)so inheritance chains keep working - ๐ก๏ธ Safe by default โ skips dunders,
@property, generators,__init__.py, migrations, and any pattern that could break Odoo
๐ฆ Installation
Requires Python 3.10+. Cython is installed automatically.
pip install jprotect
When using
--compile, a C compiler is also required:
- Linux:
gcc+python3-dev- Windows: MSVC Build Tools
๐ Quick Start
Given a module at ./addons/sale_ext:
# Step 1 โ Preview (no files written)
jprotect protect-module \
--input ./addons/sale_ext \
--output ./dist/dist/sale_ext \
--dry-run
# Step 2 โ Protect (extract logic, no compile)
jprotect protect-module \
--input ./addons/sale_ext \
--output ./dist/dist/sale_ext
# Step 3 โ Protect + compile to binary
jprotect protect-module \
--input ./addons/sale_ext \
--output ./dist/dist/sale_ext \
--compile
After running, jProtect generates a protection-manifest.json in the output directory listing every processed file.
๐ How It Works
# โโ Original file โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
class SaleOrder(models.Model):
_inherit = 'sale.order'
def action_confirm(self):
# your business logic here...
return super().action_confirm()
# โโ Public file after jProtect โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
from . import _protected
class SaleOrder(models.Model):
_inherit = 'sale.order'
def action_confirm(self):
return _protected.sale_order.SaleOrder__action_confirm(self, SaleOrder)
# โโ _protected/sale_order.py (or .so after --compile) โโโโโโโโโโโ
def SaleOrder__action_confirm(self, cls):
# your business logic here...
return super(cls, self).action_confirm()
Odoo sees the same class structure and registers the model exactly as before. The logic only lives inside the compiled binary.
โ๏ธ CLI Reference
jprotect protect-module --input <dir> --output <dir> [options]
| Option | Description | Example |
|---|---|---|
--input |
Odoo module directory (must contain __manifest__.py) |
--input ./addons/sale_ext |
--output |
Output directory | --output ./dist/dist/sale_ext |
--mode |
dist creates a copy (default); inplace modifies in place |
--mode inplace |
--dry-run |
Scan and report only, no files written | --dry-run |
--compile |
Compile _protected/ to .so/.pyd |
--compile |
--include |
Glob pattern for files to protect (repeatable, default: models/**/*.py) |
--include "models/**/*.py" --include "utils/*.py" |
--exclude |
Glob pattern for files to exclude (repeatable) | --exclude "models/res_*.py" |
๐ณ Docker
Build once, run anywhere โ useful for compiling binaries that match your Odoo server environment:
docker build -t jprotect .
docker run --rm \
-v "$PWD/addons/sale_ext:/work/input:ro" \
-v "$PWD/dist:/work/output" \
jprotect protect-module \
--input /work/input \
--output /work/output/dist/sale_ext \
--compile
โ ๏ธ Important Notes
Binaries are environment-specific. A .so/.pyd file only runs on the exact Python version + OS + CPU architecture it was compiled on. You must build on an environment that matches your Odoo server.
| Odoo Version | Python |
|---|---|
| 16, 17, 18 | 3.10 |
| 14, 15 | 3.8 |
Always test on staging first. Install and upgrade the protected module on a staging Odoo database and run through the main flows before going to production.
๐ก๏ธ What Gets Protected
jProtect protects regular instance methods only. The following are intentionally left untouched:
| Skipped | Reason |
|---|---|
@staticmethod, @classmethod, @property |
Different call semantics, cannot be safely delegated |
Property setters/deleters (@x.setter, @x.deleter) |
Setter return values are ignored by Python; wrapping changes semantics |
Dunder methods (__init__, __str__, ...) |
Called directly by Odoo/Python internals |
Generator methods (contain yield) |
Extracting a generator body breaks the iterator protocol |
Methods with super() inside nested functions |
super() without args relies on the declaring scope's __class__ cell |
__init__.py, migrations/, controllers/ |
Breaking these would prevent Odoo from loading the module |
๐ ๏ธ Development
Setup
git clone https://github.com/your-org/jprotect.git
cd jprotect
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[test]"
Run tests
pytest -q # all tests
pytest tests/unit/ -q # unit tests only
pytest tests/integration/ -q # integration tests only
pytest tests/unit/test_ast_transformer.py -v # specific file
Project structure
src/jprotect/
โโโ cli/ # CLI entry point (argparse)
โโโ config/ # Config schema and loader
โโโ core/
โ โโโ compile/ # Cython backend
โ โโโ transform/ # Core AST transformation logic
โ โ โโโ ast_transformer.py # parse, extract, build delegation
โ โ โโโ transformer.py # orchestrate transform over directory tree
โ โโโ pipeline.py
โ โโโ ...
โโโ errors.py
tests/
โโโ unit/ # per-function tests with real source strings
โโโ integration/ # full pipeline tests on a fixture Odoo module
See docs/CODE_CONVENTIONS.md for coding conventions.
๐ License
PolyForm Noncommercial 1.0.0 โ free for personal and noncommercial use. Commercial use requires a separate license from the author. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jprotect-0.1.0.tar.gz.
File metadata
- Download URL: jprotect-0.1.0.tar.gz
- Upload date:
- Size: 25.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4c1b827acdf1c597f1c5eb80dda605c7bf8b1239256684d1da6078b40485866
|
|
| MD5 |
2c15c71d721d957941dee24d68809116
|
|
| BLAKE2b-256 |
7585a660b10430b18956e029f7e0ad63e34b0904e8602fc7b2442f9a55a9bf7f
|
File details
Details for the file jprotect-0.1.0-py3-none-any.whl.
File metadata
- Download URL: jprotect-0.1.0-py3-none-any.whl
- Upload date:
- Size: 27.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea387d7e18a6e9d345e414ae7820464080518358e1328f074f5b7a13750a1d05
|
|
| MD5 |
2b821efb5a236205b86fd60a666f36a6
|
|
| BLAKE2b-256 |
670b0b1d24d200e748d0d4a12267bc7fb0e1ddb14dd43036021c8a86f9990e54
|