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
29 changes: 29 additions & 0 deletions .github/workflows/ffi-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ jobs:
build:
name: ${{ matrix.target }}
runs-on: ${{ matrix.runner }}
# Needed by the tag-only "Publish cdylib to the release" step below, which
# attaches the library to the GitHub Release cargo-dist creates for the tag.
permissions:
contents: write
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -75,3 +79,28 @@ jobs:
path: |
target/${{ matrix.target }}/release/${{ matrix.artifact }}
secretspec-ffi/include/secretspec.h

# On a version tag, attach the cdylib (named for its target, with a sha256
# sidecar) to the GitHub Release so the PHP SDK's `secretspec-install-lib`
# command can fetch the right one for a plain `composer require` install.
# cargo-dist's release.yml creates the release for this same tag, so wait
# for it to exist, then upload with --clobber (both workflows may retry).
- name: Publish cdylib to the release
if: startsWith(github.ref, 'refs/tags/v')
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
ext="${{ matrix.artifact }}"; ext="${ext##*.}"
asset="secretspec-ffi-${{ matrix.target }}.${ext}"
cp "target/${{ matrix.target }}/release/${{ matrix.artifact }}" "$asset"
# sha256 sidecar (BSD shasum on macOS, GNU sha256sum on Linux; both here).
if command -v sha256sum >/dev/null; then sha256sum "$asset" > "$asset.sha256"
else shasum -a 256 "$asset" > "$asset.sha256"; fi
# Wait for cargo-dist to create the release (concurrent workflow).
for _ in $(seq 1 30); do
gh release view "$tag" >/dev/null 2>&1 && break || sleep 20
done
gh release upload "$tag" "$asset" "$asset.sha256" --clobber
122 changes: 122 additions & 0 deletions .github/workflows/php-ext.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: "PHP extension"

# Builds the secretspec-php-native PHP extension (ext-php-rs) as a prebuilt
# shared object for each supported PHP minor x platform, smoke tests that it
# loads and registers its functions, and on a version tag attaches the binaries
# to the GitHub Release.
#
# DISTRIBUTION STATUS (see RELEASE.md): this builds and publishes prebuilt
# extension binaries. Installing them is documented in the PHP SDK docs
# (download + `extension=`, or `docker-php-ext-enable`, or build from source with
# cargo). A one-command PIE install is a follow-up: PIE builds non-Windows
# extensions from source via phpize, which does not apply to a Cargo/ext-php-rs
# extension, so the prebuilt-binary path here is what is validated.
#
# The SDK itself is exercised on every PR by the devenv-based sdks.yml (both the
# extension and the ext-ffi fallback); this workflow only builds the
# distributable extension binaries.

on:
workflow_dispatch:
push:
tags:
- v**
pull_request:
paths:
- "secretspec-php/**"
- ".github/workflows/php-ext.yml"

jobs:
build:
name: php-${{ matrix.php }}-${{ matrix.target }}
runs-on: ${{ matrix.runner }}
permissions:
contents: write # attach binaries to the release (tag runs only)
strategy:
fail-fast: false
matrix:
# Full php x target cross-product: the `include` entries share the
# `target` key with the axis, so they merge in the runner (rather than
# creating standalone combinations). Non-thread-safe (NTS) is the default
# CLI/FPM build. 8.1 is omitted (end of life). Windows and ZTS builds are
# a follow-up (ext-php-rs on Windows needs the PHP SDK dev pack + rust-lld;
# Windows users can use the ext-ffi backend meanwhile).
php: ["8.2", "8.3", "8.4"]
target:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- aarch64-apple-darwin
include:
- { target: x86_64-unknown-linux-gnu, runner: ubuntu-latest }
- { target: aarch64-unknown-linux-gnu, runner: ubuntu-24.04-arm }
- { target: aarch64-apple-darwin, runner: macos-latest }

steps:
- uses: actions/checkout@v5

- name: Set up PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
# php-config + headers, needed by ext-php-rs's build.
tools: none
env:
# Ensure the dev headers are available for the build.
phpts: nts

- name: Install Linux build dependencies (clang for bindgen, dbus for keyring)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y llvm-dev libclang-dev clang libdbus-1-dev pkg-config

- name: Install Rust (pinned by rust-toolchain.toml)
run: rustup toolchain install

- name: Build the extension
# Each runner is the target's native arch, so a plain release build emits
# the target's binary (no cross-compilation).
run: cargo build --release -p secretspec-php-native

- name: Stage the extension under its distribution name
id: stage
shell: bash
run: |
set -euo pipefail
case "$(uname -s)" in
Darwin) built="libsecretspec_php_native.dylib" ;;
*) built="libsecretspec_php_native.so" ;;
esac
# dlopen resolves by path, not suffix, so the macOS .dylib ships as .so.
asset="secretspec-php-native-${{ matrix.php }}-nts-${{ matrix.target }}.so"
cp "target/release/$built" "$asset"
echo "asset=$asset" >> "$GITHUB_OUTPUT"

- name: Smoke test (load the extension, check it registers)
# Every row builds natively, so the runner can load what it built.
shell: bash
run: |
php -d extension="$PWD/${{ steps.stage.outputs.asset }}" -r '
assert(function_exists("secretspec_native_resolve"));
assert(function_exists("secretspec_native_abi_version"));
echo secretspec_native_abi_version(), PHP_EOL;
'

- uses: actions/upload-artifact@v4
with:
name: php-ext-${{ matrix.php }}-${{ matrix.target }}
path: ${{ steps.stage.outputs.asset }}

- name: Publish extension to the release
if: startsWith(github.ref, 'refs/tags/v')
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
asset="${{ steps.stage.outputs.asset }}"
if command -v sha256sum >/dev/null; then sha256sum "$asset" > "$asset.sha256"
else shasum -a 256 "$asset" > "$asset.sha256"; fi
# cargo-dist's release.yml creates the release for this tag; wait for it.
for _ in $(seq 1 30); do
gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1 && break || sleep 20
done
gh release upload "${GITHUB_REF_NAME}" "$asset" "$asset.sha256" --clobber
2 changes: 1 addition & 1 deletion .github/workflows/sdks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: "SDKs"

# Runs every language SDK's full test suite (unit + cross-language conformance +
# the schema/quicktype codegen pipeline) against a freshly built cdylib, so the
# Python/Go/Ruby/Node/Haskell bindings cannot silently rot.
# Python/Go/Ruby/Node/Haskell/PHP bindings cannot silently rot.

on:
pull_request:
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ jobs:
- name: Install Rust
run: rustup toolchain install stable --profile minimal
- name: cargo test
run: cargo test --all
# Exclude secretspec-php-native: it is an ext-php-rs extension that needs a
# PHP dev toolchain (php-config/headers) this bare runner does not have, and
# ext-php-rs rejects the runner's PHP version anyway. The PHP SDK is built
# and tested by sdks.yml / php-ext.yml instead.
run: cargo test --workspace --exclude secretspec-php-native
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
target

.DS_Store

# PHP (Composer) — manifest at repo root, vendor-dir points into secretspec-php/
/composer.lock
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- PHP SDK (`cachix/secretspec`): resolve secrets from PHP, Laravel, and Symfony
over the same shared resolver as the other language SDKs. It ships as a native
PHP extension that embeds the resolver (works under PHP-FPM with no
`ffi.enable`, like `ext-redis`), with an `ext-ffi` fallback that dlopens the
library at runtime for CLI and local development.

### Changed
- A `ref` routed at a single store (an explicit `--provider`, a single-provider
chain, or the default provider) is now checked up front, before any store is
Expand Down
Loading
Loading