jprotect 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. jprotect-0.1.0/LICENSE +118 -0
  2. jprotect-0.1.0/PKG-INFO +362 -0
  3. jprotect-0.1.0/README.md +220 -0
  4. jprotect-0.1.0/pyproject.toml +42 -0
  5. jprotect-0.1.0/setup.cfg +4 -0
  6. jprotect-0.1.0/src/jprotect/__init__.py +4 -0
  7. jprotect-0.1.0/src/jprotect/__main__.py +5 -0
  8. jprotect-0.1.0/src/jprotect/cli/__init__.py +1 -0
  9. jprotect-0.1.0/src/jprotect/cli/main.py +64 -0
  10. jprotect-0.1.0/src/jprotect/config/__init__.py +1 -0
  11. jprotect-0.1.0/src/jprotect/config/loader.py +55 -0
  12. jprotect-0.1.0/src/jprotect/config/schema.py +29 -0
  13. jprotect-0.1.0/src/jprotect/core/__init__.py +1 -0
  14. jprotect-0.1.0/src/jprotect/core/compile/__init__.py +1 -0
  15. jprotect-0.1.0/src/jprotect/core/compile/cython_backend.py +106 -0
  16. jprotect-0.1.0/src/jprotect/core/discovery.py +27 -0
  17. jprotect-0.1.0/src/jprotect/core/filtering.py +37 -0
  18. jprotect-0.1.0/src/jprotect/core/pipeline.py +83 -0
  19. jprotect-0.1.0/src/jprotect/core/postprocess.py +18 -0
  20. jprotect-0.1.0/src/jprotect/core/report.py +61 -0
  21. jprotect-0.1.0/src/jprotect/core/safety.py +32 -0
  22. jprotect-0.1.0/src/jprotect/core/transform/__init__.py +1 -0
  23. jprotect-0.1.0/src/jprotect/core/transform/ast_transformer.py +501 -0
  24. jprotect-0.1.0/src/jprotect/core/transform/transformer.py +100 -0
  25. jprotect-0.1.0/src/jprotect/errors.py +10 -0
  26. jprotect-0.1.0/src/jprotect/utils/__init__.py +1 -0
  27. jprotect-0.1.0/src/jprotect/utils/paths.py +9 -0
  28. jprotect-0.1.0/src/jprotect.egg-info/PKG-INFO +362 -0
  29. jprotect-0.1.0/src/jprotect.egg-info/SOURCES.txt +31 -0
  30. jprotect-0.1.0/src/jprotect.egg-info/dependency_links.txt +1 -0
  31. jprotect-0.1.0/src/jprotect.egg-info/entry_points.txt +2 -0
  32. jprotect-0.1.0/src/jprotect.egg-info/requires.txt +5 -0
  33. jprotect-0.1.0/src/jprotect.egg-info/top_level.txt +1 -0
