Skip to content

Commit

Permalink
Merge pull request containerd#733 from Mossaka/pub-wasi-demo-app
Browse files Browse the repository at this point in the history
.github/workflows: add wasi-demo-app to the publish pipeline
  • Loading branch information
Mossaka authored Jan 28, 2025
2 parents e388bc3 + 1d0bf4f commit 5088658
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 8 deletions.
114 changes: 114 additions & 0 deletions .github/workflows/release-wasi-demo-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# yaml-language-server: $schema=https://json.schemastore.org/github-action.json

name: Release wasi-demo-app
run-name: wasi-demo-app@${{ inputs.version }}

on:
workflow_dispatch:
inputs:
version:
description: "The version of the image to release. (e.g., 1.2.3)"
type: string
required: true
dry_run:
description: "Run the release without actually releasing bits"
type: boolean
default: true

env:
CARGO_TERM_COLOR: always
IMAGES: "wasi-demo-app wasi-demo-oci wasi-demo-oci-artifact wasi-http"

jobs:
release-wasi-demo:
permissions:
packages: write
runs-on: ubuntu-latest
outputs:
wasi_demo_app: ${{ steps.get_digests.outputs.wasi_demo_app }}
wasi_demo_oci: ${{ steps.get_digests.outputs.wasi_demo_oci }}
wasi_demo_oci_artifact: ${{ steps.get_digests.outputs.wasi_demo_oci_artifact }}
wasi_http: ${{ steps.get_digests.outputs.wasi_http }}
steps:
- uses: actions/checkout@v4
- name: Setup build env
run: ./scripts/setup-linux.sh
- name: Install Rust and wasm32-wasi target
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: wasm32-wasip1
override: true

- name: Convert repository name to lowercase
id: prep
run: echo "repo=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT

- name: Login to GitHub container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Enable containerd image store
run: |
echo '{ "features": { "containerd-snapshotter": true } }' | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker
docker info -f '{{ .DriverStatus }}'
- name: Build oci tarballs
run: |
make docker/load
make docker/load/oci
make docker/load/http
docker image ls
- name: Tagging images
run: |
for image in $IMAGES; do
docker tag ghcr.io/containerd/runwasi/$image:latest ghcr.io/${{ steps.prep.outputs.repo }}/$image:${{ inputs.version }}
docker tag ghcr.io/containerd/runwasi/$image:latest ghcr.io/${{ steps.prep.outputs.repo }}/$image:latest
done
- name: Push images to ghcr.io
if: ${{ inputs.dry_run == false }}
run: |
for image in $IMAGES; do
docker push ghcr.io/${{ steps.prep.outputs.repo }}/$image:${{ inputs.version }}
docker push ghcr.io/${{ steps.prep.outputs.repo }}/$image:latest
done
- name: Display image digests
id: get_digests
run: |
for image in $IMAGES; do
DIGEST=$(docker inspect ghcr.io/${{ steps.prep.outputs.repo }}/$image --format '{{ .Id }}' --type image)
echo "Digest for $image: $DIGEST"
sanitized_image="${image//-/_}"
echo "$sanitized_image=$DIGEST" >> $GITHUB_OUTPUT
done
sign:
if: ${{ inputs.dry_run == false }}
needs:
- release-wasi-demo
strategy:
matrix:
image: ["wasi_demo_app", "wasi_demo_oci", "wasi_demo_oci_artifact", "wasi_http"]
uses: ./.github/workflows/sign.yml
with:
image-name: ${{ matrix.image }}
image-digest: ${{ needs.release-wasi-demo.outputs[matrix.image] }}

sbom:
if: ${{ inputs.dry_run == false }}
needs:
- release-wasi-demo
strategy:
matrix:
image: ["wasi_demo_app", "wasi_demo_oci", "wasi_demo_oci_artifact", "wasi_http"]
uses: ./.github/workflows/sbom.yml
with:
image-name: ${{ matrix.image }}
image-digest: ${{ needs.release-wasi-demo.outputs[matrix.image] }}
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,4 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
RELEASE_NAME: ${{ matrix.crate }}/v${{ matrix.version }}

83 changes: 83 additions & 0 deletions .github/workflows/sbom.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Generate SBOMs

on:
workflow_call:
inputs:
image-name:
type: string
required: true
image-digest:
type: string
required: true

jobs:
sbom:
name: Generate SBOM, sign and attach them to OCI image
permissions:
packages: write
id-token: write

