Skip to content
Open
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
50 changes: 41 additions & 9 deletions .github/workflows/build-and-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,42 @@ permissions:
actions: read # Required for workflow access

jobs:
# Resolve component versions once: pinned in versions.env, else upstream latest
resolve-tags:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

resolve-tags inherits write permission. It only needs read. Permissions can be narrowed with a resolve-tags job-level permissions: contents: read

name: resolve component tags
runs-on: ubuntu-latest
outputs:
snphost: ${{ steps.resolve.outputs.snphost }}
snpguest: ${{ steps.resolve.outputs.snpguest }}
beacon: ${{ steps.resolve.outputs.beacon }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Resolve tags (pin from versions.env, fallback to latest)
id: resolve
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
. versions.env

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

typos in versions.env could cause failures whose root causes would be difficult to find - add checks

resolve() { # $1=repo $2=pinned tag
if [ -n "$2" ]; then
echo "$2"
else
gh release view --repo "$1" --json tagName --jq '.tagName'
fi
}
{
echo "snphost=$(resolve virtee/snphost "${SNPHOST_TAG:-}")"
echo "snpguest=$(resolve virtee/snpguest "${SNPGUEST_TAG:-}")"
echo "beacon=$(resolve AMDEPYC/beacon "${BEACON_TAG:-}")"
Comment on lines +57 to +59

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A lot would have to go wrong for resolve to fail, but it failing used to cause the step to fail, now it doesn't, such failures would be masked. One possible fix:

# with this assignment approach, resolve failing isn't masked
snphost=$(resolve virtee/snphost "${SNPHOST_TAG:-}")
snpguest=$(resolve virtee/snpguest "${SNPGUEST_TAG:-}")
beacon=$(resolve AMDEPYC/beacon "${BEACON_TAG:-}")

# some, but not all, resolve failures prevent following code from exiting
for t in "$snphost" "$snpguest" "$beacon"; do
[ -n "$t" ] && [ "$t" != null ] || { echo "::error::could not resolve a component tag"; exit 1; }
done

{
echo "snphost=$snphost"
echo "snpguest=$snpguest"
echo "beacon=$beacon"
} >> "$GITHUB_OUTPUT"

} >> "$GITHUB_OUTPUT"

# Development release for tag or main pushes
create-release:
name: create new release for tagged or latest assets
needs: resolve-tags
runs-on: ubuntu-latest
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.replace_release == 'true')
steps:
Expand Down Expand Up @@ -63,6 +96,7 @@ jobs:

build:
name: ${{ matrix.distro }}-${{ matrix.release }}
needs: resolve-tags
runs-on: ubuntu-24.04
strategy:
fail-fast: false
Expand Down Expand Up @@ -99,17 +133,15 @@ jobs:
sudo apt update
sudo apt install -y mkosi

- name: Fetch latest release tags
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Apply resolved release tags
run: |
set -euo pipefail
# Fetch latest tags using gh CLI (automatically authenticated)
SNPGUEST_TAG=$(gh release view --repo virtee/snpguest --json tagName --jq '.tagName')
BEACON_TAG=$(gh release view --repo AMDEPYC/beacon --json tagName --jq '.tagName')
SNPHOST_TAG=$(gh release view --repo virtee/snphost --json tagName --jq '.tagName')

# Tags resolved once by the resolve-tags job (pinned in versions.env, else upstream latest)
SNPGUEST_TAG="${{ needs.resolve-tags.outputs.snpguest }}"
BEACON_TAG="${{ needs.resolve-tags.outputs.beacon }}"
SNPHOST_TAG="${{ needs.resolve-tags.outputs.snphost }}"

Comment on lines +139 to +144

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

a lot would have to go wrong, but this approach allows shell command injection. Better to use env: block:

  • name: Apply resolved release tags
    env:
    SNPGUEST_TAG: ${{ needs.resolve-tags.outputs.snpguest }}
    BEACON_TAG: ${{ needs.resolve-tags.outputs.beacon }}
    SNPHOST_TAG: ${{ needs.resolve-tags.outputs.snphost }}
    run: |
    set -euo pipefail

    sed -i "/^[Build]/a\Environment=SNPGUEST_TAG=$SNPGUEST_TAG" modules/build/common/snpguest/mkosi.conf
    sed -i "/^[Build]/a\Environment=BEACON_TAG=$BEACON_TAG" modules/build/host/beacon/mkosi.conf
    ...

# Inject environment variables into mkosi.conf files
sed -i "/^\[Build\]/a\Environment=SNPGUEST_TAG=$SNPGUEST_TAG" modules/build/common/snpguest/mkosi.conf
sed -i "/^\[Build\]/a\Environment=BEACON_TAG=$BEACON_TAG" modules/build/host/beacon/mkosi.conf
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Each certification run automatically creates a GitHub Issue containing the resul

