name: component
permissions:
contents: read
on:
push:
branches: [main]
pull_request:
jobs:
negative-control:
name: the export check must reject a component missing an export
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@1.97.0
with:
targets: wasm32-unknown-unknown
- name: Install wasm-tools
run: cargo install wasm-tools --version 1.258.0 --locked
- name: The checker must test itself
run: python3 scripts/test_check_component_exports.py
- name: Build a component with credential.present removed
run: |
scratch=$(mktemp -d)
rmdir "$scratch"
git worktree add --detach "$scratch" HEAD
trap 'git worktree remove --force "$scratch" || rm -rf "$scratch"' EXIT
python3 scripts/component-negative-control.py mutate "$scratch" identity.credential.present
# A failure here is the scratch build breaking, not the checker
# rejecting anything, and is reported as such.
if ! (
cd "$scratch"
cargo build --release --target wasm32-unknown-unknown \
--no-default-features --features component --locked
wasm-tools component new \
target/wasm32-unknown-unknown/release/aethel_core.wasm \
-o "$GITHUB_WORKSPACE/broken.component.wasm"
); then
echo "CONTROL BUILD FAILED: the scratch component did not build."
echo "This says nothing about the export check; fix the build first."
exit 1
fi
- name: The checker must reject it, because that export is missing
run: |
python3 scripts/component-negative-control.py verify \
wit/aethel-core.wit broken.component.wasm identity.credential.present
provenance:
name: the recorded revision must be a real ancestor
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: component.rev must name an ancestor of this commit
run: |
rev=$(tr -d '[:space:]' < component.rev)
if ! printf '%s' "$rev" | grep -qE '^[0-9a-f]{40}$'; then
echo "component.rev is not a full lowercase commit sha: '$rev'"
exit 1
fi
if ! git cat-file -e "${rev}^{commit}" 2>/dev/null; then
echo "component.rev names $rev, which is not a commit in this repository."
exit 1
fi
# Ancestry, not mere existence: a sha copied from an unrelated branch
# would pass `cat-file`. It is an ancestor rather than HEAD itself
# because a file cannot contain the hash of the commit containing it,
# which is why GIT_REVISION documents itself as one commit behind.
if ! git merge-base --is-ancestor "$rev" HEAD; then
echo "component.rev names $rev, which is not an ancestor of HEAD."
echo "It must be the commit the recorded component was built from."
exit 1
fi
echo "component.rev names $rev, an ancestor of $(git rev-parse HEAD)"
component:
name: build, validate and reproduce the component
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@1.97.0
with:
targets: wasm32-unknown-unknown
- name: Install wasm-tools
run: cargo install wasm-tools --version 1.258.0 --locked
- name: Build the component
run: |
cargo build --release --target wasm32-unknown-unknown \
--no-default-features --features component --locked
wasm-tools component new \
target/wasm32-unknown-unknown/release/aethel_core.wasm \
-o build1.component.wasm
- name: The component must validate and match the declared world exactly
run: |
wasm-tools validate build1.component.wasm
python3 scripts/check-component-exports.py \
wit/aethel-core.wit build1.component.wasm
- name: The component must execute and agree with the native API
run: |
cp build1.component.wasm aethel_core.component.wasm
cargo test --features component-tests --test component_execution --locked
- name: Two builds of the same commit must be byte-identical
run: |
rm -rf target/wasm32-unknown-unknown/release
cargo build --release --target wasm32-unknown-unknown \
--no-default-features --features component --locked
wasm-tools component new \
target/wasm32-unknown-unknown/release/aethel_core.wasm \
-o build2.component.wasm
if ! cmp -s build1.component.wasm build2.component.wasm; then
echo "NOT REPRODUCIBLE: two builds of the same source differ"
sha256sum build1.component.wasm build2.component.wasm
exit 1
fi
echo "reproducible: $(sha256sum build1.component.wasm)"
- name: The built hash must match the one checked into the repo
run: |
built=$(sha256sum build1.component.wasm | cut -d' ' -f1)
declared=$(cut -d' ' -f1 component.sha256)
if [ "$built" != "$declared" ]; then
echo "hash mismatch"
echo " built: $built"
echo " declared: $declared (component.sha256)"
echo "If this change is intended, update component.sha256."
exit 1
fi
echo "hash matches component.sha256: $built"