Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spec changes for image extensions #298

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0bbd693
Fixes link to SBOM section in buildpack spec
natalieparellano Dec 15, 2021
ded555e
Add sbom as a reserved buildpack ID
natalieparellano Dec 15, 2021
32b57c2
Add deprecation path for buildpacks using the legacy BOM format.
natalieparellano Jan 18, 2022
35f8066
Process specific working directory
natalieparellano Jan 27, 2022
319ec34
Reorder things and clarify the working directory for exec.d and profi…
natalieparellano Feb 11, 2022
4120892
Apply suggestions from code review
natalieparellano Feb 24, 2022
bfdec08
Remove standalone lines, and add one more line
natalieparellano Feb 24, 2022
27b75f4
Change working-directory to working-dir
natalieparellano Mar 2, 2022
8511bc8
Add spec changes for image extensions
natalieparellano Mar 16, 2022
1523a68
Apply suggestions from code review
natalieparellano Mar 17, 2022
3683f47
Add some missing things
natalieparellano Mar 18, 2022
9811f0f
Merge branch 'dockerfiles-extensions' of github.com:buildpacks/spec i…
natalieparellano Mar 18, 2022
8cb34ff
Update buildpack.md
natalieparellano Mar 21, 2022
6ad7e76
Detect happens before "analysis"
natalieparellano Mar 21, 2022
9cf87e0
Merge branch 'dockerfiles-extensions' of github.com:buildpacks/spec i…
natalieparellano Mar 21, 2022
84bcc82
Clarify what launch.toml and build.toml are for
natalieparellano Mar 21, 2022
126bef3
Add Dockerfile requirements and clarify what is the responsibility of…
natalieparellano Mar 23, 2022
4701ff0
Remove run image requirement
natalieparellano Mar 23, 2022
b677794
Move some things to image-extension.md
natalieparellano Mar 23, 2022
3dc326d
Fix table of contents
natalieparellano Mar 23, 2022
2afbe69
Use consistent title for image extension spec
natalieparellano Mar 23, 2022
e26384a
Fix toc
natalieparellano Mar 23, 2022
745b4fc
Apply suggestions from code review
natalieparellano Mar 24, 2022
bf837f6
Updates following latest discussion
natalieparellano Apr 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 123 additions & 38 deletions buildpack.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ This document specifies the interface between a lifecycle program and one or mor

The lifecycle program uses buildpacks to build software artifacts from source code and pack the result into an OCI image.

This is accomplished in four phases:
This is accomplished in six phases:

1. **Detection,** where an optimal selection of compatible buildpacks is chosen.
2. **Analysis,** where metadata about OCI layers generated during a previous build are made available to buildpacks.
3. **Build,** where buildpacks use that metadata to generate only the OCI layers that need to be replaced.
4. **Export,** where the remote layers are replaced by the generated layers.
1. **Detection**, where an optimal selection of compatible buildpacks is chosen.
2. **Analysis**, where metadata about OCI layers generated during a previous build are made available to buildpacks.
3. **Generation** (optional, see the [Image Extension Interface](image-extension.md)), where image extensions generate Dockerfiles that can be used to extend the build and/or run base images.
4. **Extension** (optional, see the [Image Extension Interface](image-extension.md)), where Dockerfiles generated by image extensions are applied to the build and/or run base images.
5. **Build**, where buildpacks use analyzed metadata to generate only the OCI layers that need to be replaced.
6. **Export**, where the remote layers are replaced by the generated layers.

The `ENTRYPOINT` of the OCI image contains logic implemented by the lifecycle that executes during the **Launch** phase.