Host and Guest images are constructed in GitHub Workflows via [`mkosi`](https://github.com/systemd/mkosi). Host images are designed to be booted on a SEV-enabled EPYC server, and are configured with a series of tests in the form of custom systemd services that will run on an embedded guest image. The resulting host and guest images are available in GitHub releases.

The upstream release versions of the components baked into the images — [`snphost`](https://github.com/virtee/snphost), [`snpguest`](https://github.com/virtee/snpguest), and [`beacon`](https://github.com/AMDEPYC/beacon) — are pinned in [`versions.env`](./versions.env) at the repository root. Bumps are made deliberately via a pull request so that any breakage in a new upstream release is caught at review time; the `build-and-release` workflow resolves the pinned tags (falling back to the upstream latest for any empty entry) and reports the resolved `repository → version` pairs in the `resolve-tags` job summary. Leave a value empty in `versions.env` to track the upstream latest release at build time.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

resolve-tags job summary?


[cert-3.0]: ./docs/certifications.md#amd-epyc-7003-milan
[cert-3.1]: ./docs/certifications.md#amd-epyc-9004-genoa
[cert-4.0]: ./docs/certifications.md#amd-epyc-7004-bergamo
Expand Down
4 changes: 4 additions & 0 deletions docs/how-to-add-new-os-images.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ You can create and publish new host or guest images in `sev-certify` with `mkosi

Then, verify for successful execution with the built new host and guest OS images under `devel` tag.

The `build-and-release` workflow resolves the `snphost`, `snpguest` and `beacon` release tags in its `resolve-tags` job before building. Versions are pinned in [`versions.env`](https://github.com/AMDEPYC/sev-certify/blob/main/versions.env) at the repository root (an empty entry falls back to the upstream latest release). The resolved repository/version pairs are shown as a table in the `resolve-tags` job summary.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the table?


If the `build-and-release` workflow fails, you need to troubleshoot for the error in the workflow log, implement changes, and retest until successful execution.

- **<ins>Test the new OS Host/Guest Images:</ins>**
Expand Down Expand Up @@ -183,6 +185,8 @@ make GENERATE_MANIFEST=yes guest-<distro>-<release>

The `GENERATE_MANIFEST` variable defaults to empty in the Makefile. When set to a truthy value (`y`, `yes`, or `1`), mkosi is invoked with the environment variable to generate manifest files.

The `make tags` target resolves the `snphost`, `snpguest` and `beacon` versions from [`versions.env`](https://github.com/AMDEPYC/sev-certify/blob/main/versions.env); pinned entries are used as-is and empty entries fall back to fetching the upstream latest release.

**For local builds using mkosi directly**, pass the environment variable:

```bash
Expand Down
16 changes: 11 additions & 5 deletions images/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,28 @@ CLEAN_IMAGES := $(addprefix clean-,$(IMAGES))
GH_AUTH := $(if $(GITHUB_TOKEN),-H "Authorization: Bearer $(GITHUB_TOKEN)")
GH_LATEST = curl -sf $(GH_AUTH) https://api.github.com/repos/$(1)/releases/latest | jq -r '.tag_name'

# Pinned component versions (override on the command line with make VAR=x)
-include ../versions.env

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

typos in versions.env could cause failures whose root causes would be difficult to find - add checks


.PHONY: all clean list status tags $(IMAGES) $(CLEAN_IMAGES)

# Pinned versions from ../versions.env are used as-is; empty entries fall back
# to fetching the latest upstream release.
tags:
@set -e; \
trap 'rm -f .tags.tmp' EXIT; \
fetch() { \
tag=$$($(call GH_LATEST,$$1)); \
tag=$$3; \
if [ -z "$$tag" ]; then tag=$$($(call GH_LATEST,$$1)); fi; \
if [ -z "$$tag" ] || [ "$$tag" = "null" ]; then \
echo "Failed to fetch tag for $$1. Try: export GITHUB_TOKEN=\$$(gh auth token)" >&2; \
echo "Failed to resolve tag for $$1. Try: export GITHUB_TOKEN=\$$(gh auth token)" >&2; \
exit 1; \
fi; \
echo "$$2=$$tag"; \
}; \
{ fetch virtee/snpguest SNPGUEST_TAG; \
fetch AMDEPYC/beacon BEACON_TAG; \
fetch virtee/snphost SNPHOST_TAG; } > .tags.tmp; \
{ fetch virtee/snpguest SNPGUEST_TAG "$(SNPGUEST_TAG)"; \
fetch AMDEPYC/beacon BEACON_TAG "$(BEACON_TAG)"; \
fetch virtee/snphost SNPHOST_TAG "$(SNPHOST_TAG)"; } > .tags.tmp; \
mv .tags.tmp .tags
@cat .tags

Expand Down
6 changes: 6 additions & 0 deletions versions.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Upstream release versions used to build the host/guest images.
# Bump deliberately via a PR so any breakage in a new release is caught at review time.
# Leave a value empty to fall back to the upstream latest release at build time.
SNPHOST_TAG=v0.9.0
SNPGUEST_TAG=v0.10.0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add comment explaining why not the latest release:

snpguest held at v0.10.0: v0.11.0 (virtee/snpguest#145) changed generate id-block --family-id/--image-id from 16-char ASCII to 32-char hex. sev_verify/cvm_props.py passes ASCII defaults and compares report bytes as ASCII, so ID-block generation (id_block_test, key_derivation_test) currently fails on v0.11.0.

BEACON_TAG=v1.1.0
Loading