import-effects 0.0.1__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 (37) hide show
  1. import_effects-0.0.1/.github/ISSUE_TEMPLATE/bug.yml +33 -0
  2. import_effects-0.0.1/.github/ISSUE_TEMPLATE/feature.yml +19 -0
  3. import_effects-0.0.1/.github/PULL_REQUEST_TEMPLATE.md +11 -0
  4. import_effects-0.0.1/.github/dependabot.yml +11 -0
  5. import_effects-0.0.1/.github/workflows/ci.yml +79 -0
  6. import_effects-0.0.1/.github/workflows/release.yml +48 -0
  7. import_effects-0.0.1/.gitignore +24 -0
  8. import_effects-0.0.1/CHANGELOG.md +16 -0
  9. import_effects-0.0.1/CODE_OF_CONDUCT.md +8 -0
  10. import_effects-0.0.1/CONTRIBUTING.md +20 -0
  11. import_effects-0.0.1/LICENSE +22 -0
  12. import_effects-0.0.1/PKG-INFO +169 -0
  13. import_effects-0.0.1/README.md +133 -0
  14. import_effects-0.0.1/SECURITY.md +14 -0
  15. import_effects-0.0.1/docs/api.md +24 -0
  16. import_effects-0.0.1/docs/architecture.md +28 -0
  17. import_effects-0.0.1/docs/assets/demo.gif +0 -0
  18. import_effects-0.0.1/examples/demo_bad_package.py +31 -0
  19. import_effects-0.0.1/pyproject.toml +89 -0
  20. import_effects-0.0.1/scripts/render_demo.py +155 -0
  21. import_effects-0.0.1/src/import_effects/__init__.py +15 -0
  22. import_effects-0.0.1/src/import_effects/__main__.py +3 -0
  23. import_effects-0.0.1/src/import_effects/_probe.py +321 -0
  24. import_effects-0.0.1/src/import_effects/cli.py +175 -0
  25. import_effects-0.0.1/src/import_effects/inspector.py +124 -0
  26. import_effects-0.0.1/src/import_effects/models.py +85 -0
  27. import_effects-0.0.1/src/import_effects/py.typed +1 -0
  28. import_effects-0.0.1/tests/conftest.py +15 -0
  29. import_effects-0.0.1/tests/fixtures/broken_package.py +1 -0
  30. import_effects-0.0.1/tests/fixtures/clean_package.py +1 -0
  31. import_effects-0.0.1/tests/fixtures/effects_package.py +43 -0
  32. import_effects-0.0.1/tests/fixtures/output_package.py +1 -0
  33. import_effects-0.0.1/tests/fixtures/slow_package.py +3 -0
  34. import_effects-0.0.1/tests/test_cli.py +111 -0
  35. import_effects-0.0.1/tests/test_inspector.py +90 -0
  36. import_effects-0.0.1/tests/test_models.py +14 -0
  37. import_effects-0.0.1/tests/test_probe.py +91 -0
