274 lines
16 KiB
Markdown
274 lines
16 KiB
Markdown
# Runtime Dependency Build
|
|
|
|
This directory records the public build inputs and pip-tools generator. It is not
|
|
an application configuration directory and must never contain credentials.
|
|
|
|
## Pins
|
|
|
|
| Input | Pin |
|
|
| --- | --- |
|
|
| Python image | `python:3.12-slim-bookworm@sha256:782412e85d0f0984994c290652577d4018aff08145c85b262bb63dc0c7522254` |
|
|
| Python version | `3.12.14` |
|
|
| Linux amd64 manifest | `sha256:9c47360a2a0355e2da18516d0b1c2126ec22c195d2185e97347c9d98398c5bef` |
|
|
| Linux arm64/v8 manifest | `sha256:d04f49f5882f49a3b91f874e75e19f0c265f7222da8659741a9d7eab148f22a9` |
|
|
| Debian and Debian security snapshots | `20260914T000000Z` |
|
|
| Git and git-man | `1:2.39.5-0+deb12u3` |
|
|
| tini | `0.19.0-1+b3` |
|
|
| CA certificates (already present in the pinned base) | `20250419~deb12u1` |
|
|
| PGDG server, client, libpq | `16.15-1.pgdg12+2` |
|
|
| PGDG common and client-common | `293.pgdg12+1` |
|
|
| PGDG signing-key fingerprint | `B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8` |
|
|
| PGDG signing-key SHA-256 | `0144068502a1eddd2a0280ede10ef607d1ec592ce819940991203941564e8e76` |
|
|
| TruffleHog | `3.97.4` |
|
|
| TruffleHog Linux amd64 archive SHA-256 | `dc24007c2f233bd61c05beabeb44aa27ea9b43288166279209abe0458c5ce76b` |
|
|
| TruffleHog Linux amd64 archive size | `34970205` bytes |
|
|
| TruffleHog Linux arm64 archive SHA-256 | `7e65e771d2a247964056aa5edba0f8ae3945895e5dce867fe0ffbc7b0128239a` |
|
|
| TruffleHog Windows amd64 archive SHA-256 | `6ce9a957ac62bfb19463048333d9e8481327dbbf5bdc0c43f5ab5327b9631fb9` |
|
|
| Windows embeddable Python | `3.12.10`, SHA-256 `4acbed6dd1c744b0376e3b1cf57ce906f9dc9e95e68824584c8099a63025a3c3` |
|
|
| Windows MinGit | `2.47.1.windows.1`, SHA-256 `50b04b55425b5c465d076cdb184f63a0cd0f86f6ec8bb4d5860114a713d2c29a` |
|
|
| pip-tools | `7.6.1` |
|
|
| Generator pip | `26.2.1` |
|
|
| pytest | `8.4.2` |
|
|
| httpx (test target only) | `0.28.1` |
|
|
| zstandard | `0.23.0` |
|
|
| pandas | `3.0.5` |
|
|
| plotly | `7.0.0` |
|
|
| streamlit | `1.63.0` |
|
|
| psycopg and psycopg-binary | `3.3.5` |
|
|
| boto3 and botocore | `1.43.94` |
|
|
|
|
TruffleHog's expected hashes were checked against the public release's
|
|
[`trufflehog_3.97.4_checksums.txt`](https://github.com/trufflesecurity/trufflehog/releases/download/v3.97.4/trufflehog_3.97.4_checksums.txt).
|
|
The PGDG key's primary OpenPGP fingerprint was independently calculated from the
|
|
hash-pinned public key and matches the fingerprint above.
|
|
|
|
The Dockerfile pins the base index, download digests, PGDG package versions, and
|
|
Debian snapshot. Apt verifies Debian signatures with its shipped archive keyring
|
|
and PGDG signatures with the separately hash-pinned, repository-scoped armored
|
|
key. Full GnuPG is not installed. Expired `Valid-Until` checks are disabled only
|
|
for the immutable Debian snapshots, never signature verification. The official
|
|
PGDG archive retains older package versions; apt preferences exclude every PGDG
|
|
package except the five exact pins above.
|
|
|
|
The complete Debian Git package and HTTPS helper are retained. Native executable
|
|
symlinks in the Python/Git tool directories, and PG client version-wrapper links,
|
|
are replaced with root-owned regular hard links. Dependencies stay in the
|
|
interpreter's `/usr/local/lib/python3.12/site-packages`, not a virtual environment
|
|
or user site. Installation requires hashes and binary wheels and disables
|
|
bytecode generation. The application lock includes both manifests, optional
|
|
dashboard packages, and pytest in one environment. The test target layers its
|
|
separate hash lock containing Starlette TestClient's `httpx` dependency; the
|
|
runtime target does not contain `httpx`. The separate worker lock contains only
|
|
Requests, PyYAML, zstandard, and their four transitives; it excludes PostgreSQL,
|
|
server, dashboard, test, and detailed-keycheck dependencies.
|
|
|
|
`docker/worker-package-pins.json` is the canonical public build-input record for
|
|
Linux and Windows worker artifacts. Worker manifests hash every application,
|
|
dependency, scanner, detector-policy, Python-runtime, and complete Git-runtime
|
|
file. The package grants no provider or detailed keycheck authority and contains
|
|
no server or database credentials.
|
|
|
|
PostgreSQL service starts and automatic cluster creation are disabled during
|
|
installation. No database is initialized by the build. Generated distribution
|
|
snakeoil TLS keys are removed in the same layer. Package pins make dependency
|
|
selection repeatable; this is not a claim of byte-for-byte identical OCI images
|
|
across BuildKit versions or package-maintainer timestamp generation.
|
|
|
|
## Generate Locks
|
|
|
|
All four requirements lock files are generated by pip-tools on Linux with the pinned
|
|
Python 3.12.14 interpreter. Do not edit any generated lock by hand. The initial
|
|
compiler bootstrap installs only public `pip==26.2.1` and `pip-tools==7.6.1`, then
|
|
resolves and hashes the compiler's entire dependency closure. Subsequent compiler
|
|
installs use that generated hash lock.
|
|
|
|
The generator also copies the existing locks, so normal regeneration retains
|
|
valid pins. Use pip-compile's `--upgrade` only for an intentional dependency
|
|
refresh, then rebuild and revalidate the dependency image.
|
|
|
|
Run these Docker commands from the isolated source checkout (`D:\truf-workers` for
|
|
this change), using WSL's
|
|
`sudo -n docker -H unix:///var/run/docker.sock` in place of `docker` on this host.
|
|
The generator receives only the three public application manifests and compiler
|
|
inputs. There are no host bind mounts.
|
|
|
|
```sh
|
|
docker build --target lock-generator -t truf-lock-generator:py3.12.14 .
|
|
docker run --name truf-runtime-lock truf-lock-generator:py3.12.14
|
|
docker cp truf-runtime-lock:/src/docker/requirements.lock docker/requirements.lock
|
|
docker rm truf-runtime-lock
|
|
docker run --name truf-test-lock truf-lock-generator:py3.12.14 \
|
|
python3 -m piptools compile --generate-hashes --allow-unsafe \
|
|
--resolver=backtracking --strip-extras --no-emit-index-url \
|
|
--no-emit-trusted-host --index-url=https://pypi.org/simple \
|
|
--pip-args=--only-binary=:all: \
|
|
--output-file=docker/requirements-test.lock docker/requirements-test.in
|
|
docker cp truf-test-lock:/src/docker/requirements-test.lock docker/requirements-test.lock
|
|
docker rm truf-test-lock
|
|
docker run --name truf-worker-lock truf-lock-generator:py3.12.14 \
|
|
python3 -m piptools compile --generate-hashes --allow-unsafe \
|
|
--resolver=backtracking --strip-extras --no-emit-index-url \
|
|
--no-emit-trusted-host --index-url=https://pypi.org/simple \
|
|
--pip-args=--only-binary=:all: \
|
|
--output-file=docker/requirements-worker.lock docker/requirements-worker.in
|
|
docker cp truf-worker-lock:/src/docker/requirements-worker.lock docker/requirements-worker.lock
|
|
docker rm truf-worker-lock
|
|
docker run --name truf-compiler-lock truf-lock-generator:py3.12.14 \
|
|
python3 -m piptools compile --generate-hashes --allow-unsafe \
|
|
--resolver=backtracking --strip-extras --no-emit-index-url \
|
|
--no-emit-trusted-host --index-url=https://pypi.org/simple \
|
|
--pip-args=--only-binary=:all: \
|
|
--output-file=docker/build-dependencies/requirements.lock \
|
|
docker/build-dependencies/requirements.in
|
|
docker cp truf-compiler-lock:/src/docker/build-dependencies/requirements.lock docker/build-dependencies/requirements.lock
|
|
docker rm truf-compiler-lock
|
|
```
|
|
|
|
## Build Targets
|
|
|
|
```sh
|
|
docker build --target dependencies -t truf-dependencies:py3.12.14-pg16.15-th3.97.4 .
|
|
docker build --target runtime -t truf-runtime:local .
|
|
docker build --target test -t truf-test:local .
|
|
docker build --target worker -t truf-remote-worker:linux-x86_64 .
|
|
```
|
|
|
|
## Remote Worker Artifacts
|
|
|
|
The `worker` target is independent of the server runtime. It uses the pinned image
|
|
Python and includes the worker authority, required shared DB-free modules, worker
|
|
dependency lock, detector policy, TruffleHog, CA roots, tini, and a package-local
|
|
complete Git helper tree. The final build executes the scanner and Git version
|
|
checks and verifies the full schema-3/protocol-2 capability package as unprivileged UID 10001. PostgreSQL
|
|
tools, server runtime/control authority, test code, `httpx`, provider and detailed
|
|
keycheck authority, server credentials, and database credentials are absent.
|
|
|
|
Build the Windows amd64 portable directory and deterministic ZIP from the same
|
|
isolated checkout:
|
|
|
|
```powershell
|
|
New-Item -ItemType Directory -Path dist -Force | Out-Null
|
|
python -B app/worker_package_builder.py windows `
|
|
--project-root . `
|
|
--output dist/truf-worker-windows-x86_64 `
|
|
--archive dist/truf-worker-windows-x86_64.zip `
|
|
--cache build/worker-cache
|
|
```
|
|
|
|
The builder downloads the hash-and-size-pinned Python 3.12.10 embeddable runtime,
|
|
MinGit 2.47.1, and TruffleHog 3.97.4, installs the cross-platform worker lock with
|
|
hash checking, verifies the complete package, and writes adjacent release JSON.
|
|
After extracting the ZIP, run `prepare-worker.ps1` once to replace inherited ACLs,
|
|
then use `run-worker.cmd`. Local files rely on private OS ACLs rather than
|
|
application-layer encryption; the client has no TLS-verification bypass.
|
|
|
|
Build a complete distributable release (Windows ZIP, Linux image archive,
|
|
Docker bundle, manifests, README, Compose file, and SHA-256 lists) with one
|
|
PowerShell command:
|
|
|
|
```powershell
|
|
.\build_worker_release.ps1 -ReleaseName release-YYYYMMDD-vN
|
|
```
|
|
|
|
The script uses native Docker when available and otherwise uses the Docker Engine
|
|
in `Ubuntu-24.04` through WSL. Use `-WslDistro NAME` for another distribution.
|
|
The destination must not already exist; a failed build remains on disk for
|
|
inspection and is never published as a partial replacement.
|
|
|
|
While the main context allowlist is pending, the dependency build can use this
|
|
explicit two-file context from WSL. It does not send any application code, secret
|
|
files, findings, state, or original checkout directories to the builder:
|
|
|
|
```sh
|
|
tar -C /mnt/d/truf-docker -cf - Dockerfile docker/requirements.lock \
|
|
| sudo -n docker -H unix:///var/run/docker.sock build --file Dockerfile \
|
|
--target dependencies -t truf-dependencies:py3.12.14-pg16.15-th3.97.4 -
|
|
```
|
|
|
|
`dependencies` stops before copying application code. `runtime-base` holds the
|
|
production filesystem and launch configuration; `test` inherits those exact
|
|
contents and adds private test sources. The last/default target, `runtime`, is a
|
|
direct alias of `runtime-base` and contains no test tree. The test entrypoint uses
|
|
the same interpreter isolation flags and the real `child_bootstrap.py` dependency
|
|
path loader, without processing `.pth` files or starting the application.
|
|
|
|
Application and test copies are owned by `10001:10001`; their directories are
|
|
`0700` and regular files `0600`. Build-time checks reject symlinks, special files,
|
|
and cached bytecode in these controlled copies. No recursive permission changes
|
|
are made to host paths or runtime-mounted data. The default user is `10001:10001`;
|
|
the image precreates private `/data` and `/data/home` directories.
|
|
|
|
## Verified Results
|
|
|
|
Validated on 2026-09-15 using Ubuntu 24.04 under WSL2, stock Docker Engine 29.8.0,
|
|
the local Unix socket, and `sudo -n`. Builds and generation were polled without
|
|
printing full dependency logs. A temporary WSL keepalive prevented idle shutdown
|
|
during detached lock generation; no host configuration changes were made.
|
|
|
|
| Result | Value |
|
|
| --- | --- |
|
|
| Dependency image tag | `truf-dependencies:py3.12.14-pg16.15-th3.97.4` |
|
|
| Local dependency image ID | `sha256:3fbdc2ea6fd1199aa742f54fb653e433d79ad3f1a5e4bfeed8b413dc9f704eb5` |
|
|
| Built and executed platform | `linux/amd64` |
|
|
| Runtime lock | 49 exact package pins, 1059 SHA-256 wheel hashes |
|
|
| Runtime lock SHA-256 | `82c69394b116fd8a762c3dea481682045af87c013974fcb78ac0529892188537` |
|
|
| Compiler lock | 8 exact package pins, 8 SHA-256 wheel hashes |
|
|
| Compiler lock SHA-256 | `0172b08004c6f2b0702ea9a472300cc63243492df2d3d782fd4dbaa612497fd2` |
|
|
| Lock replay in the hash-locked generator image | Both files byte-for-byte identical |
|
|
| `pip check` | No broken requirements |
|
|
|
|
- The `dependencies` and `lock-generator` targets built successfully with hash-required, binary-wheel-only installs.
|
|
- All 49 package import checks passed normally, then with `-I -S -B` through the actual `child_bootstrap.py` loader for all 10 child kinds. Application entrypoints and providers were not executed.
|
|
- Isolated `sys.path` contained only the interpreter ZIP path, standard library, `lib-dynload`, and `/usr/local/lib/python3.12/site-packages`. Neither the working directory nor the user site was added.
|
|
- 14,202 dependency-tree permission checks found root ownership, no group/world write access, and no symlinks or bytecode files. The unprivileged UID could not write these dependencies.
|
|
- Eleven selected native executables were regular root-owned files. Version and `ldd` checks passed for Python, Git, the Git HTTPS helper, tini, TruffleHog, and the six PG16 tools. TruffleHog is static; other checked ELF binaries had no missing shared libraries.
|
|
- TruffleHog global, Git, filesystem, Docker, and Hugging Face help flags were checked, including the scanner's legacy `--local-dev` and `--log-level` options. No scans or provider requests were made.
|
|
- No PostgreSQL `PG_VERSION` file or initialized cluster was present. No PostgreSQL server, application, or provider was started. Full GnuPG is absent.
|
|
- Minimal bootstrap-only runtime and test fixtures exercised the actual copy stages: `10001:10001`, directories `0700`, files `0600`. Generated in-memory contexts containing a symlink or `.pyc` file were rejected by the build.
|
|
- The test target's real tini/Python/bootstrap entrypoint reported `pytest 8.4.2` with networking disabled, a read-only root, and a UID-10001 private `/tmp` tmpfs. Pytest capture needs writable temporary storage even for `--version`.
|
|
|
|
The temporary runtime/test fixtures were deliberately incomplete and were used
|
|
only for dependency and filesystem-policy verification. They are not deployable
|
|
application images. No application test suite, PostgreSQL initialization test,
|
|
provider integration, or arm64 build was run. The arm64 base and TruffleHog assets
|
|
are pinned, but that platform still requires a native or emulated build/test.
|
|
|
|
## Integration Boundary
|
|
|
|
The main integration owns `.dockerignore`, `app/container_runtime.py`, Compose,
|
|
and tests. The context allowlist must include the exact Dockerfile, dependency
|
|
input/lock paths, this metadata file, the new runtime entrypoint, and the intended
|
|
test files. Do not replace the deny-by-default context rules with directory-wide
|
|
or wildcard exceptions. Keep `.env`, credentials, findings, original runtime
|
|
directories, and generated caches excluded.
|
|
|
|
New exact metadata/input exceptions required in the main-owned `.dockerignore`:
|
|
|
|
```text
|
|
!docker/requirements.in
|
|
!docker/requirements.lock
|
|
!docker/build-dependencies/requirements.in
|
|
!docker/build-dependencies/requirements.lock
|
|
!docker/build-dependencies/README.md
|
|
```
|
|
|
|
The Dockerfile is already allowlisted. Main must separately allowlist its
|
|
`app/container_runtime.py` and intended test source files once they exist. The
|
|
test target copies only `app/` and `tests/`; repository tests that read root-level
|
|
Compose, Docker, or PowerShell fixtures still need main-owned fixture integration.
|
|
|
|
Compose must select the runtime target, enforce a read-only root filesystem,
|
|
provide newly initialized Linux writable volumes and a temporary filesystem as
|
|
needed, and preserve the unprivileged UID/GID. Runtime startup, PostgreSQL
|
|
initialization, provider execution, and existing-data integration are explicitly
|
|
outside dependency-build validation.
|
|
|
|
For a read-only test image, provide private temporary storage, for example
|
|
`--tmpfs /tmp:rw,nosuid,nodev,noexec,size=64m,mode=0700,uid=10001,gid=10001` for
|
|
version/import checks. Main must choose temporary-storage size and execution
|
|
policy appropriate for its full tests. After the entrypoint, allowlist, fixtures,
|
|
and Compose changes are integrated, rebuild complete `runtime` and `test` images
|
|
and perform the separately authorized integration checks. No files outside the
|
|
Dockerfile and `docker/` build inputs were edited, and nothing was staged,
|
|
committed, or pushed.
|