Dalec
repository·main·Indexed 43 days ago
https://github.com/project-dalec/dalecA declarative tool for building secure system packages and containers with a focus on supply chain security, minimal image sizes, build-time SBOMs, and Provenance attestations. It supports DEB-based (Debian, Ubuntu), RPM-based (Azure Linux, Rocky Linux, Alma Linux), and Windows container targets.
What's inside Dalec
- Dalec is a tool designed to provide a declarative format for building system packages and containers. It focuses on supply chain security by enabling the creation of minimal images with a reduced attack surface and providing build-time SBOMs (Software Bill of Materials) and Provenance attestations.
What is Dalec?
mainDalec is a Docker Buildkit frontend that translates declarative YAML specifications into build instructions. It acts as a specialized compiler that takes package configurations and produces packages and containers across multiple Linux distributions (such as Debian, Ubuntu, Azure Linux, and Rocky Linux) and Windows.Understand the Dalec security posture and assurance case
mainDalec provides a structured assurance case designed to meet OpenSSF Best Practices Silver standards. This document outlines how Dalec's release process mitigates supply-chain risks by mapping high-level security claims to specific evidence (such as CI workflows, governance policies, and architectural designs).
Key Security Mitigations
- Declarative Spec Validation: Ensures build specifications are valid.
- Sandboxed Execution: Uses BuildKit's sandboxing with clearly defined mounts to isolate build processes.
- Artifact Integrity: Official release artifacts include signatures and SBOM/provenance outputs.
- Automated Testing: Specs include tests that are executed via the Dalec test runner.
- Continuous Monitoring: Uses Dependabot, GitHub Dependency Review, and Snyk to monitor and triage dependency vulnerabilities.
What is a Source in Dalec?
mainA source is an abstraction used to fetch dependencies for a build. While usually source code, a source can be any data (files, directories, or generated content) fetched over various protocols.
Key behaviors:
- Injection: Sources are injected into the root path of the build environment using the name assigned to the source in the configuration.
- File vs. Directory sources: Some sources are inherently file-based (e.g.,
http,inline: file), while others are directory-based (e.g.,git,context,docker image,build). - Wrapper types: Some sources act as wrappers or allow mounting other sources (e.g.,
docker image,build). Only the output of a top-level source is included in the build environment. - Platform Agnosticism: Ideally, source content should be platform-agnostic, as these sources are used to create source packages (like
srpmordebian dsc) for target platforms.
What is Dalec and how it works
mainDalec is a Docker Buildkit frontend that translates a YAML specification into build instructions for creating packages (such as RPMs or DEBs) and container images. It requires only Docker to run.
Dalec builds follow a three-stage lifecycle:
- Package Build: Checks out sources and executes defined build steps.
- Package Test: Installs and validates the package in a clean environment.
- Create Container (optional): Installs the resulting package(s) into a scratch image to produce a container image.
Check file existence and properties
mainYou can verify the presence and metadata of files within the container using the
fileskey under a test case.Available file checks include:
- Existence: Simply listing a path under
fileschecks if it exists. - Non-existence: Use
not_exist: trueto assert a file is absent. - Directory check: Use
is_dir: trueto assert a path is a directory. - Permissions: Use the
permissionskey (e.g.,0644) to check file mode. - Symlinks: Use
link_targetto verify the destination of a symbolic link.
tests: - name: My Test case files: /usr/bin/foo: # Checks existence /some/nonexistent/path: not_exist: true /some/path: is_dir: true /etc/foo.conf: permissions: 0644 /some/symlink: link_target: /expected/target- Existence: Simply listing a path under
Understand the cleanup policy for Debian/Ubuntu minimal images
mainDebian- and Ubuntu-based minimal container targets (e.g.,
trixie/container,bookworm/container,noble/container) run an aggressive post-install cleanup pass. This policy is all-or-nothing per directory tree:/usr/share/doc,/usr/share/man,/usr/share/info: Preserved only if the spec declares at least onedocs,manpages, orlicensesartifact. If preserved, all content under these paths (including dependency-owned files) is kept. If pruned, all content is removed./etc/systemd,/var/lib/systemd: Preserved only if thesystemdpackage is installed orsystemctlis onPATH./var/log: The directory is always preserved, but its contents are emptied.- Package manager state/caches: Paths like
/etc/apt,/var/cache/apt,/var/lib/apt,/usr/lib/apt,/var/lib/pam,/var/cache/debconf, and/usr/share/{bash-completion,bug,debconf,lintian,locale}are always removed.
Configure the Image field in the DALEC spec
mainThe
imagefield is an object in the DALEC specification used to customize the properties of the produced container image. Most fields (exceptbase,bases, andpost) are merged with the configured or default base image settings.Supported properties include:
minimization_profile: Optional post-install minimization policy.labels: Optional key-value pairs for image labels.env: Optional environment variables.entrypoint: Optional entrypoint command.cmd: Optional command.workdir: Optional working directory.user: Optional user/group configuration.stop_signal: Optional signal for graceful container shutdown.volumes: Optional volume definitions.
Customize worker images using Named Build Contexts
mainIf you need a worker image with additional tools not present in the base image, you can target the worker specifically using
<target>/worker(e.g.,--target=azlinux3/worker).To provide a custom worker image, use the Docker
buildx--build-contextflag. For theazlinux3target, DALEC looks for a named context calleddalec-azlinux3-worker. If you provide a context for the actual base image used byazlinux3, the worker context is ignored.Example using a custom worker context:
docker buildx build --build-context dalec-azlinux3-worker=<new ref> ...Configure top-level source options
mainFor all source types, you can apply the following top-level configuration keys to control how the source is processed:
path: The specific path to extract from the source type.includes: A list of glob patterns to include from the source.excludes: A list of glob patterns to exclude from the source.generate: Used to trigger a generator (e.g.,gomod,pip).
Example of configuring a
contextsource with path filtering:sources: someSource: path: path/in/source includes: - "*.txt" excludes: - "secret.txt" context: {}How Dalec tests are structured
mainDalec uses two distinct testing tiers:
1. Unit Tests
- Location: Distributed throughout the codebase (e.g.,
spec_test.go). - Characteristics: Fast (< 1 minute), no Docker/network required, tests functions in isolation.
- Execution: Use
go test --test.short ./...ormake test.
2. Integration Tests
- Location: The
test/directory. - Characteristics: Slow (30-60+ minutes), requires Docker with BuildKit, tests end-to-end scenarios (Linux/Windows packages/containers).
- Framework: Uses a custom framework in
test/testenv/to manage Docker contexts and parallel execution.
# Run all unit tests go test --test.short ./...- Location: Distributed throughout the codebase (e.g.,
How System Extensions (sysexts) work in Dalec
mainDalec can create system extensions, known as
sysexts, which are EROFS filesystem images designed for use withsystemd(version 248 or later). These images are overlaid onto a running system.Key Characteristics:
- Dependency Model: Unlike containers, Dalec uses a specific
sysextdependency type. This gives you full control over what is included, as packages are extracted directly rather than installed via a package manager. No dependency resolution or package metadata is performed during the build. - Merging Behavior: When merged, files in the extension that share a path with the running system will overshadow the existing files. The running system is not modified; original files become visible again once the extension is unmerged.
- Portability: Extensions can be standalone or rely on the host system. To maximize portability and avoid
glibccompatibility issues, consider using statically-linked binaries. - Ownership: Dalec automatically changes all file ownership to
root:rootduring creation to prevent UID/GID mismatches with the host system.
- Dependency Model: Unlike containers, Dalec uses a specific