Skip to content

Commit 373c0e9

Browse files
committed
faeat: add ffi pre-built .a library
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
1 parent ff8c5bd commit 373c0e9

8 files changed

Lines changed: 851 additions & 0 deletions

File tree

.github/workflows/release-ffi.yaml

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# ===============================================================
2+
# Release FFI - Build, sign, and publish libcpex_ffi.a artifacts
3+
# ===============================================================
4+
#
5+
# Triggered by semver-strict tag pushes. Matrix-builds the FFI
6+
# static library for the supported target tuples, packages each into
7+
# a tarball with VERSION / FFI_ABI / LICENSE metadata, signs every
8+
# tarball + the aggregate SHA256SUMS with cosign keyless (Sigstore),
9+
# and attaches everything to the GitHub Release for the tag.
10+
#
11+
# See crates/cpex-ffi/RELEASE.md for the artifact schema and the
12+
# consumer-side verify-and-unpack recipe.
13+
14+
name: Release FFI
15+
16+
on:
17+
push:
18+
tags:
19+
# Semver-strict. Two patterns so vMAJOR.MINOR.PATCH (release)
20+
# and vMAJOR.MINOR.PATCH-<prerelease> (rc / beta / ffi.test)
21+
# both fire, while loose `v*` matches (vendor-bump, v1, v-foo)
22+
# and the legacy non-prefixed tags (0.1.0, plugins.dev1) do not.
23+
# Dry-run tags like v0.0.0-ffi.test.1 deliberately hit the
24+
# prerelease branch.
25+
- 'v[0-9]+.[0-9]+.[0-9]+'
26+
- 'v[0-9]+.[0-9]+.[0-9]+-*'
27+
28+
# id-token: write is what unlocks Sigstore keyless signing (Fulcio
29+
# reads the GHA OIDC token to issue the short-lived signing cert).
30+
# contents: write is needed to create / upload to the GitHub Release.
31+
permissions:
32+
contents: write
33+
id-token: write
34+
35+
# Prevent concurrent runs on the same tag from racing the release
36+
# creation. Tag pushes are one-shot, so this is belt-and-suspenders.
37+
concurrency:
38+
group: release-ffi-${{ github.ref }}
39+
cancel-in-progress: false
40+
41+
jobs:
42+
build:
43+
name: Build ${{ matrix.target }}
44+
runs-on: ${{ matrix.runner }}
45+
strategy:
46+
fail-fast: false # one tuple failing should not cancel the others
47+
matrix:
48+
include:
49+
- target: x86_64-unknown-linux-gnu
50+
runner: ubuntu-latest
51+
- target: aarch64-unknown-linux-gnu
52+
runner: ubuntu-22.04-arm
53+
- target: x86_64-unknown-linux-musl
54+
runner: ubuntu-latest
55+
- target: aarch64-unknown-linux-musl
56+
runner: ubuntu-22.04-arm
57+
- target: aarch64-apple-darwin
58+
runner: macos-14
59+
60+
steps:
61+
- name: Checkout
62+
uses: actions/checkout@v4
63+
64+
- name: Install Rust toolchain
65+
# dtolnay/rust-toolchain is the de-facto rustup action.
66+
# `stable` picks the latest stable; pin if we need a floor.
67+
uses: dtolnay/rust-toolchain@stable
68+
with:
69+
targets: ${{ matrix.target }}
70+
71+
- name: Cache cargo build
72+
uses: Swatinem/rust-cache@v2
73+
with:
74+
# Share cache across tags (the key includes the target +
75+
# Cargo.lock hash by default). Significant speedup on
76+
# subsequent releases of the same target.
77+
key: ${{ matrix.target }}
78+
79+
- name: Build artifact
80+
env:
81+
TARGET: ${{ matrix.target }}
82+
# VERSION drops the leading "refs/tags/" so the tarball
83+
# name matches the tag verbatim.
84+
VERSION: ${{ github.ref_name }}
85+
DIST_DIR: dist
86+
run: bash scripts/release/build-artifact.sh
87+
88+
- name: Upload tarball + sha256
89+
uses: actions/upload-artifact@v4
90+
with:
91+
# Unique per-target name so the download step in
92+
# sign-and-release can merge them all into one dist/.
93+
name: cpex-ffi-${{ github.ref_name }}-${{ matrix.target }}
94+
path: dist/cpex-ffi-*
95+
if-no-files-found: error
96+
retention-days: 7
97+
98+
sign-and-release:
99+
name: Sign and publish release
100+
needs: [build]
101+
runs-on: ubuntu-latest
102+
steps:
103+
- name: Checkout
104+
uses: actions/checkout@v4
105+
106+
- name: Download all matrix artifacts
107+
uses: actions/download-artifact@v4
108+
with:
109+
path: dist
110+
# merge-multiple flattens the per-target subdirs into one
111+
# dist/ so the sign script and gh release upload see a
112+
# flat layout.
113+
merge-multiple: true
114+
115+
- name: Generate aggregate SHA256SUMS
116+
env:
117+
VERSION: ${{ github.ref_name }}
118+
run: |
119+
set -euo pipefail
120+
cd dist
121+
# Concat all individual .sha256 files into one signed
122+
# integrity manifest. The per-tarball .sha256 files stay
123+
# as convenience companions, but the SHA256SUMS file is
124+
# what auditors care about.
125+
: > "cpex-ffi-${VERSION}-SHA256SUMS"
126+
for f in cpex-ffi-*.tar.gz; do
127+
if command -v sha256sum >/dev/null; then
128+
sha256sum "$f" >> "cpex-ffi-${VERSION}-SHA256SUMS"
129+
else
130+
shasum -a 256 "$f" >> "cpex-ffi-${VERSION}-SHA256SUMS"
131+
fi
132+
done
133+
echo "--- SHA256SUMS ---"
134+
cat "cpex-ffi-${VERSION}-SHA256SUMS"
135+
136+
- name: Install cosign
137+
uses: sigstore/cosign-installer@v3
138+
139+
- name: Sign artifacts
140+
env:
141+
DIST_DIR: dist
142+
run: bash scripts/release/sign-artifact.sh
143+
144+
- name: Create or update GitHub Release
145+
env:
146+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
147+
TAG: ${{ github.ref_name }}
148+
run: |
149+
set -euo pipefail
150+
151+
# Auto-detect prerelease by suffix so dry-run tags
152+
# (v0.0.0-ffi.test.1) land as prereleases and don't surface
153+
# as "latest" on the repo's Releases page.
154+
PRERELEASE_FLAG=""
155+
if [[ "$TAG" == *-* ]]; then
156+
PRERELEASE_FLAG="--prerelease"
157+
fi
158+
159+
# Idempotent: if the release exists, upload --clobber the
160+
# new files; if it doesn't, create it with the tarballs +
161+
# SHA256SUMS + sigs in one shot.
162+
if gh release view "$TAG" >/dev/null 2>&1; then
163+
echo "Release $TAG exists; uploading artifacts with --clobber"
164+
gh release upload "$TAG" dist/cpex-ffi-* --clobber
165+
else
166+
echo "Creating release $TAG"
167+
gh release create "$TAG" \
168+
--title "$TAG" \
169+
--notes "Automated FFI artifact release. See crates/cpex-ffi/RELEASE.md for the schema and verify-and-consume recipe." \
170+
$PRERELEASE_FLAG \
171+
dist/cpex-ffi-*
172+
fi

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
1515
1616
## [Unreleased]
1717

18+
### Added
19+
20+
- Publish `libcpex_ffi.a` as signed GitHub Release artifacts on
21+
every semver tag push (`linux-amd64-gnu`, `linux-arm64-gnu`,
22+
`linux-amd64-musl`, `linux-arm64-musl`, `darwin-arm64`). Cosign
23+
keyless signatures + SHA256 checksums; see
24+
`crates/cpex-ffi/RELEASE.md` for the schema and the verify-and-
25+
consume recipe.
26+
- FFI ABI versioning: `cpex_ffi_abi_version()` extern C accessor
27+
exposes `FFI_ABI_VERSION` (currently `1`). The Go binding checks
28+
this in `init()` and panics on mismatch. Other language bindings
29+
must replicate the check.
30+
1831
## [0.1.0] - 2026-05-05
1932

2033
### Added

0 commit comments

Comments
 (0)