jprotect-0.1.0/LICENSE ADDED
@@ -0,0 +1,118 @@
1
+ PolyForm Noncommercial License 1.0.0
2
+
3
+ https://polyformproject.org/licenses/noncommercial/1.0.0
4
+
5
+ Required Notice: Copyright (c) 2024 Duong Tien Hieu (tienhieu1212@gmail.com)
6
+
7
+ Acceptance
8
+
9
+ In order to get any license under these terms, you must agree to them as
10
+ both strict obligations and conditions to all your licenses.
11
+
12
+ Copyright License
13
+
14
+ The licensor grants you a copyright license for the software to do
15
+ everything you might do with the software that would otherwise infringe
16
+ the licensor's copyright in it for any permitted purpose. However, you
17
+ may only distribute the software according to Distribution License and
18
+ make changes or new works based on the software according to Changes and
19
+ New Works License.
20
+
21
+ Distribution License
22
+
23
+ The licensor grants you an additional copyright license to distribute
24
+ copies of the software. Your license to distribute covers distributing
25
+ the software with changes and new works permitted by Changes and New
26
+ Works License.
27
+
28
+ Notices
29
+
30
+ You must ensure that anyone who gets a copy of any part of the software
31
+ from you also gets a copy of these terms or the URL for them above, as
32
+ well as copies of any plain-text lines beginning with Required Notice:
33
+ that the licensor provided with the software.
34
+
35
+ Changes and New Works License
36
+
37
+ The licensor grants you an additional copyright license to make changes
38
+ and new works based on the software for any permitted purpose.
39
+
40
+ Patent License
41
+
42
+ The licensor grants you a patent license for the software that covers
43
+ patent claims the licensor can license, or becomes able to license, that
44
+ you would infringe by using the software.
45
+
46
+ Noncommercial Purposes
47
+
48
+ Any noncommercial purpose is a permitted purpose.
49
+
50
+ Personal Uses
51
+
52
+ Personal use for research, experiment, and testing for the benefit of
53
+ public knowledge, personal study, private entertainment, hobby projects,
54
+ amateur pursuits, or religious observance, without any anticipated
55
+ commercial application, is use for a permitted purpose.
56
+
57
+ Noncommercial Organizations
58
+
59
+ Use by any charitable organization, educational institution, public
60
+ research organization, public safety or health organization,
61
+ environmental protection organization, or government institution is use
62
+ for a permitted purpose regardless of the source of funding or
63
+ obligations resulting from the funding.
64
+
65
+ Fair Use
66
+
67
+ You may have "fair use" rights for the software under the law. These
68
+ terms do not limit them.
69
+
70
+ No Other Rights
71
+
72
+ These terms do not allow you to sublicense or transfer any of your
73
+ licenses to anyone else, or prevent the licensor from granting licenses
74
+ to anyone else. These terms do not imply any other licenses.
75
+
76
+ Patent Defense
77
+
78
+ If you make any written claim that the software infringes or contributes
79
+ to infringement of any patent, your patent license for the software
80
+ granted under these terms ends immediately. If your company makes such a
81
+ claim, your patent license ends immediately for work on behalf of your
82
+ company.
83
+
84
+ Violations
85
+
86
+ The first time you are notified in writing that you have violated any of
87
+ these terms, or done anything with the software not covered by your
88
+ licenses, your licenses can nonetheless continue if you come into full
89
+ compliance with these terms, and take practical steps to correct past
90
+ violations, within 32 days of receiving notice. Otherwise, all your
91
+ licenses end immediately.
92
+
93
+ No Liability
94
+
95
+ As far as the law allows, the software comes as is, without any warranty
96
+ or condition, and the licensor will not be liable to you for any damages
97
+ arising out of these terms or the use or nature of the software, under
98
+ any kind of legal claim.
99
+
100
+ Definitions
101
+
102
+ The licensor is the individual or entity offering these terms, and the
103
+ software is the software the licensor makes available under these terms.
104
+
105
+ You refers to the individual or entity agreeing to these terms.
106
+
107
+ Your company is any legal entity, sole proprietorship, or other kind of
108
+ organization that you work for, plus all organizations that have control
109
+ over, are under the control of, or are under common control with that
110
+ organization. Control means ownership of substantially all the assets of
111
+ an entity, or the power to direct its management and policies by vote,
112
+ contract, or otherwise. Control can be direct or indirect.
113
+
114
+ Your licenses are all the licenses granted to you for the software under
115
+ these terms.
116
+
117
+ Use means anything you do with the software requiring one of your
118
+ licenses.
@@ -0,0 +1,362 @@
1
+ Metadata-Version: 2.4
2
+ Name: jprotect
3
+ Version: 0.1.0
4
+ Summary: Tool bao ve source code module Odoo theo huong an toan.
5
+ Author-email: Duong Tien Hieu <tienhieu1212@gmail.com>
6
+ License: PolyForm Noncommercial License 1.0.0
7
+
8
+ https://polyformproject.org/licenses/noncommercial/1.0.0
9
+
10
+ Required Notice: Copyright (c) 2024 Duong Tien Hieu (tienhieu1212@gmail.com)
11
+
12
+ Acceptance
13
+
14
+ In order to get any license under these terms, you must agree to them as
15
+ both strict obligations and conditions to all your licenses.
16
+
17
+ Copyright License
18
+
19
+ The licensor grants you a copyright license for the software to do
20
+ everything you might do with the software that would otherwise infringe
21
+ the licensor's copyright in it for any permitted purpose. However, you
22
+ may only distribute the software according to Distribution License and
23
+ make changes or new works based on the software according to Changes and
24
+ New Works License.
25
+
26
+ Distribution License
27
+
28
+ The licensor grants you an additional copyright license to distribute
29
+ copies of the software. Your license to distribute covers distributing
30
+ the software with changes and new works permitted by Changes and New
31
+ Works License.
32
+
33
+ Notices
34
+
35
+ You must ensure that anyone who gets a copy of any part of the software
36
+ from you also gets a copy of these terms or the URL for them above, as
37
+ well as copies of any plain-text lines beginning with Required Notice:
38
+ that the licensor provided with the software.
39
+
40
+ Changes and New Works License
41
+
42
+ The licensor grants you an additional copyright license to make changes
43
+ and new works based on the software for any permitted purpose.
44
+
45
+ Patent License
46
+
47
+ The licensor grants you a patent license for the software that covers
48
+ patent claims the licensor can license, or becomes able to license, that
49
+ you would infringe by using the software.
50
+
51
+ Noncommercial Purposes
52
+
53
+ Any noncommercial purpose is a permitted purpose.
54
+
55
+ Personal Uses
56
+
57
+ Personal use for research, experiment, and testing for the benefit of
58
+ public knowledge, personal study, private entertainment, hobby projects,
59
+ amateur pursuits, or religious observance, without any anticipated
60
+ commercial application, is use for a permitted purpose.
61
+
62
+ Noncommercial Organizations
63
+
64
+ Use by any charitable organization, educational institution, public
65
+ research organization, public safety or health organization,
66
+ environmental protection organization, or government institution is use
67
+ for a permitted purpose regardless of the source of funding or
68
+ obligations resulting from the funding.
69
+
70
+ Fair Use
71
+
72
+ You may have "fair use" rights for the software under the law. These
73
+ terms do not limit them.
74
+
75
+ No Other Rights
76
+
77
+ These terms do not allow you to sublicense or transfer any of your
78
+ licenses to anyone else, or prevent the licensor from granting licenses
79
+ to anyone else. These terms do not imply any other licenses.
80
+
81
+ Patent Defense
82
+
83
+ If you make any written claim that the software infringes or contributes
84
+ to infringement of any patent, your patent license for the software
85
+ granted under these terms ends immediately. If your company makes such a
86
+ claim, your patent license ends immediately for work on behalf of your
87
+ company.
88
+
89
+ Violations
90
+
91
+ The first time you are notified in writing that you have violated any of
92
+ these terms, or done anything with the software not covered by your
93
+ licenses, your licenses can nonetheless continue if you come into full
94
+ compliance with these terms, and take practical steps to correct past
95
+ violations, within 32 days of receiving notice. Otherwise, all your
96
+ licenses end immediately.
97
+
98
+ No Liability
99
+
100
+ As far as the law allows, the software comes as is, without any warranty
101
+ or condition, and the licensor will not be liable to you for any damages
102
+ arising out of these terms or the use or nature of the software, under
103
+ any kind of legal claim.
104
+
105
+ Definitions
106
+
107
+ The licensor is the individual or entity offering these terms, and the
108
+ software is the software the licensor makes available under these terms.
109
+
110
+ You refers to the individual or entity agreeing to these terms.
111
+
112
+ Your company is any legal entity, sole proprietorship, or other kind of
113
+ organization that you work for, plus all organizations that have control
114
+ over, are under the control of, or are under common control with that
115
+ organization. Control means ownership of substantially all the assets of
116
+ an entity, or the power to direct its management and policies by vote,
117
+ contract, or otherwise. Control can be direct or indirect.
118
+
119
+ Your licenses are all the licenses granted to you for the software under
120
+ these terms.
121
+
122
+ Use means anything you do with the software requiring one of your
123
+ licenses.
124
+
125
+ Keywords: odoo,protect,cython,obfuscate
126
+ Classifier: Development Status :: 3 - Alpha
127
+ Classifier: Intended Audience :: Developers
128
+ Classifier: License :: Other/Proprietary License
129
+ Classifier: Programming Language :: Python :: 3
130
+ Classifier: Programming Language :: Python :: 3.10
131
+ Classifier: Programming Language :: Python :: 3.11
132
+ Classifier: Programming Language :: Python :: 3.12
133
+ Classifier: Topic :: Software Development :: Build Tools
134
+ Requires-Python: >=3.10
135
+ Description-Content-Type: text/markdown
136
+ License-File: LICENSE
137
+ Requires-Dist: Cython<3.2,>=3.0
138
+ Requires-Dist: setuptools>=61
139
+ Provides-Extra: test
140
+ Requires-Dist: pytest>=7; extra == "test"
141
+ Dynamic: license-file
142
+
143
+ # jProtect
144
+
145
+ **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.
146
+
147
+ [![PyPI version](https://img.shields.io/pypi/v/jprotect)](https://pypi.org/project/jprotect/)
148
+ [![Python](https://img.shields.io/pypi/pyversions/jprotect)](https://pypi.org/project/jprotect/)
149
+ [![License: PolyForm NC](https://img.shields.io/badge/License-PolyForm%20NC-blue.svg)](LICENSE)
150
+
151
+ ---
152
+
153
+ ## 🔒 What It Does
154
+
155
+ jProtect takes an Odoo module and:
156
+
157
+ 1. **Keeps the public file intact** — class definitions, fields, decorators, and `_name`/`_inherit` stay in place so Odoo registers the model normally.
158
+ 2. **Extracts method bodies** into a hidden `models/_protected/` package as standalone functions.
159
+ 3. **Replaces each method body** with a thin delegation call to `_protected`.
160
+ 4. **Compiles `_protected/`** into `.so`/`.pyd` binaries (optional `--compile` flag).
161
+
162
+ The result: a module that looks and behaves exactly like the original — but the business logic is gone from the source files.
163
+
164
+ ---
165
+
166
+ ## ✨ Features
167
+
168
+ - 🔍 **Dry-run mode** — preview what will be protected before writing anything
169
+ - ⚙️ **Selective protection** — include/exclude files with glob patterns
170
+ - 🚀 **Cython compilation** — compile protected code to native binaries
171
+ - 🔄 **`super()` rewriting** — zero-arg `super()` is automatically rewritten to `super(cls, self)` so inheritance chains keep working
172
+ - 🛡️ **Safe by default** — skips dunders, `@property`, generators, `__init__.py`, migrations, and any pattern that could break Odoo
173
+
174
+ ---
175
+
176
+ ## 📦 Installation
177
+
178
+ Requires Python 3.10+. Cython is installed automatically.
179
+
180
+ ```bash
181
+ pip install jprotect
182
+ ```
183
+
184
+ > When using `--compile`, a C compiler is also required:
185
+ > - **Linux**: `gcc` + `python3-dev`
186
+ > - **Windows**: MSVC Build Tools
187
+
188
+ ---
189
+
190
+ ## 🚀 Quick Start
191
+
192
+ Given a module at `./addons/sale_ext`:
193
+
194
+ ```bash
195
+ # Step 1 — Preview (no files written)
196
+ jprotect protect-module \
197
+ --input ./addons/sale_ext \
198
+ --output ./dist/dist/sale_ext \
199
+ --dry-run
200
+
201
+ # Step 2 — Protect (extract logic, no compile)
202
+ jprotect protect-module \
203
+ --input ./addons/sale_ext \
204
+ --output ./dist/dist/sale_ext
205
+
206
+ # Step 3 — Protect + compile to binary
207
+ jprotect protect-module \
208
+ --input ./addons/sale_ext \
209
+ --output ./dist/dist/sale_ext \
210
+ --compile
211
+ ```
212
+
213
+ After running, jProtect generates a `protection-manifest.json` in the output directory listing every processed file.
214
+
215
+ ---
216
+
217
+ ## 🔍 How It Works
218
+
219
+ ```python
220
+ # ── Original file ────────────────────────────────────────────────
221
+ class SaleOrder(models.Model):
222
+ _inherit = 'sale.order'
223
+
224
+ def action_confirm(self):
225
+ # your business logic here...
226
+ return super().action_confirm()
227
+
228
+
229
+ # ── Public file after jProtect ───────────────────────────────────
230
+ from . import _protected
231
+
232
+ class SaleOrder(models.Model):
233
+ _inherit = 'sale.order'
234
+
235
+ def action_confirm(self):
236
+ return _protected.sale_order.SaleOrder__action_confirm(self, SaleOrder)
237
+
238
+
239
+ # ── _protected/sale_order.py (or .so after --compile) ───────────
240
+ def SaleOrder__action_confirm(self, cls):
241
+ # your business logic here...
242
+ return super(cls, self).action_confirm()
243
+ ```
244
+
245
+ Odoo sees the same class structure and registers the model exactly as before. The logic only lives inside the compiled binary.
246
+
247
+ ---
248
+
249
+ ## ⚙️ CLI Reference
250
+
251
+ ```
252
+ jprotect protect-module --input <dir> --output <dir> [options]
253
+ ```
254
+
255
+ | Option | Description | Example |
256
+ |---|---|---|
257
+ | `--input` | Odoo module directory (must contain `__manifest__.py`) | `--input ./addons/sale_ext` |
258
+ | `--output` | Output directory | `--output ./dist/dist/sale_ext` |
259
+ | `--mode` | `dist` creates a copy (default); `inplace` modifies in place | `--mode inplace` |
260
+ | `--dry-run` | Scan and report only, no files written | `--dry-run` |
261
+ | `--compile` | Compile `_protected/` to `.so`/`.pyd` | `--compile` |
262
+ | `--include` | Glob pattern for files to protect (repeatable, default: `models/**/*.py`) | `--include "models/**/*.py" --include "utils/*.py"` |
263
+ | `--exclude` | Glob pattern for files to exclude (repeatable) | `--exclude "models/res_*.py"` |
264
+
265
+ ---
266
+
267
+ ## 🐳 Docker
268
+
269
+ Build once, run anywhere — useful for compiling binaries that match your Odoo server environment:
270
+
271
+ ```bash
272
+ docker build -t jprotect .
273
+
274
+ docker run --rm \
275
+ -v "$PWD/addons/sale_ext:/work/input:ro" \
276
+ -v "$PWD/dist:/work/output" \
277
+ jprotect protect-module \
278
+ --input /work/input \
279
+ --output /work/output/dist/sale_ext \
280
+ --compile
281
+ ```
282
+
283
+ ---
284
+
285
+ ## ⚠️ Important Notes
286
+
287
+ **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.
288
+
289
+ | Odoo Version | Python |
290
+ |---|---|
291
+ | 16, 17, 18 | 3.10 |
292
+ | 14, 15 | 3.8 |
293
+
294
+ **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.
295
+
296
+ ---
297
+
298
+ ## 🛡️ What Gets Protected
299
+
300
+ jProtect protects regular instance methods only. The following are intentionally left untouched:
301
+
302
+ | Skipped | Reason |
303
+ |---|---|
304
+ | `@staticmethod`, `@classmethod`, `@property` | Different call semantics, cannot be safely delegated |
305
+ | Property setters/deleters (`@x.setter`, `@x.deleter`) | Setter return values are ignored by Python; wrapping changes semantics |
306
+ | Dunder methods (`__init__`, `__str__`, ...) | Called directly by Odoo/Python internals |
307
+ | Generator methods (contain `yield`) | Extracting a generator body breaks the iterator protocol |
308
+ | Methods with `super()` inside nested functions | `super()` without args relies on the declaring scope's `__class__` cell |
309
+ | `__init__.py`, `migrations/`, `controllers/` | Breaking these would prevent Odoo from loading the module |
310
+
311
+ ---
312
+
313
+ ## 🛠️ Development
314
+
315
+ ### Setup
316
+
317
+ ```bash
318
+ git clone https://github.com/your-org/jprotect.git
319
+ cd jprotect
320
+
321
+ python -m venv .venv
322
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
323
+
324
+ pip install -e ".[test]"
325
+ ```
326
+
327
+ ### Run tests
328
+
329
+ ```bash
330
+ pytest -q # all tests
331
+ pytest tests/unit/ -q # unit tests only
332
+ pytest tests/integration/ -q # integration tests only
333
+ pytest tests/unit/test_ast_transformer.py -v # specific file
334
+ ```
335
+
336
+ ### Project structure
337
+
338
+ ```
339
+ src/jprotect/
340
+ ├── cli/ # CLI entry point (argparse)
341
+ ├── config/ # Config schema and loader
342
+ ├── core/
343
+ │ ├── compile/ # Cython backend
344
+ │ ├── transform/ # Core AST transformation logic
345
+ │ │ ├── ast_transformer.py # parse, extract, build delegation
346
+ │ │ └── transformer.py # orchestrate transform over directory tree
347
+ │ ├── pipeline.py
348
+ │ └── ...
349
+ └── errors.py
350
+
351
+ tests/
352
+ ├── unit/ # per-function tests with real source strings
353
+ └── integration/ # full pipeline tests on a fixture Odoo module
354
+ ```
355
+
356
+ See [`docs/CODE_CONVENTIONS.md`](docs/CODE_CONVENTIONS.md) for coding conventions.
357
+
358
+ ---
359
+
360
+ ## 📄 License
361
+
362
+ PolyForm Noncommercial 1.0.0 — free for personal and noncommercial use. Commercial use requires a separate license from the author. See [LICENSE](LICENSE).
@@ -0,0 +1,220 @@
1
+ # jProtect
2
+
3
+ **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.
4
+
5
+ [![PyPI version](https://img.shields.io/pypi/v/jprotect)](https://pypi.org/project/jprotect/)
6
+ [![Python](https://img.shields.io/pypi/pyversions/jprotect)](https://pypi.org/project/jprotect/)
7
+ [![License: PolyForm NC](https://img.shields.io/badge/License-PolyForm%20NC-blue.svg)](LICENSE)
8
+
9
+ ---
10
+
11
+ ## 🔒 What It Does
12
+
13
+ jProtect takes an Odoo module and:
14
+
15
+ 1. **Keeps the public file intact** — class definitions, fields, decorators, and `_name`/`_inherit` stay in place so Odoo registers the model normally.
16
+ 2. **Extracts method bodies** into a hidden `models/_protected/` package as standalone functions.
17
+ 3. **Replaces each method body** with a thin delegation call to `_protected`.
18
+ 4. **Compiles `_protected/`** into `.so`/`.pyd` binaries (optional `--compile` flag).
19
+
20
+ The result: a module that looks and behaves exactly like the original — but the business logic is gone from the source files.
21
+
22
+ ---
23
+
24
+ ## ✨ Features
25
+
26
+ - 🔍 **Dry-run mode** — preview what will be protected before writing anything
27
+ - ⚙️ **Selective protection** — include/exclude files with glob patterns
28
+ - 🚀 **Cython compilation** — compile protected code to native binaries
29
+ - 🔄 **`super()` rewriting** — zero-arg `super()` is automatically rewritten to `super(cls, self)` so inheritance chains keep working
30
+ - 🛡️ **Safe by default** — skips dunders, `@property`, generators, `__init__.py`, migrations, and any pattern that could break Odoo
31
+
32
+ ---
33
+
34
+ ## 📦 Installation
35
+
36
+ Requires Python 3.10+. Cython is installed automatically.
37
+
38
+ ```bash
39
+ pip install jprotect
40
+ ```
41
+
42
+ > When using `--compile`, a C compiler is also required:
43
+ > - **Linux**: `gcc` + `python3-dev`
44
+ > - **Windows**: MSVC Build Tools
45
+
46
+ ---
47
+
48
+ ## 🚀 Quick Start
49
+
50
+ Given a module at `./addons/sale_ext`:
51
+
52
+ ```bash
53
+ # Step 1 — Preview (no files written)
54
+ jprotect protect-module \
55
+ --input ./addons/sale_ext \
56
+ --output ./dist/dist/sale_ext \
57
+ --dry-run
58
+
59
+ # Step 2 — Protect (extract logic, no compile)
60
+ jprotect protect-module \
61
+ --input ./addons/sale_ext \
62
+ --output ./dist/dist/sale_ext
63
+
64
+ # Step 3 — Protect + compile to binary
65
+ jprotect protect-module \
66
+ --input ./addons/sale_ext \
67
+ --output ./dist/dist/sale_ext \
68
+ --compile
69
+ ```
70
+
71
+ After running, jProtect generates a `protection-manifest.json` in the output directory listing every processed file.
72
+
73
+ ---
74
+
75
+ ## 🔍 How It Works
76
+
77
+ ```python
78
+ # ── Original file ────────────────────────────────────────────────
79
+ class SaleOrder(models.Model):
80
+ _inherit = 'sale.order'
81
+
82
+ def action_confirm(self):
83
+ # your business logic here...
84
+ return super().action_confirm()
85
+
86
+
87
+ # ── Public file after jProtect ───────────────────────────────────
88
+ from . import _protected
89
+
90
+ class SaleOrder(models.Model):
91
+ _inherit = 'sale.order'
92
+
93
+ def action_confirm(self):
94
+ return _protected.sale_order.SaleOrder__action_confirm(self, SaleOrder)
95
+
96
+
97
+ # ── _protected/sale_order.py (or .so after --compile) ───────────
98
+ def SaleOrder__action_confirm(self, cls):
99
+ # your business logic here...
100
+ return super(cls, self).action_confirm()
101
+ ```
102
+
103
+ Odoo sees the same class structure and registers the model exactly as before. The logic only lives inside the compiled binary.
104
+
105
+ ---
106
+
107
+ ## ⚙️ CLI Reference
108
+
109
+ ```
110
+ jprotect protect-module --input <dir> --output <dir> [options]
111
+ ```
112
+
113
+ | Option | Description | Example |
114
+ |---|---|---|
115
+ | `--input` | Odoo module directory (must contain `__manifest__.py`) | `--input ./addons/sale_ext` |
116
+ | `--output` | Output directory | `--output ./dist/dist/sale_ext` |
117
+ | `--mode` | `dist` creates a copy (default); `inplace` modifies in place | `--mode inplace` |
118
+ | `--dry-run` | Scan and report only, no files written | `--dry-run` |
119
+ | `--compile` | Compile `_protected/` to `.so`/`.pyd` | `--compile` |
120
+ | `--include` | Glob pattern for files to protect (repeatable, default: `models/**/*.py`) | `--include "models/**/*.py" --include "utils/*.py"` |
121
+ | `--exclude` | Glob pattern for files to exclude (repeatable) | `--exclude "models/res_*.py"` |
122
+
123
+ ---
124
+
125
+ ## 🐳 Docker
126
+
127
+ Build once, run anywhere — useful for compiling binaries that match your Odoo server environment:
128
+
129
+ ```bash
130
+ docker build -t jprotect .
131
+
132
+ docker run --rm \
133
+ -v "$PWD/addons/sale_ext:/work/input:ro" \
134
+ -v "$PWD/dist:/work/output" \
135
+ jprotect protect-module \
136
+ --input /work/input \
137
+ --output /work/output/dist/sale_ext \
138
+ --compile
139
+ ```
140
+
141
+ ---
142
+
143
+ ## ⚠️ Important Notes
144
+
145
+ **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.
146
+
147
+ | Odoo Version | Python |
148
+ |---|---|
149
+ | 16, 17, 18 | 3.10 |
150
+ | 14, 15 | 3.8 |
151
+
152
+ **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.
153
+
154
+ ---
155
+
156
+ ## 🛡️ What Gets Protected
157
+
158
+ jProtect protects regular instance methods only. The following are intentionally left untouched:
159
+
160
+ | Skipped | Reason |
161
+ |---|---|
162
+ | `@staticmethod`, `@classmethod`, `@property` | Different call semantics, cannot be safely delegated |
163
+ | Property setters/deleters (`@x.setter`, `@x.deleter`) | Setter return values are ignored by Python; wrapping changes semantics |
164
+ | Dunder methods (`__init__`, `__str__`, ...) | Called directly by Odoo/Python internals |
165
+ | Generator methods (contain `yield`) | Extracting a generator body breaks the iterator protocol |
166
+ | Methods with `super()` inside nested functions | `super()` without args relies on the declaring scope's `__class__` cell |
167
+ | `__init__.py`, `migrations/`, `controllers/` | Breaking these would prevent Odoo from loading the module |
168
+
169
+ ---
170
+
171
+ ## 🛠️ Development
172
+
173
+ ### Setup
174
+
175
+ ```bash
176
+ git clone https://github.com/your-org/jprotect.git
177
+ cd jprotect
178
+
179
+ python -m venv .venv
180
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
181
+
182
+ pip install -e ".[test]"
183
+ ```
184
+
185
+ ### Run tests
186
+
187
+ ```bash
188
+ pytest -q # all tests
189
+ pytest tests/unit/ -q # unit tests only
190
+ pytest tests/integration/ -q # integration tests only
191
+ pytest tests/unit/test_ast_transformer.py -v # specific file
192
+ ```
193
+
194
+ ### Project structure
195
+
196
+ ```
197
+ src/jprotect/
198
+ ├── cli/ # CLI entry point (argparse)
199
+ ├── config/ # Config schema and loader
200
+ ├── core/
201
+ │ ├── compile/ # Cython backend
202
+ │ ├── transform/ # Core AST transformation logic
203
+ │ │ ├── ast_transformer.py # parse, extract, build delegation
204
+ │ │ └── transformer.py # orchestrate transform over directory tree
205
+ │ ├── pipeline.py
206
+ │ └── ...
207
+ └── errors.py
208
+
209
+ tests/
210
+ ├── unit/ # per-function tests with real source strings
211
+ └── integration/ # full pipeline tests on a fixture Odoo module
212
+ ```
213
+
214
+ See [`docs/CODE_CONVENTIONS.md`](docs/CODE_CONVENTIONS.md) for coding conventions.
215
+
216
+ ---
217
+
218
+ ## 📄 License
219
+
220
+ PolyForm Noncommercial 1.0.0 — free for personal and noncommercial use. Commercial use requires a separate license from the author. See [LICENSE](LICENSE).