runs-on: ubuntu-latest
steps:
- name: Sanitize image name
run: |
image="${{ inputs.image-name }}"
image="${image//_/-}"
echo "image=$image" >> $GITHUB_ENV
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0

- name: Install syft
uses: anchore/sbom-action/download-syft@e8d2a6937ecead383dfe75190d104edd1f9c5751 # v0.16.0

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Find repository name
shell: bash
run: |
set -e
IMG_REPOSITORY_NAME=$( echo ${{ github.repository }} | awk '{print tolower($0)}' )
echo IMG_REPOSITORY_NAME=${IMG_REPOSITORY_NAME} >> $GITHUB_ENV
- name: Create SBOM file
shell: bash
run: |
SYFT=$(which syft)
sudo $SYFT \
-o spdx-json \
--file $image-sbom.spdx \
ghcr.io/${{ env.IMG_REPOSITORY_NAME }}/$image@${{ inputs.image-digest }}
- name: Sign SBOM file
run: |
cosign sign-blob --yes \
--output-certificate $image-sbom.spdx.cert \
--output-signature $image-sbom.spdx.sig \
$image-sbom.spdx
- name: Attach SBOM to container image
shell: bash
run: |
cosign attach \
sbom --sbom $image-sbom.spdx \
ghcr.io/${{ env.IMG_REPOSITORY_NAME }}/$image@${{ inputs.image-digest }}
- name: Sign SBOM file pushed to OCI registry
shell: bash
run: |
set -e
SBOM_TAG="$(echo ${{ inputs.image-digest }} | sed -e 's/:/-/g').sbom"
cosign sign --yes \
ghcr.io/${{ env.IMG_REPOSITORY_NAME }}/$image:${SBOM_TAG}
- name: Upload SBOMs as artifacts
uses: actions/upload-artifact@v4
with:
name: sbom
path: $image-sbom-*
42 changes: 42 additions & 0 deletions .github/workflows/sign.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Sign image

on:
workflow_call:
inputs:
image-name:
type: string
required: true
image-digest:
type: string
required: true

jobs:
sign:
name: Sign image
permissions:
packages: write
id-token: write

runs-on: ubuntu-latest
steps:
- name: Sanitize image name
run: |
image="${{ inputs.image-name }}"
image="${image//_/-}"
echo "image=$image" >> $GITHUB_ENV
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Sign container image
run: |
IMG_REPOSITORY_NAME=$( echo ${{ github.repository }} | awk '{print tolower($0)}' )
cosign sign --yes \
ghcr.io/${IMG_REPOSITORY_NAME}/$image@${{ inputs.image-digest }}
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -218,17 +218,27 @@ dist/img-oci-artifact.tar: target/wasm32-wasip1/$(OPT_PROFILE)/img-oci-artifact.
load: dist/img.tar
sudo ctr -n $(CONTAINERD_NAMESPACE) image import --all-platforms $<

docker/load: dist/img.tar
docker load -i $<

CTR_VERSION := $(shell sudo ctr version | sed -n -e '/Version/ {s/.*: *//p;q;}')
load/oci: dist/img-oci.tar dist/img-oci-artifact.tar
@echo $(CTR_VERSION)\\nv1.7.7 | sort -crV || @echo $(CTR_VERSION)\\nv1.6.25 | sort -crV || (echo "containerd version must be 1.7.7+ or 1.6.25+ was $(CTR_VERSION)" && exit 1)
@echo using containerd $(CTR_VERSION)
sudo ctr -n $(CONTAINERD_NAMESPACE) image import --all-platforms $<
sudo ctr -n $(CONTAINERD_NAMESPACE) image import --all-platforms dist/img-oci-artifact.tar

docker/load/oci: dist/img-oci.tar dist/img-oci-artifact.tar
docker load -i dist/img-oci.tar
docker load -i dist/img-oci-artifact.tar

.PHONY: load/http
load/http: dist/http-img-oci.tar
sudo ctr -n $(CONTAINERD_NAMESPACE) image import --all-platforms $<

docker/load/http: dist/http-img-oci.tar
docker load -i $<

target/wasm32-wasip1/$(OPT_PROFILE)/img-oci.tar: target/wasm32-wasip1/$(OPT_PROFILE)/wasi-demo-app.wasm
mkdir -p ${CURDIR}/bin/$(OPT_PROFILE)/
cargo run --bin oci-tar-builder -- --name wasi-demo-oci --repo ghcr.io/containerd/runwasi --tag latest --module ./target/wasm32-wasip1/$(OPT_PROFILE)/wasi-demo-app.wasm -o target/wasm32-wasip1/$(OPT_PROFILE)/img-oci.tar
Expand Down
53 changes: 45 additions & 8 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
# Releasing a new crate version
# Release Process

