Broadcast
•2 min read
GitHub Action — Tier 1 release broadcasting
The Action source lives in the private monorepo at packages/broadcast-action. The bundled artifact is mirrored to the public sizls/broadcast-action repository on every release, signed via Sigstore keyless OIDC tied to the release workflow identity. Consumers reference the public repo by SHA.
Quickstart
# .github/workflows/release-broadcast.yml
on:
release:
types: [published]
jobs:
broadcast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: sizls/broadcast-action@<sha>
with:
platforms: bluesky,mastodon
config-path: .sizl/broadcast.config.ts
env:
BLUESKY_APP_PASSWORD: ${{ secrets.BLUESKY_APP_PASSWORD }}
MASTODON_TOKEN: ${{ secrets.MASTODON_TOKEN }}
Pin the action by SHA (not tag) so the published binary you verified yesterday is the binary that runs tomorrow.
Tier policy
The Action is Tier 1 only. A GitHub Actions runner is ephemeral — it can dispatch a one-shot post and exit, but it cannot host the 15-minute Tier 2 approval window. If your config declares a Tier 2/3 event, the Action refuses with a structured error and a doc link to the Worker template.
::error::Event "release/feature-flag-rollout" is configured for Tier 2 approval,
but the Action runs ephemeral runners that cannot host a 15-minute approval
window. Use the Cloudflare Worker template instead:
https://directive.run/docs/broadcast/worker
The refusal is enforced at the contract layer, not via runtime check. The Action's tier resolver inspects the resolved tier before any platform call.
Sigstore verification
Every release of sizls/broadcast-action is signed with Sigstore keyless OIDC. Verify before pinning:
cosign verify-blob \
--certificate-identity-regexp '^https://github.com/sizls/broadcast/\.github/workflows/release-action\.yml@refs/tags/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--bundle dist/bundle.sigstore.json \
dist/index.js
The signing identity is the release workflow, not a long-lived key — there is no key to lose. If an attacker pushed an unsigned binary to the public mirror, cosign verify-blob would fail against the workflow-ref identity regex.
Inputs
| Input | Required | Description |
|---|---|---|
platforms | yes | Comma-separated allowlist for this run. The Action rejects events whose config emits adapters outside this list. |
config-path | yes | Path to your broadcast.config.ts in the repo. |
dry-run | no | When true, the Action skips the platform call and prints what would have posted. Receipt still signed and emitted. |
Outputs
| Output | Description |
|---|---|
cassette-hashes | JSON array of cassette hashes for each dispatched post. Use it as the input to a downstream verify step. |
What stays private
The Action source — and the @sizl/broadcast runtime it depends on — live in the private monorepo. The bundled JavaScript binary is what consumers run. This is the deliberate posture: the moat is the brand + Pluck Bureau key issuance + the posts-index hosting, not the binary's opacity.

