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
268 changes: 267 additions & 1 deletion .github/workflows/agentplugins-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,43 @@ on:
description: Exact stable tag, for example agentplugins-v0.1.0
required: true
producer_mode:
description: Bounded release contract; publishes verified GitHub binary assets only
description: Binary-only publication, read-only paired preparation, or explicit promotion
required: true
default: binary-only
type: choice
options:
- binary-only
- paired-preparation
- paired-promotion
source_sha:
description: Exact source and workflow SHA (required for paired preparation)
required: false
plugin_kit_version:
description: Explicit plugin-kit version (paired first cut requires 2.0.0)
required: false
preparation_run:
description: Exact completed preparation run ID (promotion only)
required: false
preparation_attempt:
description: Exact preparation run attempt (promotion only)
required: false
preparation_artifact:
description: Exact preparation artifact ID (promotion only)
required: false
preparation_digest:
description: Independently selected preparation ZIP SHA256 (promotion only)
required: false
promotion_operation:
description: Promote exact drafts or reconcile interrupted drafts/partial publication
required: true
default: promote
type: choice
options:
- promote
- reconcile
promotion_record:
description: Fixed canonical promotion record bindings; unsupported native contracts reject
required: false

permissions:
contents: read
Expand All @@ -23,6 +54,7 @@ concurrency:

jobs:
validate:
if: ${{ inputs.producer_mode == 'binary-only' }}
runs-on: ubuntu-latest
env:
GOWORK: "off"
Expand Down Expand Up @@ -144,6 +176,7 @@ jobs:
run: npm test && npm pack --dry-run --ignore-scripts

build:
if: ${{ inputs.producer_mode == 'binary-only' }}
needs: validate
runs-on: ubuntu-latest
env:
Expand Down Expand Up @@ -200,6 +233,7 @@ jobs:
retention-days: 3

stage-draft:
if: ${{ inputs.producer_mode == 'binary-only' }}
needs: [validate, build]
runs-on: ubuntu-latest
environment: agentplugins-release
Expand Down Expand Up @@ -308,6 +342,7 @@ jobs:
retention-days: 7

platform-proof:
if: ${{ inputs.producer_mode == 'binary-only' }}
needs: [validate, stage-draft]
uses: ./.github/workflows/agentplugins-platform-proof.yml
permissions:
Expand All @@ -322,6 +357,7 @@ jobs:
release_assets_artifact: ${{ needs.stage-draft.outputs.assets_artifact }}

promote-release:
if: ${{ inputs.producer_mode == 'binary-only' }}
needs: [validate, stage-draft, platform-proof]
runs-on: ubuntu-latest
environment: agentplugins-release
Expand Down Expand Up @@ -378,3 +414,233 @@ jobs:
gh release edit "${TAG}" --repo "${GITHUB_REPOSITORY}" --draft=false
gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" \
--jq 'select(.draft == false and .prerelease == false) | .tag_name' | grep -Fx -- "${TAG}"