This document describes the steps to release a new version of the crate.
This document describes the steps to release a new version of the crate or wasi-demo-app images.

## Overview
## Table of Contents

1. [Crate Release Process](#crate-release-process)
- [Overview](#overview)
- [Input Values for Release.yml](#input-values-for-releaseyml)
- [Crate Release Sequence](#crate-release-sequence)
- [Release Steps](#release-steps)
- [Local Development vs. Release](#local-development-vs-release)
- [Verify signing](#verify-signing)
- [First time release of a crate](#first-time-release-of-a-crate)
- [Release workflow summary](#release-workflow-summary)
2. [wasi-demo-app Release Process](#wasi-demo-app-release-process)
- [Overview](#overview-1)
- [Verify signing](#verify-signing-1)



## Crate Release Process

### Overview

To create a new release, either run the release.yml workflow as a workload_dispatch trigger through the GitHub UI, or via the following command substituting the proper values for crate and version.
```bash
Expand All @@ -20,7 +39,7 @@ Must release the creates in this order due to dependencies:
1. `containerd-shim-wasm`
2. All runtime-related crates.

## Release Steps
### Release Steps

1. Open a PR to bump crate versions and dependency versions in `Cargo.toml` for that crate, and change the "Unreleased" section in the `CHANGELOG.md` to the new version.
2. PR can be merged after 2 LGTMs
Expand All @@ -33,7 +52,7 @@ Must release the creates in this order due to dependencies:
>
> For step 5, some crates have binaries, such as the containerd-shim-wasmtime crate. These binaries are built as part of the release workflow and uploaded to the GitHub release page. You can download the binaries from the release page and verify that they work as expected.
## Local Development vs. Release
### Local Development vs. Release
Locally, crates reference local paths. During release, they target published versions.
Use both `path` and `version` fields in the workspace `Cargo.toml`:

Expand All @@ -43,7 +62,7 @@ e.g.
containerd-shim-wasm = { path = "crates/containerd-shim-wasm", version = "0.4.0" }
```

## Verify signing
### Verify signing

The release pipeline uses `cosign` to sign the release blobs, if any. It uses Github's OIDC token to authenticate with Sigstore to prove identity and outputs a `.bundle` file, which contains a signature and a key. This file can be verified using `cosign verify-blob` command, providing the workflow tag and Github as the issuer. The full command looks like this (e.g. wasmtime shim):

Expand All @@ -56,7 +75,7 @@ containerd-shim-wasmtime-v1

In the Github release page, please provide the above command in the instructions for the consumer to verify the release.

## First time release of a crate
### First time release of a crate

If the crate has never been published to crates.io before then ownership of the crate will need to be configured.
The containerd/runwasi-committers team will need to be added as an owner of the crate.
Expand All @@ -72,7 +91,7 @@ Alternatively, the cargo cli does support setting the token via an environment v

Now all members of the containerd/runwasi-committers team will have access to manage the crate (after they have accepted the invite to the crate).

## Release workflow summary
### Release workflow summary

The workflow performs the following steps:
- Verifies inputs
Expand All @@ -85,3 +104,21 @@ The workflow performs the following steps:
- Creates a GitHub release for that crate (attaching any artifacts)

The workflow utilizes a bot account (@containerd-runwasi-release-bot) to publish the crate to crates.io. The bot account is only used to get a limited-scope API token to publish the crate on crates.io. The token is stored as a secret in the repository and is only used by the release workflow.

## `wasi-demo-app` Release Process

### Overview

To release a new version of the wasi-demo-app images, run the release-wasi-demo-app.yml workflow using the following command, substituting the correct version:

```bash
gh workflow run release-wasi-demo-app.yml -f dry_run=false -f version=0.1.0
```

### Verify signing

To verify the signature of the release, run the following command:

```bash
cosign verify ghcr.io/containerd/runwasi/wasi-demo-app:0.1.0 --certificate-identity https://github.com/containerd/runwasi/.github/workflows/sign.yml@refs/heads/main --certificate-oidc-issuer https://token.actions.githubusercontent.com
```

0 comments on commit 5088658

Please sign in to comment.