Custom software from source repositories
OpenFactory recipes can reference a Git repository as a custom package input on supported image builders. This is a supply-chain-sensitive path: the repository, resolved revision, packaging instructions, build dependencies, and produced package all require review.
Support is target-specific. Source-package builds are rejected for some builders, including current Raspberry Pi and Proxmox paths. Confirm availability in the normalized recipe and build plan before promising a package will be produced.
Recipe shape
Custom package entries live under os.custom_packages:
{
"os": {
"custom_packages": [
{
"name": "my-agent",
"git_url": "https://github.com/example/my-agent.git",
"branch": "release-1.x"
}
]
}
}The schema accepts a branch name, not an immutable commit field. For a controlled release, record the exact commit resolved by the build and make that commit part of the retained provenance. A moving branch alone is not reproducible input.
Prepare the repository
The current package path expects native packaging metadata appropriate to the target. Common examples are a Debian debian/ directory or an RPM spec. Exact builder behavior and supported target versions can change, so validate a minimal package in the deployed environment rather than relying on a static compatibility table.
For Debian packaging, review at least:
debian/controlfor source/binary identity and dependencies;debian/changelogfor the package version;debian/rulesand other executable maintainer scripts;- install manifests and systemd units; and
- licensing and bundled third-party material.
For RPM packaging, review the spec’s sources, build requirements, scriptlets, file list, and license metadata.
Never assume repository ownership makes its build scripts safe. Package builds execute untrusted source and packaging logic inside the build infrastructure’s isolation boundary.
Other package controls
Native packages
Use os.packages for packages already supplied by the selected distribution or an explicitly configured repository:
{
"os": {
"packages": ["curl", "jq"]
}
}Package overrides
os.package_overrides can declare add, remove, or replace intent:
{
"os": {
"package_overrides": [
{"name": "nano", "action": "replace", "replacement": "neovim"},
{"name": "telnet", "action": "remove"}
]
}
}An override is not proof that dependency resolution honored it. Verify the final package inventory and absence/presence assertions.
Additional repositories
os.extra_repos is an advanced input. Do not add an unsigned HTTP repository as shown in older examples. An approved repository integration needs HTTPS transport, a pinned signing key, signature enforcement, release metadata appropriate to the package manager, and documented ownership and update policy. If those trust controls cannot be represented by the current builder, do not use the repository.
Acceptance evidence
For every custom package, retain:
- repository URL and resolved commit;
- source and declared license review;
- build environment and dependency snapshot;
- build logs and resulting package name/version/architecture;
- package digest and repository-signature evidence where applicable;
- final image inventory showing the package installed;
- service or executable smoke tests; and
- removal and upgrade behavior.
A successful source-package stage is not enough. The image build can later fail to consume the package, and an installed package can still be unusable.
Troubleshooting
- Packaging metadata rejected: validate the native package locally with the same distribution release and architecture.
- Build dependency missing: use dependencies available from approved repositories for that target; do not silently fetch arbitrary binaries in a maintainer script.
- Package absent from the image: compare the produced binary package name with the normalized install request and final inventory.
- Version did not change: update native version metadata and confirm the new source commit was resolved.
- Service failed: inspect its unit, runtime dependencies, permissions, and guest logs; add a behavior-level assertion before rebuilding.