scriptling.provision.fetch
Fetch provisioning library for downloading files over HTTP/HTTPS and optionally unpacking zip archives.
Overview
The scriptling.provision.fetch library downloads remote files to local paths in an idempotent way. If the destination already contains the fetched bytes, the call returns fetch.UNCHANGED; otherwise it writes the new content and returns fetch.CREATED or fetch.UPDATED.
When unpack_zip=True, the destination is treated as a directory and the response body is extracted as a zip archive. Zip entries are constrained to the destination directory, so path traversal entries such as ../secret are rejected.
Available Functions
| Function | Description |
|---|---|
file(url, dest, insecure=False, unpack_zip=False, timeout=30, max_bytes=0, mode=0o644, dir_mode=0o755, provides=None) |
Download a file or unpack a fetched zip archive |
Constants
| Constant | Value | Meaning |
|---|---|---|
fetch.CREATED |
"created" |
Destination file or extracted files were newly created |
fetch.UPDATED |
"updated" |
Existing destination content changed |
fetch.UNCHANGED |
"unchanged" |
Existing destination content already matched |
file
file(
url: str,
dest: str,
insecure: bool = False,
unpack_zip: bool = False,
timeout: int = 30,
max_bytes: int = 0,
mode: int = 0o644,
dir_mode: int = 0o755,
provides: list[str] = None,
) -> dictDownloads url using HTTP GET. The URL must use http:// or https://.
When unpack_zip=False, dest is a file path. Parent directories are created automatically.
When unpack_zip=True, dest is a directory path. The fetched body is read as a zip archive and each file entry is written under that directory.
Parameters
| Parameter | Default | Description |
|---|---|---|
url |
— | http:// or https:// URL to fetch |
dest |
— | Destination file, or destination directory when unpack_zip=True |
insecure |
False |
Skip HTTPS certificate verification |
unpack_zip |
False |
Treat the response body as a zip archive and extract it |
timeout |
30 |
Request timeout in seconds |
max_bytes |
0 |
Maximum response size in bytes, or 0 for no cap |
mode |
0o644 |
File permission mode for written files |
dir_mode |
0o755 |
Directory permission mode for created directories |
provides |
None |
List of file paths. If all paths exist, returns UNCHANGED without downloading or extracting |
Returns
dict with:
| Key | Description |
|---|---|
status |
fetch.CREATED, fetch.UPDATED, or fetch.UNCHANGED |
url |
Source URL |
path |
Destination path |
bytes |
Size of the fetched response body |
unpacked |
True when unpack_zip=True |
files |
Written or checked file paths |
When unpacking a zip archive, fetch.UPDATED takes precedence over fetch.CREATED: if one entry updates existing content and another creates a new file, the overall status is fetch.UPDATED. Existing files whose bytes already match are still chmod’d to the requested mode. For zip entries, executable bits from the archive are OR’d into mode, so a 0o755 file in the archive remains executable when the default mode=0o644 is used. Directory entries create missing directories with dir_mode; existing directories are not re-chmod’d.
Examples
Download a file:
import scriptling.provision.fetch as fetch
result = fetch.file(
"https://example.com/app.conf",
"~/.config/app/app.conf",
mode=0o600,
)
if result["status"] != fetch.UNCHANGED:
print("Fetched " + result["path"])Fetch and unpack a zip archive:
import scriptling.provision.fetch as fetch
result = fetch.file(
"https://example.com/site.zip",
"/srv/site",
unpack_zip=True,
)
print("Extracted " + str(len(result["files"])) + " files")Use insecure TLS only for trusted internal endpoints:
import scriptling.provision.fetch as fetch
fetch.file(
"https://internal.example.test/bootstrap.zip",
"/opt/bootstrap",
insecure=True,
unpack_zip=True,
)Skip fetching when all expected files are already present:
import scriptling.provision.fetch as fetch
result = fetch.file(
"https://example.com/site.zip",
"/srv/site",
unpack_zip=True,
provides=["/srv/site/bin/app", "/srv/site/config.yaml"],
)
if result["status"] == fetch.UNCHANGED:
print("All provided files already exist — skipped")Security Notes
insecure=Truedisables HTTPS certificate verification. Use it only for trusted internal endpoints or bootstrapping environments where certificate validation is impossible.- Zip extraction rejects absolute paths and
..traversal paths. - Zip extraction rejects non-regular file entries such as symlinks and device files.
- Use
max_byteswhen fetching from endpoints where a large or misconfigured response could exhaust memory. - This library performs network and filesystem writes. Avoid registering it for untrusted scripts unless the host environment is otherwise constrained.