Skip to content
Closed
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
67 changes: 62 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,57 @@ jobs:
# follow at lint time; not a real finding.
shellcheck --shell=bash --exclude=SC1091 "${scripts[@]}"

commit-signature-verification:
runs-on: ubuntu-latest
steps:
- name: Signed postil-cli commit verifies
env:
CLI_REF: e448377c918c1d6fb91f9347d8be5153a4518480
run: |
set -euo pipefail
export GNUPGHOME="$RUNNER_TEMP/postil-gnupg"
install -m 700 -d "$GNUPGHOME"
curl -fsSL --retry 3 --retry-connrefused --retry-delay 2 https://github.com/web-flow.gpg | gpg --batch --import

verify_repo="$RUNNER_TEMP/postil-cli-signature"
rm -rf "$verify_repo"
git init -q "$verify_repo"
git -C "$verify_repo" fetch --quiet --depth=1 https://github.com/postil-dev/postil-cli "$CLI_REF"
git -C "$verify_repo" verify-commit "$CLI_REF"

- name: Unsigned commit fails with clear error
run: |
set -euo pipefail
unsigned_repo="$RUNNER_TEMP/unsigned-source"
git init -q "$unsigned_repo"
git -C "$unsigned_repo" config user.name "Unsigned Commit"
git -C "$unsigned_repo" config user.email "unsigned@example.invalid"
git -C "$unsigned_repo" -c commit.gpgsign=false commit --quiet --allow-empty -m "unsigned fixture"
CLI_REF="$(git -C "$unsigned_repo" rev-parse HEAD)"

verify_repo="$RUNNER_TEMP/unsigned-signature"
rm -rf "$verify_repo"
git init -q "$verify_repo"
git -C "$verify_repo" fetch --quiet --depth=1 "$unsigned_repo" "$CLI_REF"

log="$RUNNER_TEMP/unsigned-verify.log"
set +e
(
if ! git -C "$verify_repo" verify-commit "$CLI_REF"; then
echo "::error::postil-cli commit $CLI_REF is not signed by a trusted key, or git cannot access the signer's public key. Import the signer's public key before using source builds."
exit 42
fi
) >"$log" 2>&1
status=$?
set -e

if [ "$status" -ne 42 ]; then
cat "$log"
echo "::error::unsigned commit verification exited with status $status, expected 42"
exit 1
fi
grep -F "is not signed by a trusted key, or git cannot access the signer's public key" "$log"

# The action has three composite steps: "Validate inputs", "Install
# postil" (fetch + cosign-verify the pinned CLI, or build from source),
# and "Review" (the actual LLM call). They are not separable via `uses:`
Expand All @@ -140,24 +191,30 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
target:
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3
- name: Fetch, cosign-verify, and run the pinned CLI release
env:
CLI_REF: 87f4bf08b63712d3600030a7c458f0b790cfc0d5 # postil-cli v0.1.1
CLI_RELEASE: v0.1.1
TARGET: ${{ matrix.target }}
run: |
set -euo pipefail
DEST="$RUNNER_TEMP/postil-bin"
mkdir -p "$DEST"
target="x86_64-unknown-linux-gnu"
base="https://github.com/postil-dev/postil-cli/releases/download/$CLI_RELEASE"

curl -fsSL -o "$DEST/postil.tar.gz" "$base/postil-$target.tar.gz"
curl -fsSL -o "$DEST/postil.tar.gz.sha256" "$base/postil-$target.tar.gz.sha256"
curl -fsSL -o "$DEST/postil.tar.gz.sig" "$base/postil-$target.tar.gz.sig"
curl -fsSL -o "$DEST/postil.tar.gz.pem" "$base/postil-$target.tar.gz.pem"
curl -fsSL --retry 3 --retry-connrefused --retry-delay 2 -o "$DEST/postil.tar.gz" "$base/postil-$TARGET.tar.gz"
curl -fsSL --retry 3 --retry-connrefused --retry-delay 2 -o "$DEST/postil.tar.gz.sha256" "$base/postil-$TARGET.tar.gz.sha256"
curl -fsSL --retry 3 --retry-connrefused --retry-delay 2 -o "$DEST/postil.tar.gz.sig" "$base/postil-$TARGET.tar.gz.sig"
curl -fsSL --retry 3 --retry-connrefused --retry-delay 2 -o "$DEST/postil.tar.gz.pem" "$base/postil-$TARGET.tar.gz.pem"

expected=$(awk '{print $1}' "$DEST/postil.tar.gz.sha256")
actual=$(sha256sum "$DEST/postil.tar.gz" | awk '{print $1}')
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ gate without failing this job, set `soft-fail: true` and mark the `postil/gate`
required in branch protection instead — that is the recommended setup: advisory comments
never block, the gate check does.

## Platform support

