{"id":43409713,"url":"https://github.com/matthewdeanmartin/hermetic","last_synced_at":"2026-02-02T16:32:06.773Z","repository":{"id":319519718,"uuid":"1078916573","full_name":"matthewdeanmartin/hermetic","owner":"matthewdeanmartin","description":"run a python tool with certain APIs disabled","archived":false,"fork":false,"pushed_at":"2026-01-13T23:49:44.000Z","size":456,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-14T01:32:30.930Z","etag":null,"topics":["cli-tool","configuration","development-tools","python","security"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/matthewdeanmartin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-18T17:39:08.000Z","updated_at":"2026-01-13T23:49:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"a8799e9d-a888-4f0f-8d1d-03350e6dcafc","html_url":"https://github.com/matthewdeanmartin/hermetic","commit_stats":null,"previous_names":["matthewdeanmartin/hermetic"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/matthewdeanmartin/hermetic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewdeanmartin%2Fhermetic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewdeanmartin%2Fhermetic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewdeanmartin%2Fhermetic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewdeanmartin%2Fhermetic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matthewdeanmartin","download_url":"https://codeload.github.com/matthewdeanmartin/hermetic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewdeanmartin%2Fhermetic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29015148,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-02T16:17:30.374Z","status":"ssl_error","status_checked_at":"2026-02-02T15:58:50.469Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli-tool","configuration","development-tools","python","security"],"created_at":"2026-02-02T16:32:06.244Z","updated_at":"2026-02-02T16:32:06.765Z","avatar_url":"https://github.com/matthewdeanmartin.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# hermetic\n\nRun a python tool, or your application with certain APIs disabled, such as network or subprocess.\n\nThe previously safe library you depend on was highjacked and will be sending your password files to a remote server.\nOr you installed this and the malicious hackers didn't include evasive code to defeat this fig leaf of a security\nfeature and the day is saved.\n\nIf Alice and Bob know about your application and specifically are targeting this, this tool won't help.\n\n## Usage\n\n### Command-Line Interface\n\nUse the `hermetic` command to run any Python console script, separating its arguments with `--`.\n\n**Syntax**: `hermetic [flags] -- \u003ccommand\u003e [command_args]`\n\n#### Common Flags:\n\n  - `--no-network`: Disable all network activity.\n  - `--allow-localhost`: Allows network connections to localhost (used with `--no-network`).\n  - `--allow-domain \u003cdomain\u003e`: Allows connections to a specific domain (repeatable).\n  - `--no-subprocess`: Disable creating new processes.\n  - `--fs-readonly[=/path/to/root]`: Make the filesystem read-only. Optionally, restrict all reads to be within the specified root directory.\n  - `--block-native`: Block imports of native C extensions.\n  - `--profile \u003cname\u003e`: Apply a pre-configured profile (e.g., `block-all`).\n  - `--trace`: Print a message to stderr when an action is blocked.\n\n#### CLI Examples:\n\n**Block network access for the `httpie` tool:**\n\n```bash\n$ hermetic --no-network -- http [https://example.com](https://example.com)\n\nhermetic: blocked action: network disabled: DNS(example.com)\n```\n\n**Run a script in a read-only filesystem where it can only read from `./sandbox`:**\n\n```bash\n$ hermetic --fs-readonly=./sandbox -- python my_script.py\n\n# my_script.py will raise PolicyViolation if it tries to read outside ./sandbox\n# or write anywhere.\n```\n\n**Apply the `block-all` profile to completely lock down a script:**\n\n```bash\n$ hermetic --profile block-all -- my_analyzer.py --input data.csv\n```\n\n-----\n\n### Programmatic API\n\nYou can use `hermetic` directly in your Python code via the `hermetic_blocker` context manager or the `@with_hermetic` decorator.\n\n#### Decorator\n\nThe `@with_hermetic` decorator is the easiest way to apply guards to an entire function.\n\n```python\nfrom hermetic import with_hermetic\nimport requests\n\n@with_hermetic(block_network=True, allow_domains=[\"api.internal.com\"])\ndef process_data():\n    # This will fail because all network access is blocked by default.\n    # requests.get(\"https://example.com\") # --\u003e raises PolicyViolation\n\n    # This is allowed because the domain is on the allow-list.\n    return requests.get(\"https://api.internal.com/data\")\n\nprocess_data()\n```\n\n#### Context Manager\n\nFor more granular control, use the `hermetic_blocker` context manager.\n\n```python\nfrom hermetic import hermetic_blocker\nimport os\n\ndef check_system():\n    # Subprocesses are allowed here\n    os.system(\"echo 'Checking system...'\")\n\n    with hermetic_blocker(block_subprocess=True):\n        # Inside this block, os.system() would raise a PolicyViolation\n        print(\"Running in a sandboxed context.\")\n        os.system(\"echo 'This will fail.'\") # --\u003e raises PolicyViolation\n\n    # Subprocesses are allowed again\n    os.system(\"echo 'Exited sandbox.'\")\n\ncheck_system()\n```\n\n## Where could this work?\n\nThere are APIs you don't need but an application or 3rd party library you depend on needs. So you block them.\n\nThe 3rd party library must be unaware of hermetic or monkeypatching. Import order is important, hermetic must run\nearly enough to intercept all imports to the banned API. Then use of the banned API is blocked and the whole app stops.\n\nThis already works in unit testing where there isn't an adversarial relationship between the developers testing the code\nand writing the code under test, where you block network traffic to guarantee a unit test is pure of network side\neffects.\n\n## Is this defeatable?\n\nYes, by many routes. Native code, import order tricks, undoing a monkey patch, bringing along a vendorized copy of APIs,\nand so on.\n\nThis is \"envelope instead of postcard\" level security. This is \"lock your door with standard key that can be picked with\na $5 purchase on Ebay\" level security.\n\nReal sandboxing is running your code in a docker container.\n\n## Prior Art\n\nThis technique of monkey-patching for isolation is well-established, particularly in the testing ecosystem.\n\n  - [pytest-socket](https://pypi.org/project/pytest-socket/): Disables sockets during tests.\n  - [pytest-network](https://pypi.org/project/pytest-network/): Disables networking during tests.\n\nFor stronger sandboxing, consider:\n\n  - [pysandbox](https://github.com/vstinner/pysandbox): Uses Linux `seccomp` for kernel-level syscall filtering.\n  - [RestrictedPython](https://pypi.org/project/RestrictedPython/): Rewrites Python AST to enforce constraints.\n  - [Docker](https://www.docker.com/): OS-level virtualization.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatthewdeanmartin%2Fhermetic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatthewdeanmartin%2Fhermetic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatthewdeanmartin%2Fhermetic/lists"}