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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ Inputs are visible in GitHub, so none of them is secret.
{"grant": "ployzgrant1:…", "commit": "<40 hex>", "fingerprint": "<64 hex>", "ployzVersion": "<x.y.z[-beta.n]>", "deployment": { "snapshots": [{ "resolvedEnv": {} }] }}
```
The token, the grant, and every `resolvedEnv` value are masked (`::add-mask::`, per line) before anything else runs. Lines under 4 characters are not: masking `0` would star out every 0 in the log. A check-in that can't reach Cloud is retried; an HTTP error is not, and the job fails with Cloud's status and message.
4. Installs exactly `ployzVersion` from `https://ployz.sh`: the version of the Cloud process that computed `fingerprint`, so they match even while Cloud rolls out a new version. The installer verifies the release checksum. If the install fails, the Action sends Cloud a final report naming the version (`installFailed`), so Cloud moves the build on to the next Builder.
4. Installs exactly `ployzVersion` from `https://ployz.sh`: the version of the Cloud process that computed `fingerprint`, so they match even while Cloud rolls out a new version. The installer verifies the release checksum. The install is timed as the first Build Step, "Installing ployz". If it fails, the Action sends Cloud a final report with that step failed and naming the version (`installFailed`), so Cloud moves the build on to the next Builder.
5. Checks out `commit` without persisting credentials.
6. Runs `PLOYZ_BUILD_GRANT=… ployz build --deployment <file> --commit <commit> --fingerprint <fingerprint> --events <file>`. The deployment file lives in `$RUNNER_TEMP` and is deleted when the job ends, pass or fail.
7. Reports the Build Steps while it builds, every few seconds, each time with a fresh OIDC token: `POST {cloud}/api/builds/{build}/steps` with `{"from": <line>, "events": [<new ployz build --events lines>]}`, where `from` is the 0-based line the batch starts at. Cloud files only lines it hasn't taken, so a retried batch is harmless. As soon as `ployz build` prints its result (the image is in the Machine), or when it fails, the last batch adds `"platforms": [...]`; empty means the build failed. That report settles the build, and Cloud takes no more. `ployz build` then uploads the build cache to the GitHub Actions cache; a failed upload is only a warning.
7. Reports the Build Steps while it builds, every few seconds, each time with a fresh OIDC token: `POST {cloud}/api/builds/{build}/steps` with `{"from": <line>, "events": [<new event lines>]}`, where `from` is the 0-based line the batch starts at. The lines are the "Installing ployz" step, then `ployz build --events`, which includes the push and its per-layer progress. Cloud files only lines it hasn't taken, so a retried batch is harmless. As soon as `ployz build` prints its result (the image is in the Machine), or when it fails, the last batch adds `"platforms": [...]`; empty means the build failed. That report settles the build, and Cloud takes no more. `ployz build` then uploads the build cache to the GitHub Actions cache; a failed upload is only a warning.

Output `digest` is the manifest digest the Machine received. Cloud does not trust it: it reads the pushed digest from the Machine when it ends the grant.

Expand Down
10 changes: 8 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ export PLOYZ_BUILD_GRANT
: >"$events"
sent=0

# Every event line so far: prepare.sh's "Installing ployz", then the build's own.
steps() {
[[ ! -f "$work/install.jsonl" ]] || cat "$work/install.jsonl"
cat "$events"
}