Linux runners use prebuilt CLI release artifacts when `cli-release` is set and
the release tag points at the pinned `cli-ref`. The action selects the target
from the runner CPU and libc:

| Runner | Selected target |
|---|---|
| x86_64 glibc Linux | `x86_64-unknown-linux-gnu` |
| aarch64 glibc Linux | `aarch64-unknown-linux-gnu` |
| x86_64 Alpine/musl Linux | `x86_64-unknown-linux-musl` |
| aarch64 Alpine/musl Linux | `aarch64-unknown-linux-musl` |

If a matching prebuilt artifact is not present on the pinned CLI release, the
action falls back to building `postil` from `cli-ref`.

## Inputs

| Input | Required | Description |
Expand Down
58 changes: 49 additions & 9 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,46 @@ runs:
if: inputs.cli-release != ''
uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3

- name: Select postil target
id: target
shell: bash
run: |
set -euo pipefail

target=""
if [ "$RUNNER_OS" = "Linux" ]; then
libc="gnu"
if command -v ldd >/dev/null 2>&1; then
ldd_output="$(ldd --version 2>&1 || true)"
if printf '%s\n' "$ldd_output" | grep -qi musl; then
libc="musl"
fi
elif [ "$libc" != "musl" ] \
&& { compgen -G "/lib/ld-musl-*.so.1" >/dev/null \
|| compgen -G "/usr/lib/ld-musl-*.so.1" >/dev/null; }; then
libc="musl"
fi

case "$(uname -m)" in
x86_64) target="x86_64-unknown-linux-$libc" ;;
aarch64|arm64) target="aarch64-unknown-linux-$libc" ;;
esac
fi

if [ -n "$target" ]; then
echo "Selected postil target $target"
else
echo "::notice::no prebuilt target for $RUNNER_OS/$(uname -m); falling back to source build"
fi
echo "target=$target" >> "$GITHUB_OUTPUT"

- name: Install postil
shell: bash
env:
CLI_REF: ${{ inputs.cli-ref }}
CLI_RELEASE: ${{ inputs.cli-release }}
GH_TOKEN: ${{ inputs.github-token }}
POSTIL_TARGET: ${{ steps.target.outputs.target }}
run: |
set -euo pipefail
DEST="$RUNNER_TEMP/postil-bin"
Expand All @@ -133,13 +167,7 @@ runs:
if [ "$tag_sha" = "$CLI_REF" ]; then
# Prebuilt artifacts are Linux-only here; other runners fall back
# to the source build rather than fetching a binary that cannot run.
target=""
if [ "$RUNNER_OS" = "Linux" ]; then
case "$(uname -m)" in
x86_64) target="x86_64-unknown-linux-gnu" ;;
aarch64|arm64) target="aarch64-unknown-linux-gnu" ;;
esac
fi
target="$POSTIL_TARGET"
if [ -n "$target" ]; then
base="https://github.com/postil-dev/postil-cli/releases/download/$CLI_RELEASE"
if curl -fsSL --retry 3 --retry-connrefused --retry-delay 2 -o "$DEST/postil.tar.gz" "$base/postil-$target.tar.gz" \
Expand Down Expand Up @@ -168,8 +196,6 @@ runs:
else
echo "::warning::no prebuilt artifact (or signature) for $target on $CLI_RELEASE; falling back to source build"
fi
else
echo "::notice::no prebuilt target for $RUNNER_OS/$(uname -m); falling back to source build"
fi
else
echo "::warning::release $CLI_RELEASE points at ${tag_sha:-unknown}, not cli-ref $CLI_REF; falling back to source build"
Expand All @@ -178,6 +204,20 @@ runs:

if [ "$prebuilt_ok" = false ]; then
echo "Building postil from postil-dev/postil-cli@$CLI_REF"
verify_repo="$RUNNER_TEMP/postil-cli-signature"
rm -rf "$verify_repo"
git init -q "$verify_repo"
if ! git -C "$verify_repo" fetch --quiet --depth=1 https://github.com/postil-dev/postil-cli "$CLI_REF"; then
echo "::error::failed to fetch postil-cli commit $CLI_REF for signature verification"
exit 1
fi
# Source builds use Git's built-in GPG verification. The runner's
# git/GPG config must be able to resolve the signer's public key,
# for example from a keyserver or repository .git/config.
if ! git -C "$verify_repo" verify-commit "$CLI_REF"; then
echo "::error::postil-cli commit $CLI_REF is not signed by a trusted key, or git cannot access the signer's public key. Import the signer's public key before using source builds."
exit 1
fi
if ! command -v cargo >/dev/null 2>&1; then
curl -fsSL --retry 3 --retry-connrefused --retry-delay 2 https://sh.rustup.rs | sh -s -- -y --profile minimal
. "$HOME/.cargo/env"
Expand Down
Loading