Source Builds, Local Packages and Reproducibility

Updated

October 31, 2026

Building software locally transfers responsibility for its source, build dependencies, updates and removal to the operator. A successful compile does not establish that the source was authentic, that the result is reproducible or that it will receive security fixes.

Record the supply chain

Record the project’s identity, release or commit, source URL, verified signature or hash from an independently authenticated channel, license, target architecture, compiler, dependency versions and build instructions. Build in an isolated disposable environment with no production credentials and limited network access. Build scripts are executable code: an untrusted source tree must not be run with administrator privileges. Inspect the build system and use the upstream project’s documented tests.

A reproducible build means independent builds from equivalent declared inputs produce bit-identical artifacts. It does not establish that the source is benign. Timestamps, generated file order, toolchain versions, paths and network-fetched dependencies can make outputs differ. SOURCE_DATE_EPOCH supplies a deterministic timestamp to tools that support it; it does not make an arbitrary build reproducible by itself. See the SOURCE_DATE_EPOCH specification.

Stage instead of installing into the host

Many build systems support a staging directory (often DESTDIR) that receives files under their intended final paths without writing into /usr on the build host. Check the project’s documentation: support and syntax vary. Avoid sudo make install as an untracked shortcut, especially when a distribution package already owns the same paths. Build artifacts for deployment should have a documented owner, version, dependencies, upgrade path and removal procedure.

A Debian package records ownership and metadata in the package database. Creating one does not automatically solve dependency selection, signatures, upgrades, triggers or service policy. Debian source packaging and a clean build environment are the appropriate next step for a maintained application. The dpkg-deb manual documents the archive format and inspection commands.

Lab: build and inspect a tiny local package

On the disposable bl05-packages-lab clone, create an isolated working directory owned by the current user. This example packages a text file and has no maintainer scripts; it does not install anything. dpkg-deb must already be available.

labdir=$(mktemp -d)
printf 'Working directory: %s\n' "$labdir"
mkdir -p "$labdir/pkg/DEBIAN" "$labdir/pkg/usr/share/bl05-demo"
cat > "$labdir/pkg/DEBIAN/control" <<'CONTROL'
Package: bl05-demo
Version: 1.0-1
Architecture: all
Maintainer: Lab Operator <lab@example.invalid>
Description: Disposable local packaging example
 A small file for inspecting a package without installing it.
CONTROL
printf 'Package ownership demonstration\n' > "$labdir/pkg/usr/share/bl05-demo/readme"
dpkg-deb --root-owner-group --build "$labdir/pkg" "$labdir/bl05-demo_1.0-1_all.deb"
dpkg-deb --info "$labdir/bl05-demo_1.0-1_all.deb"
dpkg-deb --contents "$labdir/bl05-demo_1.0-1_all.deb"
sha256sum "$labdir/bl05-demo_1.0-1_all.deb"

Examine the package name, version, architecture and file paths. all means the package is architecture-independent, not that every dependency or interpreter would work on all hosts. The hash identifies these bytes; it is not a signature or evidence of trust. Rebuilding and comparing hashes is an experiment, not proof of independently reproducible builds unless inputs and environments are controlled independently.

Record the printed working directory. Remove it only after checking that it is the disposable directory just created:

printf '%s\n' "$labdir"
# After checking the path is the disposable directory:
rm -r -- "$labdir"

Do not reuse this removal command in a later shell where labdir is missing or has a different value. A real deployment would use a reviewed package with appropriate dependency metadata, authenticated distribution, an upgrade policy and acceptance tests. Installing a local .deb can execute its maintainer scripts as root; inspect and trust the whole package before installation.

Diagnose and practice

If an application works on the build host but fails elsewhere, compare architecture, interpreter, shared-library requirements, build flags, paths and runtime dependencies. A successful build may have used undeclared libraries already present on the builder. Rebuild in a clean environment and verify on a separate test host before changing dependency metadata. Explain the differences between file ownership, source authenticity and artifact reproducibility.