# Posts the complete event lines not sent yet, from line $sent; with $1, the platforms built, the
# build's end. A fresh OIDC token proves this run each time. Best effort: a refused batch is resent.
report() {
local lines
lines=$(wc -l <"$events")
lines=$(steps | wc -l)
[[ -n "${1:-}" || $lines -gt $sent ]] || return 0
tail -n "+$((sent + 1))" "$events" | head -n "$((lines - sent))" |
steps | tail -n "+$((sent + 1))" | head -n "$((lines - sent))" |
jq -cs --argjson from "$sent" --argjson platforms "${1:-null}" \
'{from: $from, events: .} + (if $platforms == null then {} else {platforms: $platforms} end)' >"$work/steps.json"
oidc_token "$cloud"
Expand Down
13 changes: 12 additions & 1 deletion prepare.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,20 @@ version=$(jq -r '.ployzVersion' "$work/check-in.json")

# The exact version that computed the fingerprint: during a Cloud rollout, the Cloud that
# dispatched this build may run another version than the one that answered the check-in.
# The install is the first Build Step, timed here where it runs, as a `ployz build --events` line:
# build.sh reports it ahead of the build's own. $1: why it failed.
install_started=$(date -u +%FT%T.%3NZ)
install_step() {
jq -cn --argjson at "$(date +%s%3N)" --arg started "$install_started" --arg completed "$(date -u +%FT%T.%3NZ)" --arg error "${1:-}" \
'{at: $at, event: {Build: {Step: {id: "install", name: "Installing ployz", started: $started, completed: $completed,
cached: false, error: (if $error == "" then null else $error end)}}}}' >"$work/install.jsonl"
}
# A failed install never reaches build.sh, so its final report goes from here, naming the version:
# Cloud then moves the build on to the next Builder instead of waiting for the run to end.
install_failed() {
jq -n --arg version "$version" '{from: 0, events: [], platforms: [], installFailed: $version}' >"$work/steps.json"
install_step "Could not install ployz $version."
jq -n --arg version "$version" --slurpfile events "$work/install.jsonl" \
'{from: 0, events: $events, platforms: [], installFailed: $version}' >"$work/steps.json"
oidc_token "$cloud"
cloud_post "$cloud/api/builds/$PLOYZ_BUILD_ID/steps" "$work/steps-response.json" \
-H "Content-Type: application/json" --data-binary "@$work/steps.json" ||
Expand All @@ -72,6 +82,7 @@ install_failed() {
}
curl -fsSL https://ployz.sh -o "$work/install.sh" || install_failed
PLOYZ_VERSION="$version" INSTALL_BIN_DIR="$work/bin" sh "$work/install.sh" || install_failed
install_step
echo "$work/bin" >>"$GITHUB_PATH"

echo "commit=$commit" >>"$GITHUB_OUTPUT"
5 changes: 3 additions & 2 deletions test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ grep -qxF "digest=sha256:abc" "$GITHUB_OUTPUT" || { echo "FAIL: digest output" >
# Steps go to Cloud while the build runs, each batch from where the last one ended; the last carries the platforms.
# shellcheck disable=SC2016 # jq variables, not shell ones
reported='length >= 2 and .[0].from == 0 and (.[0] | has("platforms") | not)
and ([.[].events[].at] == [1, 2, 3]) and (. as $b | all(range(1; $b | length); $b[.].from == $b[. - 1].from + ($b[. - 1].events | length)))'
and ([.[].events[].at][1:] == [1, 2, 3]) and .[0].events[0].event.Build.Step.name == "Installing ployz" and (. as $b | all(range(1; $b | length); $b[.].from == $b[. - 1].from + ($b[. - 1].events | length)))'
jq -s -e "$reported"' and .[-1].platforms == ["linux/amd64"]' "$tmp/posted.jsonl" >/dev/null ||
{ echo "FAIL: Build Steps not posted as they happened" >&2; cat "$tmp/posted.jsonl" >&2; exit 1; }
[ -e "$tmp/reported-during-export" ] || { echo "FAIL: the final report waited for the cache export" >&2; exit 1; }
Expand Down Expand Up @@ -115,7 +115,8 @@ grep -qF "::error::Ployz Cloud refused the check-in for build b-1 (HTTP 409: Thi
# A failed install tells Cloud, naming the version, so Cloud moves the build on; the job fails.
rm -f "$tmp/posted.jsonl"
if log=$(INSTALL_FAIL=1 "$here/prepare.sh" 2>&1); then echo "FAIL: a failed install passed" >&2; exit 1; fi
jq -s -e '. == [{from: 0, events: [], platforms: [], installFailed: "0.1.0-beta.28"}]' "$tmp/posted.jsonl" >/dev/null ||
jq -s -e 'length == 1 and (.[0] | .from == 0 and .platforms == [] and .installFailed == "0.1.0-beta.28"
and (.events | length == 1 and .[0].event.Build.Step.error == "Could not install ployz 0.1.0-beta.28."))' "$tmp/posted.jsonl" >/dev/null ||
{ echo "FAIL: a failed install did not report" >&2; cat "$tmp/posted.jsonl" >&2; exit 1; }
grep -qxF "::error::Could not install ployz 0.1.0-beta.28." <<<"$log" || { echo "FAIL: a failed install did not say why" >&2; echo "$log" >&2; exit 1; }

Expand Down
Loading