Expand All @@ -34,25 +36,32 @@ The `ENTRYPOINT` of the OCI image contains logic implemented by the lifecycle th
- [Phase #1: Detection](#phase-1-detection)
- [Purpose](#purpose)
- [Process](#process)
- [Mixin Satisfaction](#mixin-satisfaction)
- [Order Resolution](#order-resolution)
- [Phase #2: Analysis](#phase-2-analysis)
- [Purpose](#purpose-1)
- [Process](#process-1)
- [Phase #3: Build](#phase-3-build)
- [Phase #3: Generation (optional)](#phase-3-generation-optional)
- [Purpose](#purpose-2)
- [Process](#process-2)
- [Phase #4: Extension (optional)](#phase-4-extension-optional)
- [Purpose](#purpose-3)
- [Process](#process-3)
- [Phase #5: Build](#phase-5-build)
- [Purpose](#purpose-4)
- [Process](#process-4)
- [Unmet Buildpack Plan Entries](#unmet-buildpack-plan-entries)
- [Software Bill of Materials](#software-bill-of-materials)
- [Software-Bill-of-Materials](#software-bill-of-materials)
- [Layers](#layers)
- [Providing Layers](#providing-layers)
- [Reusing Layers](#reusing-layers)
- [Slice Layers](#slice-layers)
- [Phase #4: Export](#phase-4-export)
- [Purpose](#purpose-3)
- [Process](#process-3)
- [Phase #6: Export](#phase-6-export)
- [Purpose](#purpose-5)
- [Process](#process-5)
- [Launch](#launch)
- [Purpose](#purpose-4)
- [Process](#process-4)
- [Purpose](#purpose-6)
- [Process](#process-6)
- [Environment](#environment)
- [Provided by the Lifecycle](#provided-by-the-lifecycle)
- [Buildpack Specific Variables](#buildpack-specific-variables)
Expand Down Expand Up @@ -80,6 +89,9 @@ The `ENTRYPOINT` of the OCI image contains logic implemented by the lifecycle th
- [Order Buildpacks](#order-buildpacks)
- [Exec.d Output (TOML)](#execd-output-toml)
- [Deprecations](#deprecations)
- [`0.7`](#07)
- [launch.toml (TOML) `bom` Array](#launchtoml-toml-bom-array)
- [build.toml (TOML) `bom` Array](#buildtoml-toml-bom-array)
- [`0.3`](#03)
- [Build Plan (TOML) `requires.version` Key](#build-plan-toml-requiresversion-key)

Expand Down Expand Up @@ -132,7 +144,6 @@ Executable: `/bin/detect <platform[AR]> <plan[E]>`, Working Dir: `<app[AR]>`
| Standard error | Logs (warnings, errors)
| `<plan>` | Contributions to the the Build Plan (TOML)


### Build

Executable: `/bin/build <layers[EIC]> <platform[AR]> <plan[ER]>`, Working Dir: `<app[AI]>`
Expand All @@ -150,12 +161,12 @@ Executable: `/bin/build <layers[EIC]> <platform[AR]> <plan[ER]>`, Working Dir: `
| Standard output | Logs (info)
| Standard error | Logs (warnings, errors)
| `<layers>/launch.toml` | App metadata (see [launch.toml](#launchtoml-toml))
| `<layers>/launch.sbom.<ext>` | Launch Software Bill of Materials (see [Software-Bill-of-Materials](#bill-of-materials))
| `<layers>/launch.sbom.<ext>` | Launch Software Bill of Materials (see [Software-Bill-of-Materials](#software-bill-of-materials))
| `<layers>/build.toml` | Build metadata (see [build.toml](#buildtoml-toml))
| `<layers>/build.sbom.<ext>` | Build Software Bill of Materials (see [Software-Bill-of-Materials](#bill-of-materials))
| `<layers>/build.sbom.<ext>` | Build Software Bill of Materials (see [Software-Bill-of-Materials](#software-bill-of-materials))
| `<layers>/store.toml` | Persistent metadata (see [store.toml](#storetoml-toml))
| `<layers>/<layer>.toml` | Layer metadata (see [Layer Content Metadata](#layer-content-metadata-toml))
| `<layers>/<layer>.sbom.<ext>` | Layer Software Bill of Materials (see [Software-Bill-of-Materials](#bill-of-materials))
| `<layers>/<layer>.sbom.<ext>` | Layer Software Bill of Materials (see [Software-Bill-of-Materials](#software-bill-of-materials))
| `<layers>/<layer>/bin/` | Binaries for launch and/or subsequent buildpacks
| `<layers>/<layer>/lib/` | Shared libraries for launch and/or subsequent buildpacks
| `<layers>/<layer>/profile.d/` | Scripts sourced by Bash before launch
Expand Down Expand Up @@ -301,17 +312,18 @@ At the end of each individual buildpack's build phase:

### Purpose

The purpose of detection is to find an ordered group of buildpacks to use during the build phase.
These buildpacks must be compatible with the app.
The purpose of detection is to find an ordered group of image extensions and buildpacks to use during the generation and build phases.

For detect requirements that are specific to image extensions, see the [Image Extension Interface](image-extension.md).

### Process

**GIVEN:**
- An ordered list of buildpack groups resolved into buildpack implementations as described in [Order Resolution](#order-resolution)
- An ordered list of resolved groups as described in [Order Resolution](#order-resolution)
- A directory containing application source code
- A shell, if needed,

For each buildpack in each group in order, the lifecycle MUST execute `/bin/detect`.
For each buildpack implementation in each group in order, the lifecycle MUST execute `/bin/detect`. Image extensions and buildpacks are both buildpack implementations. For simplicity, the following section will refer to both as "buildpacks". Image extensions MUST always be optional during detection.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we stop using the term "buildpack implementation"? Or at least swap the word order to "implementation buildpack" if we can't think of a better term for a non-meta-buildpack? Meta-buildpacks are still implementations of buildpacks, so I think it's difficult to understand these sections.

This could be a separate PR, but I feel like adding image extensions makes this even more confusing.

Some name ideas:

  • atomic buildpacks
  • executable buildpacks
  • concrete buildpacks

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like concrete buildpacks.. has a nice construction theme to it ;p

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see #300 - I went with "executable buildpack" because that seemed most natural according to the definition I used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why image extensions MUST be optional?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sclevine could you elaborate?


1. **If** the exit status of `/bin/detect` is non-zero and the buildpack is not marked optional, \
**Then** the lifecycle MUST proceed to the next group or fail detection completely if no more groups are present.
Expand All @@ -325,7 +337,7 @@ For each buildpack in each group in order, the lifecycle MUST execute `/bin/dete
**Then** the lifecycle MUST proceed to the next group or fail detection completely if no more groups are present.

2. **If** at least one exit status from `/bin/detect` in the group is zero \
**Then** the lifecycle MUST select this group and proceed to the analysis phase.
**Then** the lifecycle MUST select this group and MAY proceed to the generation phase.

The selected group MUST be filtered to only include buildpacks with exit status zero.
The order of the buildpacks in the group MUST otherwise be preserved.
Expand Down Expand Up @@ -373,12 +385,14 @@ A buildpack's mixin requirements must be satisfied by the stack in one of the fo

#### Order Resolution

During detection, an order definition MUST be resolved into individual buildpack implementations.
During detection, an order definition for image extensions (if present) and an order definition for buildpacks MUST be resolved into individual buildpack implementations.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
During detection, an order definition for image extensions (if present) and an order definition for buildpacks MUST be resolved into individual buildpack implementations.
During detection, order definitions for image extensions and buildpacks MUST be resolved into a single order definition containing only atomic buildpacks.


Order definitions for image extensions MUST NOT contain nested orders. If an order definition for image extensions is present, it will be pre-pended to the order definition for buildpacks (as if the order definition for image extensions were an order buildpack).
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence (while "accurate", I think) doesn't make much sense... I am not sure how to improve it without re-working the entire section.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"During detection, order definitions MUST be resolved into individual buildpack implementations. If present, Image Extensions MAY provide an order definition. Buildpacks MUST provide an order definition."

Not sure if that covers the intent.. which itself kinda hints the original still has wiggle room.. (It's possible in my rephrasing to interpret that each extension would supply an order definition, or that there would be one for all extensions).

The original leaves bare the possibilty that an order defintiion for extensions is required, although the extensions themselves remain optional (as the binding of the 'if present' can be made to 'image extensions' rather than 'order definition').

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Order definitions for image extensions MUST NOT contain nested orders. If an order definition for image extensions is present, it will be pre-pended to the order definition for buildpacks (as if the order definition for image extensions were an order buildpack).
Order definitions for image extensions MUST NOT contain nested orders.
If an order definition for image extensions is present, it MUST be prepended to the order definition for buildpacks before the resolution process occurs.

To make this more clear, I think we should define the following six terms early in the spec:

  1. Order buildpack
  2. Atomic buildpack
  3. Order image extension (not currently allowed)
  4. Atomic image extension
  5. Order build module (currently only order buildpack)
  6. Atomic build module (atomic buildpacks and image extensions)

The names are just suggestions.
Maybe it's easier to say that image extensions are buildpacks?

  1. Normal order buildpack
  2. Normal atomic buildpack
  3. Image extension order bulidpack (not currently allowed)
  4. Image extension atomic buildpack
  5. Order buildpack (only normal buildpacks allowed)
  6. Atomic buildpack (atomic normal and extension buildpacks)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sclevine what is a build module? What is the difference between an order build module and an atomic build module?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's hash this out in https://github.com/buildpacks/spec/pull/300/files - we can rebase this PR when that one is merged.


The resolution process MUST follow this pattern:

Where:
- O and P are buildpack orders.
- O and P are image extension or buildpack orders.
- A through H are buildpack implementations.

Given:
Expand Down Expand Up @@ -456,7 +470,27 @@ For each buildpack in the group, the lifecycle

After analysis, the lifecycle MUST proceed to the build phase.

## Phase #3: Build
## Phase #3: Generation (optional)

### Purpose

The purpose of the generation phase is to generate Dockerfiles that can be used to extend the build and/or run base images. The generation phase MUST NOT be run for Windows builds.

### Process

See the [Image Extension Specification](#image-extension.md).

## Phase #4: Extension (optional)

### Purpose

The purpose of the extension phase is to apply the Dockerfiles generated in the generation phase to the build and/or run base images. The extension phase MUST NOT be run for Windows builds.

### Process

See the [Image Extension Specification](#image-extension.md).

## Phase #5: Build

![Build](img/build.svg)

Expand Down Expand Up @@ -544,14 +578,14 @@ Correspondingly, each `/bin/build` executable:

#### Unmet Buildpack Plan Entries

A buildpack SHOULD designate a Buildpack Plan entry as unmet if the buildpack did not satisfy the requirement described by the entry.
An image extension or buildpack SHOULD designate a Buildpack Plan entry as unmet if the buildpack did not satisfy the requirement described by the entry.
The lifecycle SHALL assume that all entries in the Buildpack Plan were satisfied by the buildpack unless the buildpack writes an entry with the given name to the `unmet` section of `build.toml`.

For each entry in `<plan>`:
- **If** there is an unmet entry in `build.toml` with a matching `name`, the lifecycle
- MUST include the entry in the `<plan>` of the next buildpack that provided an entry with that name during the detection phase.
- MUST include the entry in the `<plan>` of the next image extension or buildpack that provided an entry with that name during the detection phase.
- **Else**, the lifecycle
- MUST NOT include entries with matching names in the `<plan>` provided to subsequent buildpacks.
- MUST NOT include entries with matching names in the `<plan>` provided to subsequent image extensions or buildpacks.

#### Software-Bill-of-Materials

Expand Down Expand Up @@ -607,7 +641,7 @@ Additionally, a buildpack MAY specify sub-paths within `<app>` as `slices` in `l
Separate layers MUST be created during the export phase for each slice with one or more files or directories.
This minimizes data transfer when the app directory contains a known set of files.

## Phase #4: Export
## Phase #6: Export

![Export](img/export.svg)

Expand Down Expand Up @@ -704,17 +738,17 @@ Given the start command and execution strategy,

1. The lifecycle MUST set all buildpack-provided launch environment variables as described in the [Environment](#environment) section.

2. The lifecycle MUST
1. [execute](#execd) each file in each `<layers>/<layer>/exec.d` directory in the launch environment and set the [returned variables](#execd-output-toml) in the launch environment before continuing,
1. The lifecycle MUST
1. [execute](#execd) each file in each `<layers>/<layer>/exec.d` directory in the launch environment, with working directory `<app>`, and set the [returned variables](#execd-output-toml) in the launch environment before continuing,
1. Firstly, in order of `/bin/build` execution used to construct the OCI image.
2. Secondly, in alphabetically ascending order by layer directory name.
3. Thirdly, in alphabetically ascending order by file name.
2. [execute](#execd) each file in each `<layers>/<layer>/exec.d/<process>` directory in the launch environment and set the [returned variables](#execd-output-toml) in the launch environment before continuing,
2. [execute](#execd) each file in each `<layers>/<layer>/exec.d/<process>` directory in the launch environment, with working directory `<app>`, and set the [returned variables](#execd-output-toml) in the launch environment before continuing,
1. Firstly, in order of `/bin/build` execution used to construct the OCI image.
2. Secondly, in alphabetically ascending order by layer directory name.
3. Thirdly, in alphabetically ascending order by file name.

3. If using an execution strategy involving a shell, the lifecycle MUST use a single shell process to
1. If using an execution strategy involving a shell, the lifecycle MUST use a single shell process, with working directory `<app>`, to
1. source each file in each `<layers>/<layer>/profile.d` directory,
1. Firstly, in order of `/bin/build` execution used to construct the OCI image.
2. Secondly, in alphabetically ascending order by layer directory name.
Expand All @@ -725,10 +759,9 @@ Given the start command and execution strategy,
3. Thirdly, in alphabetically ascending order by file name.
3. source [†](README.md#linux-only)`<app>/.profile` or [‡](README.md#windows-only)`<app>/.profile.bat` if it is present.

1. The lifecycle MUST set the working directory for the start command to `<working-dir>`, or to `<app>` if `<working-dir>` is not specified.

3. If using an execution strategy involving a shell, the lifecycle MUST source [†](README.md#linux-only)`<app>/.profile` or [‡](README.md#windows-only)`<app>/.profile.bat` if it is present.

4. The lifecycle MUST invoke the start command with the decided execution strategy.
1. The lifecycle MUST invoke the start command with the decided execution strategy.

[†](README.md#linux-only)When executing a process using any execution strategy, the lifecycle SHOULD replace the lifecycle process in memory without forking it.

Expand Down Expand Up @@ -883,13 +916,15 @@ Prohibited:

### Requirements

The lifecycle MUST be implemented so that the detection and build phases do not have access to OCI image store credentials used in the analysis and export phases.
The lifecycle MUST be implemented so that the detection, generation, extension, and build phases do not have access to OCI image store credentials used in the analysis and export phases.
The lifecycle SHOULD be implemented so that each phase may run in a different container.

## Data Format

### launch.toml (TOML)

This section describes the `launch.toml` output by buildpacks; for image extensions see the [Image Extension Interface Specification](image-extension.md).

```toml
[[labels]]
key = "<label key>"
Expand All @@ -901,6 +936,7 @@ command = "<command>"
args = ["<arguments>"]
direct = false
default = false
working-dir = "<working directory>"

[[slices]]
paths = ["<app sub-path glob>"]
Expand Down Expand Up @@ -928,6 +964,7 @@ For each process, the buildpack:
- MAY specify an `args` list to be passed directly to the specified executable.
- MAY specify a `direct` boolean that bypasses the shell.
- MAY specify a `default` boolean that indicates that the process type should be selected as the [buildpack-provided default](https://github.com/buildpacks/spec/blob/main/platform.md#outputs-4) during the export phase.
- MAY specify a `working-dir` for the process. The `working-dir` defaults to the application directory if not specified.

An individual buildpack may only specify one process type with `default = true`. The lifecycle MUST select, from all buildpack-provided process types, the last process type with `default = true` as the buildpack-provided default. If multiple buildpacks define processes of the same type, the lifecycle MUST use the last process type definition ordered by buildpack execution for the combined process list (a non-default process type definition may override a default process type definition, leaving the app image with no default).

Expand All @@ -949,6 +986,8 @@ The lifecycle MUST include all unmatched files in the app directory in any numbe

### build.toml (TOML)

This section describes the `build.toml` output by buildpacks; for image extensions see the [Image Extension Interface Specification](image-extension.md).

```toml
[[unmet]]
name = "<dependency name>"
Expand Down Expand Up @@ -1060,7 +1099,7 @@ Buildpack authors MUST choose a globally unique ID, for example: "io.buildpacks.

*Key: `id = "<buildpack ID>"`*
- MUST only contain numbers, letters, and the characters `.`, `/`, and `-`.
- MUST NOT be `config` or `app`.
- MUST NOT be `config`, `app`, or `sbom`.
- MUST NOT be identical to any other buildpack ID when using a case-insensitive comparison.

**The buildpack version:**
Expand Down Expand Up @@ -1103,7 +1142,7 @@ Each stack in `stacks` either:

#### Order Buildpacks

A buildpack descriptor that specifies `order` MUST be [resolvable](#order-resolution) into an ordering of buildpacks that implement the [Buildpack Interface](#buildpack-interface).
A buildpack descriptor that specifies `order` MUST be [resolvable](#order-resolution) into an ordering of buildpacks that implement the [Buildpack Interface](#buildpack-interface). The `order` MUST include only regular buildpacks and MUST NOT include image extensions.

A buildpack reference inside of a `group` MUST contain an `id` and `version`.

Expand All @@ -1124,6 +1163,52 @@ Each `key`:
## Deprecations
This section describes all the features that are deprecated.

### `0.7`

#### launch.toml (TOML) `bom` Array

The `bom` array is deprecated.

```toml
[[bom]]
name = "<dependency name>"

[bom.metadata]
# arbitrary metadata describing the dependency
```

If the `bom` array is used, the buildpack:
- SHOULD add a bill-of-materials entry to the `bom` array describing each dependency contributed to the app image, where:
- `name` is REQUIRED.
- `metadata` MAY contain additional data describing the dependency.

The buildpack MAY add `bom` describing the contents of the app dir, even if they were not contributed by the buildpack.

When the build is complete, a legacy Bill of Materials (BOM) describing the app image MAY be generated for auditing purposes.

If generated, this legacy BOM MUST contain all `bom` entries in each `launch.toml` at the end of each `/bin/build` execution, in adherence with the process and data format outlined in the [Platform Interface Specification](platform.md) for legacy BOM formats.

#### build.toml (TOML) `bom` Array

The `bom` array is deprecated.

```toml
[[bom]]
name = "<dependency name>"

[bom.metadata]
# arbitrary metadata describing the dependency
```

If the `bom` array is used, the buildpack:
- SHOULD add a bill-of-materials entry to the `bom` array describing each dependency contributed to the build environment, where:
- `name` is REQUIRED.
- `metadata` MAY contain additional data describing the dependency.

When the build is complete, a legacy build BOM describing the build container MAY be generated for auditing purposes.

If generated, this legacy build BOM MUST contain all `bom` entries in each `build.toml` at the end of each `/bin/build` execution, in adherence with the process and data format outlined in the [Platform Interface Specification](platform.md) for legacy BOM formats.

### `0.3`

#### Build Plan (TOML) `requires.version` Key
Expand Down
Loading