CLI tool for creating and maintaining air-gapped Python projects
Project description
offliner
A CLI tool that automates the creation and maintenance of air-gapped Python projects. It scaffolds new projects, generates a self-contained transfer script for downloading vendored dependencies on a networked machine (without transmitting source code), writes back hash-pinned lock files, verifies vendor integrity, and regenerates project boilerplate from templates.
Workflow
All steps up to and including bundle export run with zero network access. The networked machine only receives the generated scripts — no source code is transmitted.
[offline] offliner init <name> scaffold a new project
[offline] offliner lock write requirements stubs from pyproject.toml
[offline] offliner bundle export embed dep specs in download.sh
[ONLINE] bash download.sh resolve, pin, hash, download → vendor.tar.gz
[offline] offliner bundle apply vendor.tar.gz extract vendor/, write hash-pinned lock files
[offline] make install-offline pip install --require-hashes from vendor/
[offline] offliner audit verify hashes + static security scan
Container image bundle (optional)
If your project needs container images on the air-gapped machine, declare them in pyproject.toml (or pass --images to offliner init) and follow the same export/apply pattern:
# pyproject.toml
[tool.offliner]
images = [
"registry.access.redhat.com/ubi9/python-311:latest",
"docker.io/library/postgres:16-alpine",
]
[offline] offliner bundle image export generate pull-images.sh (reads [tool.offliner].images)
[ONLINE] bash pull-images.sh pull images, save as .tar, SHA-256 → images.tar.gz
[offline] offliner bundle image apply images.tar.gz verify SHA-256, load into podman/docker
Commands
offliner init <name> Scaffold a new air-gap-ready Python project
offliner lock Write plain requirements stubs from pyproject.toml
offliner bundle export Generate a self-contained download.sh
offliner bundle apply <tar> Extract vendor.tar.gz, write lock files, verify SHA-256
offliner bundle image export Generate a self-contained pull-images.sh
offliner bundle image apply <tar> Verify SHA-256 and load images into podman/docker
offliner audit [--online] bandit + hash verify [+ pip-audit if --online]
offliner generate makefile (Re)generate Makefile from template
offliner generate pyproject (Re)generate pyproject.toml from template
offliner init
offliner init myproject \
--python 3.11 \
--author "Alice" \
--email "alice@example.com" \
--description "My air-gapped service" \
--version 0.1.0
# With container images (non-interactive; --images may be repeated)
offliner init myproject \
--images "registry.access.redhat.com/ubi9/python-311:latest" \
--images "docker.io/library/postgres:16-alpine"
Generates a full project skeleton: pyproject.toml, Makefile, Containerfile, Containerfile.build, .pre-commit-config.yaml, .gitignore, and src/<package>/__init__.py — all configured for offline operation once vendor/ is populated. When --images is provided the interactive prompt is skipped and the image list is written directly to [tool.offliner].images in pyproject.toml.
offliner bundle export
Reads [project.dependencies] and [project.optional-dependencies.dev] directly from pyproject.toml and embeds them into download.sh. No existing lock files or network access required.
On the networked machine download.sh runs pip-compile --generate-hashes, downloads all wheels into vendor/, and packs vendor.tar.gz (which also contains the generated hash-pinned lock files).
offliner bundle apply
Extracts vendor.tar.gz, writes requirements.txt and requirements-dev.txt to the project directory, and verifies every wheel's SHA-256 against the embedded hashes. Exits non-zero on any mismatch.
offliner bundle image export / apply
bundle image export reads [tool.offliner].images from pyproject.toml and writes a self-contained pull-images.sh. No network access or container runtime is required.
On the networked machine pull-images.sh pulls each image, saves it as a .tar file, records OCI digests in images.manifest, computes SHA-256 checksums, and packs everything into images.tar.gz.
bundle image apply extracts images.tar.gz, verifies every .tar's SHA-256 against the embedded checksums, and loads each image via podman load (or docker load). Exits non-zero on any verification failure or load error.
offliner bundle image apply images.tar.gz
offliner bundle image apply images.tar.gz --runtime docker
offliner bundle image apply images.tar.gz --skip-verify # not recommended
offliner audit
Offline: bandit static analysis on src/ + SHA-256 hash verification of vendor/ against lock files.
Online (--online): also runs pip-audit against requirements.txt for CVE lookups.
Installation
# First time (requires network for vendor/)
make venv && make vendor
# Install dev environment from vendor/ (offline from here)
make install-offline
make pre-commit-install
# Day-to-day checks (all offline)
make check # fmt + lint + typecheck + test
make fmt # ruff format
make lint # ruff check
make typecheck # mypy --strict
make test # pytest + coverage (80% branch minimum)
Container
# Runtime image (offline — vendor/ required)
make build-image
podman run --rm offliner:latest --help
# Build environment image (needs network for apt-get)
make build-build-image
make check-in-container # run make check inside the build container
make build-in-container # build wheel inside the container; artifacts → dist/
Design notes
pyproject.tomlis the single dependency source —[project.dependencies]and[project.optional-dependencies.dev]are canonical. No.infiles in generated projects.- No source code leaves the air-gapped machine —
download.shcontains only dependency specs. - Hash-pinned everywhere —
pip install --require-hashesis enforced in the generatedMakefile. - Pre-commit hooks use
language: system— all hooks run from the project venv; nothing is downloaded at install or commit time. - Multi-stage Containerfile — built with
--network=noneto verify no network leakage. tomllib(stdlib 3.11+) — no third-party TOML dependency.
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 offliner_py-0.2.5.tar.gz.
File metadata
- Download URL: offliner_py-0.2.5.tar.gz
- Upload date:
- Size: 90.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc2a86367a0521cdc72f1e900f14a89c9e96782fd85d6451d54ed126a266841e
|
|
| MD5 |
8caa55ca5e2149e45933f5b247e0e342
|
|
| BLAKE2b-256 |
7b7b01e210d71b3389f2e37db89371def184016a89e26aaadc48a15203294ef6
|
File details
Details for the file offliner_py-0.2.5-py3-none-any.whl.
File metadata
- Download URL: offliner_py-0.2.5-py3-none-any.whl
- Upload date:
- Size: 42.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ebebb1dd24a7ba589b000a6fcfc10d7ff4851da1929a49def9afb1e07b3103d6
|
|
| MD5 |
200c0cc88877592d2e38548c10bd1b96
|
|
| BLAKE2b-256 |
4a170959e1ede0f7cd9c2211932719b1693cf3125fad49783e9927242683e4f9
|