paired-preparation:
if: ${{ inputs.producer_mode == 'paired-preparation' }}
runs-on: ubuntu-latest
permissions:
contents: read
env:
SOURCE_SHA: ${{ inputs.source_sha }}
WORKFLOW_SHA: ${{ github.sha }}
TAG: ${{ inputs.tag }}
KIT_VERSION: ${{ inputs.plugin_kit_version }}
GOTOOLCHAIN: local
GOMAXPROCS: "2"
steps:
- name: Validate explicit paired identity before checkout
shell: bash
run: |
set -euo pipefail
[[ "${SOURCE_SHA}" =~ ^[0-9a-f]{40}$ && ! "${SOURCE_SHA}" =~ ^0{40}$ ]]
test "${SOURCE_SHA}" = "${WORKFLOW_SHA}"
[[ "${TAG}" =~ ^agentplugins-v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]
test "${KIT_VERSION}" = "2.0.0"
test "${TAG#agentplugins-v}" != "${KIT_VERSION}"
test "${GITHUB_REPOSITORY}" = "777genius/universal-agent-plugins"
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ inputs.source_sha }}
- name: Check exact checkout
run: test "$(git rev-parse HEAD)" = "${SOURCE_SHA}"
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: 1.25.13
cache: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
package-manager-cache: false
- name: Provision declared Go modules for offline producer
env:
GOMODCACHE: ${{ runner.temp }}/paired-modules
GOCACHE: ${{ runner.temp }}/paired-cache
run: go mod download
- name: Freeze one full release-contract pair and project verified bytes
shell: bash
env:
GOMODCACHE: ${{ runner.temp }}/paired-modules
GOCACHE: ${{ runner.temp }}/paired-cache
run: |
set -euo pipefail
export TRUSTED_GO="$(command -v go)"
node <<'NODE'
const fs = require('node:fs');
const path = require('node:path');
const { stageCandidate } = require('./npm/agentplugins/scripts/stage-dual-authoring-candidate');
const { prepareAuthoringRelease, verifyAuthoringRelease } = require('./npm/agentplugins/scripts/release-assets');
const root = fs.mkdtempSync(path.join(process.env.RUNNER_TEMP, 'authoring-preparation-'));
const workParent = path.join(root, 'work');
fs.mkdirSync(workParent, { mode: 0o700 });
const identity = { repository: '777genius/universal-agent-plugins',
commit: process.env.SOURCE_SHA, engine_revision: process.env.SOURCE_SHA,
versions: { agentplugins: process.env.TAG.slice('agentplugins-v'.length), 'plugin-kit-ai': process.env.KIT_VERSION } };
const common = { candidate: true, identity, go: process.env.TRUSTED_GO, workParent,
assetScope: 'six-platform-pair', authoringMode: 'release-cli-contract-v1' };
// stageCandidate builds once and independently verifies before sealing.
const candidate = path.join(root, 'candidate');
const staged = stageCandidate({ ...common, repo: process.env.GITHUB_WORKSPACE,
modCache: process.env.GOMODCACHE, output: candidate });
fs.writeFileSync(path.join(root, 'candidate-identity.json'), JSON.stringify({ identity, ...staged }, null, 2) + '\n', { flag: 'wx' });
const options = { ...common, root: candidate, manifestDigest: staged.manifest_sha256,
outputs: { agentplugins: path.join(root, 'agentplugins'), 'plugin-kit-ai': path.join(root, 'plugin-kit-ai') },
pairMarker: path.join(root, 'pair-prepared.json') };
prepareAuthoringRelease(options);
verifyAuthoringRelease(options);
fs.appendFileSync(process.env.GITHUB_ENV, `PAIRED_OUTPUT=${root}\n`);
NODE
- name: Upload candidate identity and both prepared projections together
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0
with:
name: authoring-preparation-${{ inputs.source_sha }}
path: |
${{ env.PAIRED_OUTPUT }}/candidate-identity.json
${{ env.PAIRED_OUTPUT }}/candidate/candidate.json
${{ env.PAIRED_OUTPUT }}/pair-prepared.json
${{ env.PAIRED_OUTPUT }}/agentplugins/*
${{ env.PAIRED_OUTPUT }}/plugin-kit-ai/*
if-no-files-found: error
retention-days: 7

paired-promotion-admission:
if: ${{ github.event_name == 'workflow_dispatch' && inputs.producer_mode == 'paired-promotion' }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Validate promotion identity before checkout
env:
SOURCE_SHA: ${{ inputs.source_sha }}
WORKFLOW_SHA: ${{ github.sha }}
WORKFLOW_REF: ${{ github.ref }}
TAG: ${{ inputs.tag }}
KIT_VERSION: ${{ inputs.plugin_kit_version }}
shell: bash
run: |
set -euo pipefail
[[ "${SOURCE_SHA}" =~ ^[0-9a-f]{40}$ && ! "${SOURCE_SHA}" =~ ^0{40}$ ]]
test "${SOURCE_SHA}" = "${WORKFLOW_SHA}"
[[ "${TAG}" =~ ^agentplugins-v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]
test "${WORKFLOW_REF}" = "refs/tags/${TAG}"
test "${KIT_VERSION}" = "2.0.0"
test "${TAG#agentplugins-v}" != "${KIT_VERSION}"
test "${GITHUB_REPOSITORY}" = "777genius/universal-agent-plugins"
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ inputs.source_sha }}
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22.21.1
package-manager-cache: false
- name: Reject missing native terminal contracts before protected effects
env:
PROMOTION_RECORD: ${{ inputs.promotion_record }}
TAG: ${{ inputs.tag }}
WORKFLOW_REF: ${{ github.ref }}
KIT_VERSION: ${{ inputs.plugin_kit_version }}
WORKFLOW_SHA: ${{ github.sha }}
run: |
node <<'NODE'
const p = require('./npm/agentplugins/scripts/authoring-promotion');
const input = process.env.PROMOTION_RECORD || '{}';
if (Buffer.byteLength(input) > 1024 * 1024) throw Error('bounded promotion input required');
const selected = { tag: process.env.TAG, ref: process.env.WORKFLOW_REF, source: process.env.WORKFLOW_SHA,
versions: { agentplugins: process.env.TAG.slice('agentplugins-v'.length), 'plugin-kit-ai': process.env.KIT_VERSION } };
const record = p.validateSelection(Buffer.from(input), selected);
p.requireNativeContracts(record.qualification?.lanes || []);
NODE

paired-sign-and-promote:
if: ${{ github.event_name == 'workflow_dispatch' && inputs.producer_mode == 'paired-promotion' }}
needs: paired-promotion-admission
runs-on: ubuntu-latest
environment: agentplugins-release
permissions:
contents: write
actions: read
id-token: write
attestations: write
artifact-metadata: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ inputs.source_sha }}
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22.21.1
package-manager-cache: false
# Admission currently always rejects: real terminal producer integration is
# required before any artifact download, attestation or release mutation.
- name: Acquire exact frozen preparation after native admission
env:
GH_TOKEN: ${{ github.token }}
PROMOTION_RECORD: ${{ inputs.promotion_record }}
TAG: ${{ inputs.tag }}
WORKFLOW_REF: ${{ github.ref }}
KIT_VERSION: ${{ inputs.plugin_kit_version }}
WORKFLOW_SHA: ${{ github.sha }}
PREPARATION_RUN: ${{ inputs.preparation_run }}
PREPARATION_ATTEMPT: ${{ inputs.preparation_attempt }}
PREPARATION_ARTIFACT: ${{ inputs.preparation_artifact }}
PREPARATION_DIGEST: ${{ inputs.preparation_digest }}
SOURCE_SHA: ${{ inputs.source_sha }}
run: |
node <<'NODE'
const fs = require('node:fs');
const path = require('node:path');
const p = require('./npm/agentplugins/scripts/authoring-promotion');
const selected = { tag: process.env.TAG, ref: process.env.WORKFLOW_REF, source: process.env.WORKFLOW_SHA,
versions: { agentplugins: process.env.TAG.slice('agentplugins-v'.length), 'plugin-kit-ai': process.env.KIT_VERSION } };
const record = p.admitRecord(Buffer.from(process.env.PROMOTION_RECORD), selected);
if (record.identity.commit !== process.env.SOURCE_SHA) throw Error('exact promotion source required');
const scratch = fs.mkdtempSync(path.join(process.env.RUNNER_TEMP, 'paired-promotion-'));
const preparation = { run_id: Number(process.env.PREPARATION_RUN), run_attempt: Number(process.env.PREPARATION_ATTEMPT),
artifact_id: Number(process.env.PREPARATION_ARTIFACT), artifact_sha256: process.env.PREPARATION_DIGEST };
p.acquireArtifact(preparation, p.WORKFLOW, record.identity.commit, scratch);
const recordFile = path.join(scratch, 'authoring-promotion.json');
fs.writeFileSync(recordFile, p.encodeRecord(record), { flag: 'wx', mode: 0o400 });
fs.writeFileSync(path.join(scratch, 'options.json'), JSON.stringify({ record: recordFile,
root: path.join(scratch, 'frozen'), scratch: path.join(scratch, 'provider'), workflow_sha: process.env.SOURCE_SHA, preparation, selected }), { flag: 'wx' });
fs.mkdirSync(path.join(scratch, 'provider'), { mode: 0o700 });
fs.appendFileSync(process.env.GITHUB_ENV, `PROMOTION_ROOT=${scratch}\n`);
NODE
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
artifact-ids: ${{ inputs.preparation_artifact }}
run-id: ${{ inputs.preparation_run }}
github-token: ${{ github.token }}
repository: 777genius/universal-agent-plugins
merge-multiple: true
path: ${{ env.PROMOTION_ROOT }}/frozen
- name: Recheck admission and exact subject closure before signing
id: subjects
env:
GH_TOKEN: ${{ github.token }}
PROMOTION_OPERATION: ${{ inputs.promotion_operation }}
run: |
case "${PROMOTION_OPERATION}" in
promote) admission=admit ;;
reconcile) admission=admit-reconciliation ;;
*) exit 1 ;;
esac
node npm/agentplugins/scripts/authoring-promotion.js "${admission}" "${PROMOTION_ROOT}/options.json" > "${PROMOTION_ROOT}/admitted.json"
node <<'NODE'
const fs = require('node:fs');
const result = JSON.parse(fs.readFileSync(`${process.env.PROMOTION_ROOT}/admitted.json`));
if (!['qualified-for-promotion', 'reconciliation-required'].includes(result.status) || result.subjects.length !== 19) throw Error('exact admitted subjects required');
fs.appendFileSync(process.env.GITHUB_OUTPUT, `sign_required=${result.sign_required}\npaths<<SUBJECTS\n${result.subjects.map(s => s.file).join('\n')}\nSUBJECTS\n`);
NODE
- uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
if: ${{ steps.subjects.outputs.sign_required == 'true' }}
with:
subject-path: ${{ steps.subjects.outputs.paths }}
- name: Reverify all signatures and reconcile both native releases
env:
GH_TOKEN: ${{ github.token }}
PROMOTION_OPERATION: ${{ inputs.promotion_operation }}
run: |
case "${PROMOTION_OPERATION}" in promote|reconcile) ;; *) exit 1 ;; esac
node npm/agentplugins/scripts/authoring-promotion.js "${PROMOTION_OPERATION}" "${PROMOTION_ROOT}/options.json"
10 changes: 10 additions & 0 deletions .github/workflows/release-assets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ jobs:
attestations: write
artifact-metadata: write
steps:
- name: Reject standard-first versions on legacy producer
shell: bash
env:
RELEASE_TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
if [[ ! "${RELEASE_TAG}" =~ ^v1\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
echo "Legacy GoReleaser supports plugin-kit-ai v1 only. Use agentplugins-release.yml paired-preparation for plugin-kit-ai major 2; publication requires later qualification." >&2
exit 1
fi
- uses: actions/checkout@v6
with:
fetch-depth: 0
Expand Down
Loading
Loading