Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
112 changes: 112 additions & 0 deletions .docs/build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Build action

## Description

The **build** composite action builds a Deckhouse module with [werf](https://werf.io/), pushes bundle and release-channel images to the registry, registers the module tag, and optionally copies VEX attestations for the bundle image.

Run **setup** before **build** in the same job.

```yaml
deckhouse/modules-actions/build@main
```

## New in `vex-attestations`

### Edition and build report artifact

Pass `edition` when building edition-specific modules (e.g. `fe`, `ee`). The action:

1. Exports `EDITION` for werf.
2. Uploads `images_tags_werf.json` as a workflow artifact named `build_report_<edition>` (or `build_report` when edition is empty).

The artifact is saved even when the build step fails, so downstream jobs can inspect image metadata.

### Vault and registry authentication

Optional inputs are forwarded to the werf build environment:

| Input | Env var | Description |
|-------|---------|-------------|
| `vault_addr` | `VAULT_ADDR` | Vault server address |
| `vault_key` | `VAULT_KEY` | Key name in Vault |
| `vault_role` | `VAULT_ROLE` | Vault auth role |
| `transit_secret_engine_path` | `TRANSIT_SECRET_ENGINE_PATH` | Transit secrets engine path |
| `registry_user` | `REGISTRY_USER` | Registry username - is used for cosign attestations |
| `registry_password` | `REGISTRY_PASSWORD` | Registry password - is used for cosign attestations |

### Bundle VEX attestation

After `crane copy` pushes the bundle image, the action checks for an attestation tag:

```
<repo>:sha256-<digest>.att
```

If the manifest exists, it is copied to the same tag on the destination repo. If not, the step logs a skip message and continues.

## Inputs

### Required

| Input | Description |
|-------|-------------|
| `module_source` | Registry repository for the module, e.g. `registry.example.com/module-source` |
| `module_name` | Module name, e.g. `my-module` |
| `module_tag` | Version tag, e.g. `v1.21.1` or branch name |

### Optional

| Input | Description |
|-------|-------------|
| `secondary_repo` | Secondary registry path for the module |
| `source_repo` | Source Git repository URL |
| `source_repo_ssh_key` | SSH key for `source_repo` |
| `svace_enabled` | Enable Svace static analysis integration |
| `svace_analyze_host` | Svace analyze server hostname |
| `svace_analyze_ssh_user` | SSH user for Svace server |
| `svace_analyze_ssh_key` | SSH private key for Svace server |
| `edition` | Module edition; sets `EDITION` and artifact name suffix |
| `vault_addr` | Vault address for signing/secrets |
| `vault_key` | Vault key name |
| `vault_role` | Vault JWT/OIDC role |
| `transit_secret_engine_path` | Vault transit engine path |
| `registry_user` | Registry username for werf build |
| `registry_password` | Registry password for werf build |

## Example

```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: deckhouse/modules-actions/setup@v4
with:
registry: registry.deckhouse.io
registry_login: ${{ secrets.REGISTRY_LOGIN }}
registry_password: ${{ secrets.REGISTRY_PASSWORD }}
- uses: deckhouse/modules-actions/build@main
with:
module_source: registry.deckhouse.io/deckhouse/fe/modules
module_name: my-module
module_tag: ${{ github.ref_name }}
edition: fe
vault_addr: ${{ secrets.VAULT_ADDR }}
vault_key: ${{ secrets.VAULT_KEY }}
vault_role: ${{ secrets.VAULT_ROLE }}
transit_secret_engine_path: ${{ secrets.TRANSIT_SECRET_ENGINE_PATH }}
registry_user: ${{ secrets.REGISTRY_USER }}
registry_password: ${{ secrets.REGISTRY_PASSWORD }}
```

## Artifacts

| Artifact name | Contents | When |
|---------------|----------|------|
| `build_report` | `images_tags_werf.json` | Build finished (success or failure), no `edition` |
| `build_report_<edition>` | `images_tags_werf.json` | Build finished (success or failure), `edition` set |

Full workflow example: [.examples/build.yml](../.examples/build.yml).

PR changelog for this feature set: [CHANGELOG-vex-attestations.md](./CHANGELOG-vex-attestations.md).
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This repository contains GitHub Actions workflows for building and deploying mod
| Workflow | Description |
|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| [**setup**](./setup/action.yml) | Sets up the environment for building and deploying modules. This workflow **must** be run before any other workflows. |
| [**build**](./build/action.yml) | Builds the Deckhouse modules using the [werf](https://werf.io/) tool. |
| [**build**](./build/action.yml) | Builds Deckhouse modules with [werf](https://werf.io/), copies bundle VEX attestations, and uploads the build report. See [build docs](./.docs/build.md). |
| [**deploy**](./deploy/action.yml) | Deploys the Deckhouse modules to the one of selected release channels. |
| [**cve_scan**](./cve_scan/action.yml) | Trivy CVE Scan of module images. Documentation can be found [here](./.docs/cve_scan.md) |
| [**svace_analyze**](./svace_analyze/action.yml) | Include svace analyze action to analyze and import builds made with svace tool |
Expand Down Expand Up @@ -42,3 +42,11 @@ To use these GitHub Action workflows in your own repository:
3. Make sure to configure any necessary secrets or environment variables in your GitHub repository settings to enable secure deployment.

4. Trigger the workflows manually or automatically on each push, pull request, or any other event as needed.

## Documentation

| Topic | Description |
|-------|-------------|
| [Build action](./.docs/build.md) | Vault/registry inputs, edition support, VEX attestation copy, build report artifacts |
| [CVE scan](./.docs/cve_scan.md) | Trivy scanning and DefectDojo upload |
| [VEX attestations changelog](./.docs/CHANGELOG-vex-attestations.md) | Changes in branch `vex-attestations` vs `main` |
64 changes: 62 additions & 2 deletions build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,45 @@ inputs:
source_repo_ssh_key:
description: "SSH private key for the source repository"
required: false
vault_addr:
description: "Vault adddress"
required: false
vault_key:
description: "Key in the vault"
required: false
transit_secret_engine_path:
description: "Transit engine secret path"
required: false
vault_role:
description: "Vault auth role"
required: false
registry_user:
description: "User to authenticate to registry"
required: false
registry_password:
description: "Password to authenticate to registry"
required: false
edition:
description: "Edition of the builded artifact"
required: false
default: ''

runs:
using: "composite"
steps:
- name: Set edition
id: set_edition
shell: bash
run: |
edition="${{ inputs.edition }}"
if [ -n "$edition" ]; then
echo "Set edition: $edition"
echo "EDITION=${edition}" >> $GITHUB_ENV
echo "build_report_postfix=_${edition}" >> $GITHUB_OUTPUT
else
echo "No edition has been detected."
fi

- name: Set secondary repo if input exists
shell: bash
if: ${{ inputs.secondary_repo != '' }}
Expand Down Expand Up @@ -121,9 +156,15 @@ runs:
werf build --repo=${{ inputs.module_source }}/${{ inputs.module_name }} --save-build-report --build-report-path images_tags_werf.json
env:
MODULES_MODULE_TAG: ${{ inputs.module_tag }}
REGISTRY_USER: "${{ inputs.registry_user }}"
REGISTRY_PASSWORD: "${{ inputs.registry_password }}"
SVACE_ANALYZE_HOST: "${{ inputs.svace_analyze_host }}"
SVACE_ANALYZE_SSH_USER: "${{ inputs.svace_analyze_ssh_user }}"
SVACE_ENABLED: "${{ inputs.svace_enabled }}"
VAULT_ADDR: "${{ inputs.vault_addr }}"
VAULT_KEY: "${{ inputs.vault_key }}"
VAULT_ROLE: "${{ inputs.vault_role }}"
TRANSIT_SECRET_ENGINE_PATH: "${{ inputs.transit_secret_engine_path }}"

- name: Cleanup ssh-agent
if: ${{ steps.ssh_agent.outcome != 'skipped' && always() }}
Expand All @@ -136,11 +177,22 @@ runs:
- name: Bundle the module image
shell: bash
run: |
IMAGE_SRC="$(jq -r '.Images."bundle".DockerImageName' images_tags_werf.json)"
IMAGE_DST="$(jq -r '.Images.bundle.DockerRepo' images_tags_werf.json):${{ inputs.module_tag }}"
IMAGE_REPO="$(jq -r '.Images.bundle.DockerRepo' images_tags_werf.json)"
IMAGE_SRC="$(jq -r '.Images.bundle.DockerImageName' images_tags_werf.json)"
IMAGE_DST="${IMAGE_REPO}:${{ inputs.module_tag }}"
echo "✨ Bundle image : Pushing ${IMAGE_SRC} to ${IMAGE_DST}"
crane copy ${IMAGE_SRC} ${IMAGE_DST}

# Copying attestation for bundle
IMAGE_DIGEST="$(jq -r ".Images.bundle.DockerImageDigest" images_tags_werf.json)"
IMAGE_DIGEST="${IMAGE_DIGEST#sha256:}"
if (crane manifest "${IMAGE_REPO}:sha256-${IMAGE_DIGEST}.att" > /dev/null 2>&1); then
echo "✨ [$(date -u)] Copying 'bundle' attestation"
crane copy "${IMAGE_REPO}:sha256-${IMAGE_DIGEST}.att" "${IMAGE_REPO}:sha256-${IMAGE_DIGEST}.att"
else
echo "✨ [$(date -u)] Attestation for 'bundle' not found, skipping..."
fi

- name: Prepare the release-channel image
shell: bash
run: |
Expand All @@ -157,3 +209,11 @@ runs:
--oci-empty-base \
--new_layer "" \
--new_tag "${{ inputs.module_source }}:${{ inputs.module_name }}"

- name: Save build report
if: ${{ always() && (steps.build.outcome == 'success' || steps.build.outcome == 'failure') }}
uses: actions/upload-artifact@v7.0.1
with:
name: build_report${{ steps.set_edition.outputs.build_report_postfix }}
path: images_tags_werf.json
overwrite: true
Loading