Skip to content
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9d06f01
fix: bootstrap the initial plugin release
nathanvale Aug 5, 2026
83fd820
Address PR review feedback (#11)
nathanvale Aug 5, 2026
a1e3dab
fix: enforce native plugin release metadata
nathanvale Aug 5, 2026
246f1e3
Address PR review feedback (#11)
nathanvale Aug 5, 2026
6930f18
feat(init): reset recipient release lineage to 0.1.0
nathanvale Aug 5, 2026
96aad7e
feat(payload): enforce one safe regular-file-only payload inventory
nathanvale Aug 5, 2026
5396fd3
feat(metadata): own native package rules with two named profiles
nathanvale Aug 5, 2026
e6451fe
feat(release): bind proof, tag, release, and repair to one commit
nathanvale Aug 5, 2026
3127a5b
feat(ci): gate installable payload changes on releasable PR title
nathanvale Aug 5, 2026
5f1b06f
feat(readiness): verify human-owned publication safeguards read-only
nathanvale Aug 5, 2026
57cd1d3
feat(proof): prove native install, cache, trust, update, and rollback
nathanvale Aug 5, 2026
d1e859f
feat(canary): qualify publishing-system changes with hosted Git canaries
nathanvale Aug 5, 2026
048faae
docs: align operator guidance with the hardened release contract
nathanvale Aug 5, 2026
d00e0fb
docs(plan): add reviewed plugin publishing hardening plan
nathanvale Aug 5, 2026
4c4dd44
fix(ci): isolate packaging fixture from GitHub SHA
nathanvale Aug 5, 2026
04fb28a
Address PR review feedback (#11)
nathanvale Aug 5, 2026
79cd078
fix: close release and canary review gaps
nathanvale Aug 5, 2026
64b60ea
fix: exercise centralized release impact policy
nathanvale Aug 5, 2026
c55082c
fix: bind final release validation to candidate
nathanvale Aug 5, 2026
95c4fb2
fix: close release repair review gaps
nathanvale Aug 5, 2026
d32f637
fix: fetch fork canary heads from source
nathanvale Aug 5, 2026
4c95f28
fix: make hosted and repair gates fail closed
nathanvale Aug 5, 2026
ebbc03e
fix: bind release gates across rename and trust boundaries
nathanvale Aug 5, 2026
f3f8d03
fix: execute release gates from trusted code
nathanvale Aug 5, 2026
232ec8e
fix: isolate release impact in trusted workflow
nathanvale Aug 5, 2026
9c6954c
fix: preserve canary generator and transport boundaries
nathanvale Aug 5, 2026
aafeec5
fix: close release review gaps (#11)
nathanvale Aug 5, 2026
4cf8727
docs: bind release automation identity (#11)
nathanvale Aug 5, 2026
7180e3f
fix: bind package source to checkout (#11)
nathanvale Aug 5, 2026
7832ac9
fix: resolve publication review findings (#11)
nathanvale Aug 5, 2026
5cfdcdc
fix: pin bootstrap release to v0.1.0 (#11)
nathanvale Aug 5, 2026
fc0c99d
docs: clarify release automation credentials (#11)
nathanvale Aug 5, 2026
fef9097
fix: require release automation token (#11)
nathanvale Aug 5, 2026
2a9efcf
fix: harden release and canary admission (#11)
nathanvale Aug 5, 2026
6b9b3b6
fix: close release review gaps
nathanvale Aug 6, 2026
8660009
fix: fail closed on workflow policy gaps
nathanvale Aug 6, 2026
24034b5
fix: sanitize public canary publication
nathanvale Aug 6, 2026
9096fa6
fix: prove sanitized public canaries
nathanvale Aug 6, 2026
7036418
fix: preserve unusual archive filenames
nathanvale Aug 6, 2026
7ea726a
fix: detect list-item workflow actions
nathanvale Aug 6, 2026
ed5a995
fix: resolve release qualification review findings (#11)
nathanvale Aug 6, 2026
fac5e40
fix: close remaining release review gaps
nathanvale Aug 6, 2026
cb182a3
fix: check main linear history policy
nathanvale Aug 6, 2026
bf01654
fix: verify hosted canary credentials (#11)
nathanvale Aug 6, 2026
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
2 changes: 1 addition & 1 deletion .agents/plugins/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "harness-native-plugin-prototype",
"interface": {
"displayName": "Harness Native Plugin Prototype"
"displayName": "Harness Plugin Prototype"
},
"plugins": [
{
Expand Down
5 changes: 3 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "Prototype"
},
"metadata": {
"description": "Marketplace for Harness Native Plugin Prototype",
"description": "Marketplace for Harness Plugin Prototype",
"version": "0.1.0"
},
"plugins": [
Expand All @@ -14,7 +14,8 @@
"author": {
"name": "Prototype"
},
"source": "./plugin"
"source": "./plugin",
"defaultEnabled": false
}
]
}
4 changes: 1 addition & 3 deletions .github/.release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
{
".": "0.1.0"
}
{}
Comment thread
myagentdojo marked this conversation as resolved.
3 changes: 3 additions & 0 deletions .github/release-please-config.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"include-component-in-tag": false,
"skip-github-release": true,
"release-search-depth": 100,
"commit-search-depth": 500,
"packages": {
".": {
"release-type": "node",
"initial-version": "0.1.0",
"package-name": "agent-plugin",
"changelog-path": "CHANGELOG.md",
"changelog-sections": [
Expand All @@ -23,6 +25,7 @@
{ "type": "json", "path": ".claude-plugin/marketplace.json", "jsonpath": "$.metadata.version" },
{ "type": "json", "path": "plugin/.claude-plugin/plugin.json", "jsonpath": "$.version" },
{ "type": "json", "path": "plugin/.codex-plugin/plugin.json", "jsonpath": "$.version" },
{ "type": "generic", "path": "plugin/hooks/codex/hooks.json" },
{ "type": "generic", "path": "plugin/runtime/hello-world.js" }
]
}
Expand Down
125 changes: 125 additions & 0 deletions .github/workflows/hosted-canary.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
name: Hosted canary qualification

on:
pull_request_target:

permissions:
contents: read

concurrency:
group: hosted-canary-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }}
cancel-in-progress: true

jobs:
classify:
name: Classify publishing-system paths
runs-on: ubuntu-24.04
outputs:
required: ${{ steps.classify.outputs.required }}
triggers: ${{ steps.classify.outputs.triggers }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.base.sha }}
fetch-depth: 0
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
with:
bun-version: 1.3.14
- name: Fetch candidate object without executing it
env:
HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: git fetch --no-tags "https://github.com/${HEAD_REPOSITORY}.git" "$HEAD_SHA"
- name: Classify with trusted base code
id: classify
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
result="$(bun run ship:canary -- --classify --base "$BASE_SHA" --head "$HEAD_SHA" --json)"
printf '%s\n' "$result"
printf 'required=%s\n' "$(jq -r '.canaries.required' <<< "$result")" >> "$GITHUB_OUTPUT"
printf 'triggers=%s\n' "$(jq -c '.canaries.triggeringPaths' <<< "$result")" >> "$GITHUB_OUTPUT"

qualify:
name: Qualify immutable hosted candidates
if: needs.classify.outputs.required == 'true' && github.event.pull_request.head.repo.full_name == github.repository
needs: classify
runs-on: ubuntu-24.04
environment: hosted-canary-qualification
steps:
- name: Check out trusted driver
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.base.sha }}
fetch-depth: 0
- name: Check out candidate as data
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.sha }}
path: candidate
persist-credentials: false
fetch-depth: 1
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
with:
bun-version: 1.3.14
- name: Install pinned native marketplace CLIs
run: bun add --global "@anthropic-ai/claude-code@2.1.222" "@openai/codex@0.146.1"
- name: Qualify immutable candidates with trusted driver
env:
CANARY_GH_TOKEN: ${{ secrets.CANARY_GH_TOKEN }}
CANARY_SSH_KNOWN_HOSTS: ${{ secrets.CANARY_SSH_KNOWN_HOSTS }}
CANARY_SSH_PRIVATE_KEY: ${{ secrets.CANARY_SSH_PRIVATE_KEY }}
SOURCE_SHA: ${{ github.event.pull_request.head.sha }}
CANARY_QUALIFIED_SOURCE_SHA: ${{ github.event.pull_request.head.sha }}
CANARY_TRUSTED_WORKFLOW_SHA: ${{ github.event.pull_request.base.sha }}
run: |
test -n "$CANARY_GH_TOKEN"
test -n "$CANARY_SSH_KNOWN_HOSTS"
test -n "$CANARY_SSH_PRIVATE_KEY"
export GH_TOKEN="$CANARY_GH_TOKEN"
gh auth setup-git
install -m 700 -d "$HOME/.ssh"
printf '%s\n' "$CANARY_SSH_KNOWN_HOSTS" > "$HOME/.ssh/known_hosts"
chmod 600 "$HOME/.ssh/known_hosts"
eval "$(ssh-agent -s)"
trap 'ssh-agent -k >/dev/null' EXIT
ssh-add - <<< "$CANARY_SSH_PRIVATE_KEY"
unset CANARY_GH_TOKEN CANARY_SSH_KNOWN_HOSTS CANARY_SSH_PRIVATE_KEY
git remote set-url origin "git@github.com:${GITHUB_REPOSITORY}.git"
bun run ship:canary -- --execute --source-root candidate --ref "$SOURCE_SHA" --json

result:
name: Hosted public and private Git canaries
if: always()
needs:
- classify
- qualify
runs-on: ubuntu-24.04
steps:
- name: Enforce conditional qualification
env:
CANARIES_REQUIRED: ${{ needs.classify.outputs.required }}
CLASSIFICATION_RESULT: ${{ needs.classify.result }}
QUALIFICATION_RESULT: ${{ needs.qualify.result }}
SAME_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
TRIGGERING_PATHS: ${{ needs.classify.outputs.triggers }}
run: |
conclusion=success
summary="Hosted canaries not required. Publishing-system triggers: ${TRIGGERING_PATHS}"
if [ "$CLASSIFICATION_RESULT" != "success" ]; then
conclusion=failure
summary="Publishing-system classification failed."
elif [ "$CANARIES_REQUIRED" = "true" ] && [ "$SAME_REPOSITORY" != "true" ]; then
conclusion=failure
summary="Hosted canaries were required for this fork pull request. A maintainer must run qualification from a same-repository branch. Publishing-system triggers: ${TRIGGERING_PATHS}"
elif [ "$CANARIES_REQUIRED" = "true" ] && [ "$QUALIFICATION_RESULT" != "success" ]; then
conclusion=failure
summary="Hosted canaries were required but did not qualify. Publishing-system triggers: ${TRIGGERING_PATHS}"
elif [ "$CANARIES_REQUIRED" = "true" ]; then
summary="Hosted public and private Git canaries passed for: ${TRIGGERING_PATHS}"
fi
printf '%s\n' "$summary"
printf '### Hosted canary qualification\n\n%s\n' "$summary" >> "$GITHUB_STEP_SUMMARY"
test "$conclusion" = "success"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
19 changes: 6 additions & 13 deletions .github/workflows/plugin-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,10 @@ name: Prove and package plugin

on:
pull_request:
paths:
- "plugin/**"
- "runtime/src/**"
- "plugin.config.json"
- "scripts/**"
- "package.json"
- "CHANGELOG.md"
- ".agents/plugins/marketplace.json"
- ".claude-plugin/marketplace.json"
- ".github/.release-please-manifest.json"
- ".github/release-please-config.json"
- ".github/workflows/**"
push:
branches:
- main
- "candidate/**"
workflow_dispatch:

permissions:
Expand Down Expand Up @@ -58,7 +47,11 @@ jobs:
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
with:
bun-version: 1.3.14
- name: Install pinned native marketplace CLIs
run: bun add --global "@anthropic-ai/claude-code@2.1.222" "@openai/codex@0.146.1"
- run: bun run generate:check
- run: bun test
Comment thread
myagentdojo marked this conversation as resolved.
- run: bun run prove:harness-install -- --require-native
- run: bun run release:validate
- run: bun run prove:distribution
- run: bun run prove:dx
Expand All @@ -69,7 +62,7 @@ jobs:
name: agent-plugin-${{ github.sha }}
path: |
dist/*.tar.gz
dist/*.provenance.json
dist/*.checksums.json
if-no-files-found: error

attest:
Expand Down
106 changes: 106 additions & 0 deletions .github/workflows/release-impact.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: Release impact

on:
pull_request_target:
types:
- opened
- edited
- reopened
- synchronize

permissions:
contents: read
statuses: write

env:
STATUS_CONTEXT: Release impact

concurrency:
group: release-impact-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
qualify:
name: Qualify from trusted base code
runs-on: ubuntu-24.04
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
PR_AUTHOR_LOGIN: ${{ github.event.pull_request.user.login }}
PR_URL: ${{ github.event.pull_request.html_url }}
EXPECTED_RELEASE_PLEASE_LOGIN: ${{ vars.RELEASE_PLEASE_AUTOMATION_LOGIN || 'github-actions[bot]' }}
GH_TOKEN: ${{ github.token }}
steps:
- name: Mark the head commit pending
run: |
gh api --method POST "repos/${GITHUB_REPOSITORY}/statuses/${HEAD_SHA}" \
--raw-field state=pending \
--raw-field context="${STATUS_CONTEXT}" \
--raw-field description="Release impact qualification in progress" \
--raw-field target_url="${PR_URL}"
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.base.sha }}
persist-credentials: false
- name: Fetch the pull request head as untrusted data
run: git fetch --no-tags origin "refs/pull/${PR_NUMBER}/head"
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
with:
bun-version: 1.3.14
- name: Classify payload changes
id: impact
continue-on-error: true
run: >-
bun run scripts/release-impact.ts
--pr-head-ref "$PR_HEAD_REF"
--pr-author-login "$PR_AUTHOR_LOGIN"
--expected-release-please-login "$EXPECTED_RELEASE_PLEASE_LOGIN"
- name: Publish the bound result
if: always()
env:
IMPACT_OUTCOME: ${{ steps.impact.outcome }}
run: |
state=failure
description="Release impact qualification failed"
if [[ "${IMPACT_OUTCOME}" == "success" ]]; then
if current_pr=$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}"); then
current_head_sha=$(jq -r .head.sha <<< "$current_pr")
current_title=$(jq -r .title <<< "$current_pr")
else
description="Release impact could not read current pull request"
current_head_sha=""
current_title=""
fi
if [[ -n "$current_head_sha" && "$current_head_sha" == "$HEAD_SHA" ]] && \
PR_TITLE="$current_title" bun run scripts/release-impact.ts \
--pr-head-ref "$PR_HEAD_REF" \
--pr-author-login "$PR_AUTHOR_LOGIN" \
--expected-release-please-login "$EXPECTED_RELEASE_PLEASE_LOGIN" >/dev/null; then
if verified_pr=$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}"); then
verified_head_sha=$(jq -r .head.sha <<< "$verified_pr")
verified_title=$(jq -r .title <<< "$verified_pr")
else
description="Release impact could not verify the pull request after qualification"
verified_head_sha=""
verified_title=""
fi
if [[ -n "$verified_head_sha" && "$verified_head_sha" == "$current_head_sha" && "$verified_title" == "$current_title" ]]; then
state=success
description="Release impact qualification passed"
fi
elif [[ -n "$current_head_sha" ]]; then
description="Release impact changed before qualification completed"
fi
fi
gh api --method POST "repos/${GITHUB_REPOSITORY}/statuses/${HEAD_SHA}" \
--raw-field state="${state}" \
--raw-field context="${STATUS_CONTEXT}" \
--raw-field description="${description}" \
--raw-field target_url="${PR_URL}"
if [[ "${state}" != "success" ]]; then
exit 1
fi
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Loading