This action publishes a WordPress plugin release artifact to FAIR.
It handles:
- Artifact signing
- FAIR metadata generation
- Metadata upload to GitHub release
FAIR Pulse uses two key pairs:
- Rotation keys (secp256k1) — control the DID identity. Used for DID creation and service endpoint updates.
- Verification keys (Ed25519) — sign release artifacts. Used during every publish.
The recommended setup creates the DID and sets its service endpoint locally (one-time), then CI only needs verification keys. Rotation keys never leave your machine.
The DID service endpoint is set to https://github.com/<owner>/<repo>/releases/latest/download/fair-metadata.json which GitHub automatically redirects to the most recent release. No DID updates are needed when publishing new releases.
You need:
- A GitHub repository with your plugin code
- Permission to add repository secrets and variables
- Local PHP + Composer
- Git installed locally
mkdir -p ~/fair-tools
cd ~/fair-tools
git clone https://github.com/fairpm/fair-pulse.git
cd fair-pulsecomposer installcomposer fair:setup-local -- https://github.com/your-name/your-pluginThis single command:
- Generates rotation and verification key pairs on your machine
- Creates a DID on the PLC directory
- Sets the DID service endpoint to the static latest-release URL
- Prints instructions for what to add to GitHub
From the setup output, add these to your plugin repository:
Secrets (Settings → Secrets and variables → Actions → Secrets tab):
FAIR_VERIFICATION_KEY_PRIVATEFAIR_VERIFICATION_KEY_PUBLIC
Variable (Settings → Secrets and variables → Actions → Variables tab):
FAIR_DID
The setup command also prints rotation keys. Do NOT add them to GitHub.
Store them in a password manager or encrypted backup. You only need them if you ever change the DID document (which is rare).
Create .github/workflows/publish-fair.yml:
name: Publish FAIR Metadata
on:
push:
tags: ["v*"]
workflow_dispatch:
inputs:
version:
description: Version tag (for example v1.2.3)
required: false
type: string
permissions:
contents: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Publish to FAIR
uses: fairpm/fair-pulse@v1
with:
version: ${{ inputs.version }}
artifact-name: my-plugin.zip
upload-metadata: 'true'
env:
FAIR_VERIFICATION_KEY_PRIVATE: ${{ secrets.FAIR_VERIFICATION_KEY_PRIVATE }}
FAIR_VERIFICATION_KEY_PUBLIC: ${{ secrets.FAIR_VERIFICATION_KEY_PUBLIC }}
FAIR_DID: ${{ vars.FAIR_DID }}Tag and push a release, or trigger the workflow manually from the Actions tab.
FAIR Pulse handles building the artifact, creating the release, signing, metadata generation, and uploading — all automatically.
| Input | Required | Default | Description |
|---|---|---|---|
| version | No | empty | Version/tag to publish. If empty, resolves from tag ref or latest git tag. |
| artifact-name | No | empty | Release asset filename to download and sign. Must end in .zip. |
| upload-metadata | No | true | Upload generated fair-metadata.json to release. |
| Output | Description |
|---|---|
| version | Published release version |
| did | DID used during publish |
| artifact-path | Local path of downloaded artifact |
| metadata-path | Local path of generated FAIR metadata |
fair:setup-local sets the service endpoint once during initial setup. Because the endpoint uses GitHub's /releases/latest/download/ URL, it never needs updating when you publish new releases.
If you ever need to point the endpoint to a different URL (for example, after migrating repositories), run this locally using your rotation private key:
composer fair:update-did-serviceRunning it without arguments will prompt for each required value interactively:
Your DID (e.g. did:plc:abc123): did:plc:yourdid
Rotation private key: <paste key>
Metadata URL: https://github.com/your-name/your-plugin/releases/latest/download/fair-metadata.json
Previous operation CID (optional, press Enter to skip):
Alternatively, pass values as environment variables to skip prompting:
DID=did:plc:yourdid \
ROTATION_PRIVATE=your_rotation_private_key \
METADATA_URL=https://github.com/your-name/your-plugin/releases/latest/download/fair-metadata.json \
composer fair:update-did-servicePREV_CID is optional. If you have the CID from the last DID operation, pass it to ensure consistency; otherwise it is fetched automatically from the PLC directory.
- Full workflow example:
examples/example.yml - Example guide:
examples/README.md
Build Docker image:
docker build -t fair-pulse-local .Run local setup in Docker:
docker run --rm -it fair-pulse-local composer fair:setup-local -- https://github.com/owner/repoRun full publish flow in Docker:
docker run --rm -it \
-e GITHUB_REPOSITORY=owner/repo \
-e GITHUB_SERVER_URL=https://github.com \
-e GITHUB_TOKEN=ghp_xxx \
-e INPUT_VERSION=v1.2.3 \
-e INPUT_ARTIFACT_NAME=my-plugin.zip \
-e FAIR_VERIFICATION_KEY_PRIVATE=... \
-e FAIR_VERIFICATION_KEY_PUBLIC=... \
-e FAIR_DID=did:plc:yourDid \
fair-pulse-local-
Missing verification keys: Set
FAIR_VERIFICATION_KEY_PRIVATEandFAIR_VERIFICATION_KEY_PUBLICas repository secrets. -
Missing DID and no rotation keys: Run
composer fair:setup-local -- https://github.com/<owner>/<repo>locally first. -
Artifact not found: Ensure
artifact-namematches the exact release asset filename (or omit it to auto-detect). -
Permission issues: Workflow needs
contents: writepermission to upload metadata.
vendor/bin/phpunit
composer validate --no-check-publishSee CHANGELOG.md.