# How melange Is Designed

> Source: https://www.ymotongpoo.com/books/chainguard-image-toolchain/15-melange-concept/


[melange](https://github.com/chainguard-dev/melange) is a Go-based CLI tool that builds APK packages from a declarative pipeline definition. Its [README](https://github.com/chainguard-dev/melange) frames the tool as a means to realize a "secure software factory." The idea is that by writing each build step down as a declaration and sandboxing the execution environment, you keep how a package was built in a mechanically verifiable state.

## The structure of melange.yaml

You write a melange build definition in a single YAML file (conventionally named `melange.yaml`, though any filename works). The main top-level fields are:

| Field | Role |
|---|---|
| `package` | Metadata: package name, version, epoch, description, license, runtime dependencies, and so on |
| `environment` | Defines the build environment. `contents.repositories` and `contents.packages` specify the APK repository and packages used at build time |
| `pipeline` | The sequence of build steps, made up of built-in `uses` actions or raw shell commands written under `runs` |
| `subpackages` | Derived packages built separately from the main one (such as `-doc` or `-dev`). Each can have its own `pipeline` and `dependencies` |
| `test` | A pipeline for verifying the built package |

Each `pipeline` step either calls a pre-built action, as in `uses: fetch`, or writes an arbitrary shell command under `runs: |`. The built-in actions themselves are defined one action per YAML file in the [pkg/build/pipelines](https://github.com/chainguard-dev/melange/tree/main/pkg/build/pipelines) directory. They include `fetch` for retrieving source, build-system wrappers like `autoconf/configure` and `autoconf/make`, `go/build` for Go, `patch` for applying patches, and `strip` for removing debug symbols. Using built-in actions lets you share the same kind of build work across multiple package definitions.

Variable expansion uses notation like `${{package.version}}`, `${{targets.destdir}}`, and `${{build.arch}}`, letting you reference the version number or build output directory directly inside the pipeline.

A table only gets you so far, so let's look at the skeleton of the quickstart example in [melange's README](https://github.com/chainguard-dev/melange):

```yaml
package:
  name: hello
  version: 2.12
  epoch: 0
  description: "the GNU hello world program"

environment:
  contents:
    repositories:
      - https://dl-cdn.alpinelinux.org/alpine/edge/main
    packages:
      - alpine-baselayout-data
      - busybox
      - build-base

pipeline:
  - uses: fetch
    with:
      uri: https://ftp.gnu.org/gnu/hello/hello-${{package.version}}.tar.gz
      expected-sha256: cf04af86dc085268c5f4470fbae49b18afbc221b78096aab842d934a76bad0ab
  - uses: autoconf/configure
  - uses: autoconf/make
  - uses: autoconf/make-install
  - uses: strip
```

`package` carries the name and version, `environment.contents` lists the Alpine repository and packages used as the build environment, and `pipeline` lays out the steps from fetching the source to installing it. The next chapter's hands-on exercise actually runs this example, but swaps the build environment from Alpine to a Wolfi repository. The next chapter explains why.

## Sandboxing the build

Every time melange runs a pipeline, it prepares a clean APK root environment and performs the build inside it. You can choose the execution environment (the runner) with the `--runner` flag — `bubblewrap`, `docker`, or `qemu` — and the default varies by platform. `bubblewrap` is a lightweight sandbox using Linux's namespace isolation feature; running it inside a container requires the `--privileged` flag, due to the Linux capabilities it needs.

Multi-architecture support is achieved through QEMU's user-mode emulation. Without setting up a separate cross-compilation environment, you can run builds for different architectures — x86_64, arm64, ppc64le, and others — on the same host.

## Recording the SBOM and provenance

melange generates an SPDX-format SBOM on every build and embeds it inside the resulting package. Because it's generated from inside the build process, rather than inferred later by scanning the filesystem (the problem covered in Chapter 2), the record is based on what the pipeline actually fetched and actually installed.

Passing the `--generate-provenance` flag additionally outputs [SLSA](https://slsa.dev/)-format provenance information as `.attest.tar.gz`. The provenance records which build definition, in which environment, and when the build happened.

## Signing as a prerequisite

An APK built with melange isn't treated as trustworthy on its own. Signing it with a key pair generated by `melange keygen` makes it possible to verify that a specific build entity produced the package. This signing mechanism is indispensable for setting up a public APK repository like Wolfi's. The next chapter's hands-on exercise walks through actually generating a key and signing a package.