@@ -0,0 +1,33 @@
1
+ name: Bug report
2
+ description: Report incorrect or missing import observations
3
+ title: "bug: "
4
+ labels: [bug]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: Do not paste secrets or reports containing private paths without sanitizing them.
9
+ - type: input
10
+ id: version
11
+ attributes:
12
+ label: import-effects version
13
+ validations:
14
+ required: true
15
+ - type: input
16
+ id: platform
17
+ attributes:
18
+ label: Python and operating system
19
+ validations:
20
+ required: true
21
+ - type: textarea
22
+ id: reproduction
23
+ attributes:
24
+ label: Minimal reproduction
25
+ validations:
26
+ required: true
27
+ - type: textarea
28
+ id: expected
29
+ attributes:
30
+ label: Expected behavior
31
+ validations:
32
+ required: true
33
+
@@ -0,0 +1,19 @@
1
+ name: Feature request
2
+ description: Propose a reliable new observation or developer workflow
3
+ title: "feat: "
4
+ labels: [enhancement]
5
+ body:
6
+ - type: textarea
7
+ id: problem
8
+ attributes:
9
+ label: Problem
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: evidence
14
+ attributes:
15
+ label: Reliable runtime evidence or API
16
+ description: Explain how the behavior can be observed without overstating attribution.
17
+ validations:
18
+ required: true
19
+
@@ -0,0 +1,11 @@
1
+ ## Summary
2
+
3
+ ## Verification
4
+
5
+ - [ ] `ruff format --check .`
6
+ - [ ] `ruff check .`
7
+ - [ ] `mypy`
8
+ - [ ] `pytest --cov`
9
+ - [ ] `python -m build && twine check dist/*`
10
+ - [ ] No private reports, tokens, or generated artifacts are included
11
+
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ - package-ecosystem: github-actions
8
+ directory: /
9
+ schedule:
10
+ interval: weekly
11
+
@@ -0,0 +1,79 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ concurrency:
10
+ group: ci-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ quality:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v5
21
+ with:
22
+ fetch-depth: 0
23
+ - uses: actions/setup-python@v6
24
+ with:
25
+ python-version: "3.12"
26
+ cache: pip
27
+ - run: python -m pip install -e '.[dev]'
28
+ - run: ruff format --check .
29
+ - run: ruff check .
30
+ - run: mypy
31
+ - run: pytest --cov --cov-report=term-missing --cov-report=xml
32
+ - run: python -m build
33
+ - run: twine check dist/*
34
+ - name: Inspect distributions
35
+ run: |
36
+ python -m zipfile -l dist/*.whl
37
+ tar -tzf dist/*.tar.gz
38
+ - name: Install Gitleaks
39
+ run: |
40
+ curl --fail --location --silent --show-error \
41
+ https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz \
42
+ | tar -xz -C /tmp gitleaks
43
+ - name: Scan repository history
44
+ run: /tmp/gitleaks git --redact --exit-code 1 .
45
+
46
+ test:
47
+ strategy:
48
+ fail-fast: false
49
+ matrix:
50
+ os: [ubuntu-latest, macos-latest, windows-latest]
51
+ python: ["3.10", "3.12", "3.14"]
52
+ exclude:
53
+ - os: macos-latest
54
+ python: "3.10"
55
+ - os: windows-latest
56
+ python: "3.10"
57
+ runs-on: ${{ matrix.os }}
58
+ steps:
59
+ - uses: actions/checkout@v5
60
+ - uses: actions/setup-python@v6
61
+ with:
62
+ python-version: ${{ matrix.python }}
63
+ cache: pip
64
+ - run: python -m pip install -e '.[dev]'
65
+ - run: pytest
66
+
67
+ wheel-smoke:
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - uses: actions/checkout@v5
71
+ - uses: actions/setup-python@v6
72
+ with:
73
+ python-version: "3.12"
74
+ - run: python -m pip install build
75
+ - run: python -m build
76
+ - run: python -m venv /tmp/import-effects-consumer
77
+ - run: /tmp/import-effects-consumer/bin/pip install dist/*.whl
78
+ - run: /tmp/import-effects-consumer/bin/import-effects json --quiet
79
+ - run: /tmp/import-effects-consumer/bin/python -c "from import_effects import inspect_import; assert inspect_import('json').success"
@@ -0,0 +1,48 @@
1
+ name: Publish PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+ id-token: write
10
+
11
+ jobs:
12
+ publish:
13
+ if: startsWith(github.event.release.tag_name, 'v')
14
+ runs-on: ubuntu-latest
15
+ environment: pypi
16
+ steps:
17
+ - uses: actions/checkout@v5
18
+ - uses: actions/setup-python@v6
19
+ with:
20
+ python-version: "3.12"
21
+ - run: python -m pip install build twine
22
+ - run: python -m build
23
+ - run: twine check dist/*
24
+ - name: Check whether this version is already published
25
+ id: registry
26
+ run: |
27
+ version="${GITHUB_REF_NAME#v}"
28
+ if python - "$version" <<'PY'
29
+ import sys
30
+ import urllib.error
31
+ import urllib.request
32
+
33
+ try:
34
+ urllib.request.urlopen(
35
+ f"https://pypi.org/pypi/import-effects/{sys.argv[1]}/json", timeout=15
36
+ )
37
+ except urllib.error.HTTPError as error:
38
+ raise SystemExit(1 if error.code == 404 else 2)
39
+ PY
40
+ then
41
+ echo "published=true" >> "$GITHUB_OUTPUT"
42
+ else
43
+ echo "published=false" >> "$GITHUB_OUTPUT"
44
+ fi
45
+ - name: Publish with trusted publishing
46
+ if: steps.registry.outputs.published != 'true'
47
+ uses: pypa/gh-action-pypi-publish@release/v1
48
+
@@ -0,0 +1,24 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .coverage
6
+ coverage.xml
7
+ htmlcov/
8
+ .mypy_cache/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ build/
12
+ dist/
13
+ *.whl
14
+ *.tar.gz
15
+ .env
16
+ .env.*
17
+ !.env.example
18
+ .DS_Store
19
+ .idea/
20
+ .vscode/
21
+ docs/assets/*.mp4
22
+ launch*.md
23
+ x-launch*.md
24
+
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ ## [0.0.1] - 2026-09-22
6
+
7
+ ### Added
8
+
9
+ - Fresh-subprocess import inspection with timeout handling.
10
+ - Audit-based file, network, subprocess, and filesystem observations.
11
+ - Thread, multiprocessing, environment, cwd, logging, path, warning, and signal observations.
12
+ - Typed Python API, JSON output, policy exits, ignores, and assertion helper.
13
+ - CPython 3.10 through 3.14 CI across Linux, macOS, and Windows.
14
+
15
+ [0.0.1]: https://github.com/royalpinto007/import-effects/releases/tag/v0.0.1
16
+
@@ -0,0 +1,8 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ We pledge to make participation in this project a harassment-free experience for everyone. Be respectful, constructive, and considerate.
4
+
5
+ Unacceptable behavior includes harassment, discriminatory language, personal attacks, publishing private information, or other conduct inappropriate in a professional community.
6
+
7
+ Report conduct concerns privately to royalpinto007@gmail.com. Maintainers may remove, edit, or reject contributions and ban participants whose behavior violates this code.
8
+
@@ -0,0 +1,20 @@
1
+ # Contributing
2
+
3
+ Contributions are welcome. Please open an issue before changing public behavior or adding a new effect kind.
4
+
5
+ ```bash
6
+ python -m venv .venv
7
+ . .venv/bin/activate
8
+ pip install -e '.[dev]'
9
+ ruff format .
10
+ ruff check .
11
+ mypy
12
+ pytest --cov
13
+ python -m build
14
+ twine check dist/*
15
+ ```
16
+
17
+ Tests should exercise behavior through the public API or CLI in a real child interpreter. Do not add observations that cannot be reproduced reliably, and keep confidence and attribution claims conservative.
18
+
19
+ Use Conventional Commits and do not commit captured environment data, tokens, local package sources, or generated artifacts.
20
+
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Royal Pinto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,169 @@
1
+ Metadata-Version: 2.5
2
+ Name: import-effects
3
+ Version: 0.0.1
4
+ Summary: See what Python does when you import.
5
+ Project-URL: Homepage, https://github.com/royalpinto007/import-effects
6
+ Project-URL: Documentation, https://github.com/royalpinto007/import-effects#readme
7
+ Project-URL: Issues, https://github.com/royalpinto007/import-effects/issues
8
+ Project-URL: Source, https://github.com/royalpinto007/import-effects
9
+ Author-email: Royal Pinto <royalpinto007@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: audit-hooks,cli,debugging,imports,observability,python,security,side-effects,testing
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Programming Language :: Python :: Implementation :: CPython
25
+ Classifier: Topic :: Software Development :: Debuggers
26
+ Classifier: Topic :: Software Development :: Testing
27
+ Requires-Python: >=3.10
28
+ Provides-Extra: dev
29
+ Requires-Dist: build>=1.3; extra == 'dev'
30
+ Requires-Dist: mypy>=1.17; extra == 'dev'
31
+ Requires-Dist: pytest-cov>=6.2; extra == 'dev'
32
+ Requires-Dist: pytest>=8.4; extra == 'dev'
33
+ Requires-Dist: ruff>=0.12; extra == 'dev'
34
+ Requires-Dist: twine>=6.2; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # import-effects
38
+
39
+ > See what Python does when you `import`.
40
+
41
+ [![PyPI](https://img.shields.io/pypi/v/import-effects)](https://pypi.org/project/import-effects/) [![Python](https://img.shields.io/pypi/pyversions/import-effects)](https://pypi.org/project/import-effects/) [![CI](https://github.com/royalpinto007/import-effects/actions/workflows/ci.yml/badge.svg)](https://github.com/royalpinto007/import-effects/actions/workflows/ci.yml) [![license](https://img.shields.io/pypi/l/import-effects)](LICENSE)
42
+
43
+ `import-effects` runs one import in a fresh child interpreter and reports file writes, sockets, subprocesses, threads, environment changes, and other observable import-time behavior.
44
+
45
+ ```bash
46
+ pip install import-effects
47
+ import-effects requests
48
+ ```
49
+
50
+ ![A Python import starts a thread, opens a socket, writes a file, and launches a subprocess](docs/assets/demo.gif)
51
+
52
+ ## 30-second quickstart
53
+
54
+ ```console
55
+ $ import-effects mypackage
56
+ import mypackage
57
+
58
+ ✓ imported in 143 ms
59
+
60
+ SIDE EFFECTS
61
+
62
+ ⚠ FILE WRITE
63
+ /home/me/.cache/mypackage/config.json
64
+
65
+ ⚠ NETWORK
66
+ api.example.com:443
67
+
68
+ ⚠ THREAD
69
+ background-worker
70
+
71
+ 3 side effects detected · 1 file-write · 1 network · 1 thread
72
+ ```
73
+
74
+ The target must already be importable. `import-effects` never installs it and normal inspection needs no server, database, Docker, network access, or elevated privileges.
75
+
76
+ ## CLI
77
+
78
+ ```bash
79
+ import-effects package.submodule
80
+ import-effects requests --json
81
+ import-effects requests --quiet
82
+ import-effects requests --verbose
83
+ import-effects requests --timeout 10
84
+ import-effects requests --fail-on network,subprocess,file-write
85
+ import-effects requests --ignore '~/.cache/**'
86
+ ```
87
+
88
+ `--fail-on` turns selected observations into policy failures without pretending every observation is inherently unsafe. `--ignore` matches the human-readable effect detail and may be repeated.
89
+
90
+ Exit codes:
91
+
92
+ | Code | Meaning |
93
+ | ---: | ------------------------------------------------- |
94
+ | 0 | Import succeeded with no configured violation |
95
+ | 1 | A configured `--fail-on` effect was detected |
96
+ | 2 | Invalid CLI input |
97
+ | 3 | Target import failed or timed out |
98
+ | 4 | Internal inspector failure |
99
+
100
+ ## Python API
101
+
102
+ ```python
103
+ from import_effects import inspect_import
104
+
105
+ report = inspect_import("mypackage", timeout=10)
106
+
107
+ print(report.duration_ms)
108
+ for effect in report.effects:
109
+ print(effect.kind, effect.detail, effect.confidence)
110
+ ```
111
+
112
+ For tests:
113
+
114
+ ```python
115
+ from import_effects import assert_no_effects
116
+
117
+
118
+ def test_import_stays_quiet() -> None:
119
+ assert_no_effects("mypackage", forbidden=("network", "subprocess", "file-write"))
120
+ ```
121
+
122
+ The models are frozen, typed dataclasses. Reports can be converted with `report.to_dict()` and filtered with `report.effects_of("network")`.
123
+
124
+ ## What it observes
125
+
126
+ - files opened for writing, removal, rename, and directory operations
127
+ - socket connect, bind, and DNS activity
128
+ - subprocess spawning, `os.system`, and process forks
129
+ - Python threads and `multiprocessing` children started
130
+ - environment variable names added, removed, or changed, never their values
131
+ - current directory, logging handlers, `sys.path`, warning filters, and signal handlers
132
+ - newly imported module names, import duration, stdout/stderr, failures, crashes, and timeouts
133
+
134
+ CPython audit events provide high-confidence observations for many OS operations. Before/after snapshots and lifecycle wrappers cover state changes and thread/process starts. Each effect includes confidence and attribution metadata because an effect may come from the target, one of its dependencies, or code merely observed during the import window.
135
+
136
+ See [Architecture and limitations](docs/architecture.md) and the [API reference](docs/api.md).
137
+
138
+ ## Security warning
139
+
140
+ **Importing untrusted Python code executes that code. `import-effects` is an observer, not a sandbox.**
141
+
142
+ The target runs in a separate child interpreter, so it cannot directly mutate the parent Python process. It still runs as your user with normal filesystem, network, and process permissions. Use an OS sandbox or disposable virtual machine when inspecting code you do not trust.
143
+
144
+ Target stdout and stderr are capped. Suspected credentials in captured messages are redacted, and environment variable values are never included. Audit hooks are visibility mechanisms, not a security boundary, and sufficiently hostile native code can evade or disable Python-level observation.
145
+
146
+ ## Platform support
147
+
148
+ `import-effects` targets CPython 3.10 through 3.14 on Linux, macOS, and Windows. Audit event availability and process termination behavior differ by Python and OS. Linux currently provides the broadest coverage. Windows does not offer the same process-group cleanup guarantees as POSIX, and some native extensions perform operations below CPython's audit surface.
149
+
150
+ ## Development
151
+
152
+ ```bash
153
+ python -m venv .venv
154
+ . .venv/bin/activate
155
+ pip install -e '.[dev]'
156
+ ruff format --check .
157
+ ruff check .
158
+ mypy
159
+ pytest --cov
160
+ python -m build
161
+ twine check dist/*
162
+ ```
163
+
164
+ See [Contributing](CONTRIBUTING.md), [Security](SECURITY.md), and the [Changelog](CHANGELOG.md).
165
+
166
+ ## License
167
+
168
+ MIT
169
+
@@ -0,0 +1,133 @@
1
+ # import-effects
2
+
3
+ > See what Python does when you `import`.
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/import-effects)](https://pypi.org/project/import-effects/) [![Python](https://img.shields.io/pypi/pyversions/import-effects)](https://pypi.org/project/import-effects/) [![CI](https://github.com/royalpinto007/import-effects/actions/workflows/ci.yml/badge.svg)](https://github.com/royalpinto007/import-effects/actions/workflows/ci.yml) [![license](https://img.shields.io/pypi/l/import-effects)](LICENSE)
6
+
7
+ `import-effects` runs one import in a fresh child interpreter and reports file writes, sockets, subprocesses, threads, environment changes, and other observable import-time behavior.
8
+
9
+ ```bash
10
+ pip install import-effects
11
+ import-effects requests
12
+ ```
13
+
14
+ ![A Python import starts a thread, opens a socket, writes a file, and launches a subprocess](docs/assets/demo.gif)
15
+
16
+ ## 30-second quickstart
17
+
18
+ ```console
19
+ $ import-effects mypackage
20
+ import mypackage
21
+
22
+ ✓ imported in 143 ms
23
+
24
+ SIDE EFFECTS
25
+
26
+ ⚠ FILE WRITE
27
+ /home/me/.cache/mypackage/config.json
28
+
29
+ ⚠ NETWORK
30
+ api.example.com:443
31
+
32
+ ⚠ THREAD
33
+ background-worker
34
+
35
+ 3 side effects detected · 1 file-write · 1 network · 1 thread
36
+ ```
37
+
38
+ The target must already be importable. `import-effects` never installs it and normal inspection needs no server, database, Docker, network access, or elevated privileges.
39
+
40
+ ## CLI
41
+
42
+ ```bash
43
+ import-effects package.submodule
44
+ import-effects requests --json
45
+ import-effects requests --quiet
46
+ import-effects requests --verbose
47
+ import-effects requests --timeout 10
48
+ import-effects requests --fail-on network,subprocess,file-write
49
+ import-effects requests --ignore '~/.cache/**'
50
+ ```
51
+
52
+ `--fail-on` turns selected observations into policy failures without pretending every observation is inherently unsafe. `--ignore` matches the human-readable effect detail and may be repeated.
53
+
54
+ Exit codes:
55
+
56
+ | Code | Meaning |
57
+ | ---: | ------------------------------------------------- |
58
+ | 0 | Import succeeded with no configured violation |
59
+ | 1 | A configured `--fail-on` effect was detected |
60
+ | 2 | Invalid CLI input |
61
+ | 3 | Target import failed or timed out |
62
+ | 4 | Internal inspector failure |
63
+
64
+ ## Python API
65
+
66
+ ```python
67
+ from import_effects import inspect_import
68
+
69
+ report = inspect_import("mypackage", timeout=10)
70
+
71
+ print(report.duration_ms)
72
+ for effect in report.effects:
73
+ print(effect.kind, effect.detail, effect.confidence)
74
+ ```
75
+
76
+ For tests:
77
+
78
+ ```python
79
+ from import_effects import assert_no_effects
80
+
81
+
82
+ def test_import_stays_quiet() -> None:
83
+ assert_no_effects("mypackage", forbidden=("network", "subprocess", "file-write"))
84
+ ```
85
+
86
+ The models are frozen, typed dataclasses. Reports can be converted with `report.to_dict()` and filtered with `report.effects_of("network")`.
87
+
88
+ ## What it observes
89
+
90
+ - files opened for writing, removal, rename, and directory operations
91
+ - socket connect, bind, and DNS activity
92
+ - subprocess spawning, `os.system`, and process forks
93
+ - Python threads and `multiprocessing` children started
94
+ - environment variable names added, removed, or changed, never their values
95
+ - current directory, logging handlers, `sys.path`, warning filters, and signal handlers
96
+ - newly imported module names, import duration, stdout/stderr, failures, crashes, and timeouts
97
+
98
+ CPython audit events provide high-confidence observations for many OS operations. Before/after snapshots and lifecycle wrappers cover state changes and thread/process starts. Each effect includes confidence and attribution metadata because an effect may come from the target, one of its dependencies, or code merely observed during the import window.
99
+
100
+ See [Architecture and limitations](docs/architecture.md) and the [API reference](docs/api.md).
101
+
102
+ ## Security warning
103
+
104
+ **Importing untrusted Python code executes that code. `import-effects` is an observer, not a sandbox.**
105
+
106
+ The target runs in a separate child interpreter, so it cannot directly mutate the parent Python process. It still runs as your user with normal filesystem, network, and process permissions. Use an OS sandbox or disposable virtual machine when inspecting code you do not trust.
107
+
108
+ Target stdout and stderr are capped. Suspected credentials in captured messages are redacted, and environment variable values are never included. Audit hooks are visibility mechanisms, not a security boundary, and sufficiently hostile native code can evade or disable Python-level observation.
109
+
110
+ ## Platform support
111
+
112
+ `import-effects` targets CPython 3.10 through 3.14 on Linux, macOS, and Windows. Audit event availability and process termination behavior differ by Python and OS. Linux currently provides the broadest coverage. Windows does not offer the same process-group cleanup guarantees as POSIX, and some native extensions perform operations below CPython's audit surface.
113
+
114
+ ## Development
115
+
116
+ ```bash
117
+ python -m venv .venv
118
+ . .venv/bin/activate
119
+ pip install -e '.[dev]'
120
+ ruff format --check .
121
+ ruff check .
122
+ mypy
123
+ pytest --cov
124
+ python -m build
125
+ twine check dist/*
126
+ ```
127
+
128
+ See [Contributing](CONTRIBUTING.md), [Security](SECURITY.md), and the [Changelog](CHANGELOG.md).
129
+
130
+ ## License
131
+
132
+ MIT
133
+
@@ -0,0 +1,14 @@
1
+ # Security policy
2
+
3
+ ## Reporting
4
+
5
+ Please report vulnerabilities privately through GitHub Security Advisories. Do not include live credentials, private package contents, or sensitive import reports in a public issue.
6
+
7
+ ## Scope and safety model
8
+
9
+ `import-effects` executes the requested import in a child process. It is not a sandbox and does not make untrusted code safe. The child inherits the user's OS account permissions and a largely unchanged environment so ordinary imports continue to work.
10
+
11
+ The tool never installs packages. It redacts likely credentials from captured messages, never reports environment values, caps target output, validates module names, and applies a timeout. These controls reduce accidental disclosure and runaway imports but are not a security boundary against malicious Python or native code.
12
+
13
+ Supported security fixes target the latest released version.
14
+
@@ -0,0 +1,24 @@
1
+ # API reference
2
+
3
+ ## `inspect_import`
4
+
5
+ ```python
6
+ inspect_import(module: str, *, timeout: float = 10.0, python_executable: str | PathLike | None = None) -> ImportReport
7
+ ```
8
+
9
+ Runs the import in a fresh child interpreter. Invalid module names and timeouts less than or equal to zero raise `ValueError`. Failure to start or decode the child raises `InspectionError`. A target import exception is returned as a normal unsuccessful report.
10
+
11
+ ## `assert_no_effects`
12
+
13
+ ```python
14
+ assert_no_effects(module: str, *, forbidden=("network", "subprocess", "file-write"), timeout=10.0) -> ImportReport
15
+ ```
16
+
17
+ Raises `AssertionError` when the import fails or a forbidden effect is observed. This helper works naturally in pytest, unittest, and other test runners without a plugin.
18
+
19
+ ## Models
20
+
21
+ `ImportReport` and `Effect` are frozen dataclasses. `ImportReport.to_dict()` returns JSON-compatible data, `ImportReport.from_dict()` reconstructs a report, and `effects_of(*kinds)` filters effects.
22
+
23
+ An effect includes `kind`, redacted `detail`, optional `source`, `confidence`, `attribution`, and small non-sensitive metadata. Environment values are never included.
24
+
@@ -0,0 +1,28 @@
1
+ # Architecture and limitations
2
+
3
+ ## Execution model
4
+
5
+ The public process validates the module name and launches the same Python interpreter with `python -m import_effects._probe`. The child prepares observers, takes a baseline snapshot, activates observation, calls `importlib.import_module`, takes a final snapshot, and writes a private JSON report. The parent enforces the timeout and deserializes that report into typed dataclasses.
6
+
7
+ Target stdout and stderr travel on separate pipes, so they cannot corrupt structured output. The parent never imports the target.
8
+
9
+ ## Observation sources
10
+
11
+ CPython's [PEP 578 audit hooks](https://peps.python.org/pep-0578/) expose operations such as `open`, `socket.connect`, `subprocess.Popen`, and filesystem changes. Thread and multiprocessing start methods are observed with child-local wrappers. Snapshots compare environment keys, current directory, logging handlers, `sys.path`, warning filters, signal handlers, and loaded modules.
12
+
13
+ Startup work is excluded by activating observers immediately before the target import. Dependency activity during the import remains relevant and is reported. Stack inspection provides a best-effort source classification, not a security-grade provenance claim.
14
+
15
+ ## Limitations
16
+
17
+ - This is not an OS sandbox. Target code executes with the child's normal permissions.
18
+ - Python audit hooks are designed for visibility and can be bypassed by hostile native code.
19
+ - A dependency imported by the target can cause any reported effect.
20
+ - Completed native threads or processes that do not use the observed Python APIs may be missed.
21
+ - Filesystem changes performed entirely below CPython's audit events may be missed.
22
+ - Snapshot-based findings show that state changed during the import window, not necessarily which exact line changed it.
23
+ - Import-generated bytecode cache writes are excluded as runtime noise.
24
+ - Timeout cleanup is strongest on POSIX. Windows child descendants may outlive a force-killed probe.
25
+ - Only modules already importable in the selected interpreter are inspected. No package installation occurs.
26
+
27
+ The report uses `target`, `dependency`, `observed-during-import`, and `runtime` attribution labels plus `high`, `medium`, or `low` confidence. Consumers should preserve those qualifiers.
28
+