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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
15 changes: 15 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Human ownership must be backed by a repository ruleset that requires this
# code-owner review, dismisses stale approvals, and does not accept bot approval.
* @fearclear @smackgg @youking-lib @JPJeePee

/registry/host-capability-policy.json @fearclear @smackgg @youking-lib @JPJeePee
/docs/host-capability-requests/ @fearclear @smackgg @youking-lib @JPJeePee
/packages/skills/convax-plugin-authoring/ @fearclear @smackgg @youking-lib @JPJeePee
/tooling/host-capability-history.mjs @fearclear @smackgg @youking-lib @JPJeePee
/tooling/host-capability-request.mjs @fearclear @smackgg @youking-lib @JPJeePee
/tooling/host-capability-decision.mjs @fearclear @smackgg @youking-lib @JPJeePee
/tooling/create-host-capability-decision-receipt.mjs @fearclear @smackgg @youking-lib @JPJeePee
/docs/host-capability-resolution.md @fearclear @smackgg @youking-lib @JPJeePee
/tooling/publication-eligibility.mjs @fearclear @smackgg @youking-lib @JPJeePee
/.github/CODEOWNERS @fearclear @smackgg @youking-lib @JPJeePee
/.github/workflows/ @fearclear @smackgg @youking-lib @JPJeePee
277 changes: 277 additions & 0 deletions .github/workflows/approve-host-capability.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
name: Issue protected Host capability decision

on:
workflow_dispatch:
inputs:
request_id:
description: Pending Host capability request id on protected main
required: true
type: string
plugin_api_version:
description: Exact published @convax/plugin-api stable version
required: true
type: string
catalog_sha256:
description: SHA-256 of the published plugin-api.json asset
required: true
type: string
package_asset:
description: Exact npm package tarball asset name in the immutable Host Release
required: true
type: string
package_sha256:
description: SHA-256 of the published @convax/plugin-api npm tarball
required: true
type: string
host_repository:
description: Host repository; only microvoid/convax is accepted
required: true
default: microvoid/convax
type: string
host_commit:
description: Exact Host release commit containing the merged PR
required: true
type: string
host_pull_request:
description: Merged Host pull request number
required: true
type: string
host_release_tag:
description: Immutable Host release tag for Catalog and conformance assets
required: true
type: string
catalog_asset:
description: plugin-api.json release asset name
required: true
default: plugin-api.json
type: string
conformance_asset:
description: Runtime conformance evidence release asset name
required: true
type: string
conformance_sha256:
description: SHA-256 of runtime conformance evidence
required: true
type: string

permissions:
contents: read

concurrency:
group: host-capability-decision-${{ inputs.request_id }}-${{ inputs.catalog_sha256 }}
cancel-in-progress: false

jobs:
issue:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 15
environment: plugin-host-capability-governance
permissions:
actions: read
attestations: write
contents: write
id-token: write
env:
REQUEST_ID: ${{ inputs.request_id }}
PLUGIN_API_VERSION: ${{ inputs.plugin_api_version }}
CATALOG_SHA256: ${{ inputs.catalog_sha256 }}
PACKAGE_SHA256: ${{ inputs.package_sha256 }}
CONFORMANCE_SHA256: ${{ inputs.conformance_sha256 }}
HOST_REPOSITORY: ${{ inputs.host_repository }}
HOST_COMMIT: ${{ inputs.host_commit }}
HOST_PULL_REQUEST: ${{ inputs.host_pull_request }}
HOST_RELEASE_TAG: ${{ inputs.host_release_tag }}
CATALOG_ASSET: ${{ inputs.catalog_asset }}
PACKAGE_ASSET: ${{ inputs.package_asset }}
CONFORMANCE_ASSET: ${{ inputs.conformance_asset }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Check out protected decision source
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: true
- name: Set up Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.14
- name: Install protected verifier dependencies
run: bun install --frozen-lockfile --ignore-scripts
- name: Validate bounded workflow inputs
shell: bash
run: |
set -euo pipefail
test "$GITHUB_REF" = refs/heads/main
test "$HOST_REPOSITORY" = microvoid/convax
[[ "$REQUEST_ID" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]
[[ "$PLUGIN_API_VERSION" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]
[[ "$CATALOG_SHA256" =~ ^[a-f0-9]{64}$ ]]
[[ "$PACKAGE_SHA256" =~ ^[a-f0-9]{64}$ ]]
[[ "$CONFORMANCE_SHA256" =~ ^[a-f0-9]{64}$ ]]
[[ "$HOST_COMMIT" =~ ^[a-f0-9]{40}$ ]]
[[ "$HOST_PULL_REQUEST" =~ ^[1-9][0-9]*$ ]]
[[ "$HOST_RELEASE_TAG" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]
[[ "$CATALOG_ASSET" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]
[[ "$PACKAGE_ASSET" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]
[[ "$CONFORMANCE_ASSET" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]
- name: Fetch and verify immutable Host evidence
shell: bash
run: |
set -euo pipefail
evidence="$RUNNER_TEMP/host-capability-evidence"
mkdir "$evidence"
gh release download "$HOST_RELEASE_TAG" \
--repo "$HOST_REPOSITORY" \
--pattern "$CATALOG_ASSET" \
--pattern "$PACKAGE_ASSET" \
--pattern "$CONFORMANCE_ASSET" \
--dir "$evidence"
test "$(sha256sum "$evidence/$CATALOG_ASSET" | awk '{print $1}')" = "$CATALOG_SHA256"
test "$(sha256sum "$evidence/$PACKAGE_ASSET" | awk '{print $1}')" = "$PACKAGE_SHA256"
test "$(sha256sum "$evidence/$CONFORMANCE_ASSET" | awk '{print $1}')" = "$CONFORMANCE_SHA256"
test "$(stat -c '%s' "$evidence/$PACKAGE_ASSET")" -le 33554432
test "$(stat -c '%s' "$evidence/$CONFORMANCE_ASSET")" -le 1048576
gh release verify "$HOST_RELEASE_TAG" \
--repo "$HOST_REPOSITORY" \
--format json > "$evidence/host-release-verification.json"
gh release verify-asset "$HOST_RELEASE_TAG" \
"$evidence/$CATALOG_ASSET" \
--repo "$HOST_REPOSITORY" \
--format json > "$evidence/catalog-verification.json"
gh release verify-asset "$HOST_RELEASE_TAG" \
"$evidence/$PACKAGE_ASSET" \
--repo "$HOST_REPOSITORY" \
--format json > "$evidence/package-verification.json"
gh release verify-asset "$HOST_RELEASE_TAG" \
"$evidence/$CONFORMANCE_ASSET" \
--repo "$HOST_REPOSITORY" \
--format json > "$evidence/conformance-verification.json"
gh attestation verify "$evidence/$CATALOG_ASSET" \
--repo microvoid/convax \
--signer-workflow microvoid/convax/.github/workflows/plugin-api-release.yml \
--source-ref refs/heads/convax-next \
--source-digest "$HOST_COMMIT" \
--deny-self-hosted-runners \
> "$evidence/catalog-attestation.json"
gh attestation verify "$evidence/$PACKAGE_ASSET" \
--repo microvoid/convax \
--signer-workflow microvoid/convax/.github/workflows/plugin-api-release.yml \
--source-ref refs/heads/convax-next \
--source-digest "$HOST_COMMIT" \
--deny-self-hosted-runners \
> "$evidence/package-attestation.json"
gh attestation verify "$evidence/$CONFORMANCE_ASSET" \
--repo microvoid/convax \
--signer-workflow microvoid/convax/.github/workflows/plugin-api-release.yml \
--source-ref refs/heads/convax-next \
--source-digest "$HOST_COMMIT" \
--deny-self-hosted-runners \
> "$evidence/conformance-attestation.json"
echo "EVIDENCE_DIRECTORY=$evidence" >> "$GITHUB_ENV"
- name: Verify the npm package is published from the same tarball
shell: bash
run: |
set -euo pipefail
npm view "@convax/plugin-api@$PLUGIN_API_VERSION" dist \
--registry=https://registry.npmjs.org \
--json | jq '{dist:.}' > "$EVIDENCE_DIRECTORY/npm-metadata.json"
npm_tarball_url="$(jq -r '.dist.tarball' "$EVIDENCE_DIRECTORY/npm-metadata.json")"
test "${npm_tarball_url#https://registry.npmjs.org/}" != "$npm_tarball_url"
curl --fail --location --silent --show-error \
"$npm_tarball_url" \
--output "$EVIDENCE_DIRECTORY/npm-package.tgz"
cmp "$EVIDENCE_DIRECTORY/$PACKAGE_ASSET" \
"$EVIDENCE_DIRECTORY/npm-package.tgz"
tar -xOzf "$EVIDENCE_DIRECTORY/$PACKAGE_ASSET" package/package.json \
| head -c 131073 > "$EVIDENCE_DIRECTORY/package.json"
test "$(stat -c '%s' "$EVIDENCE_DIRECTORY/package.json")" -le 131072
tar -xOzf "$EVIDENCE_DIRECTORY/$PACKAGE_ASSET" \
package/dist/generated/plugin-api.json \
| head -c 16777217 > "$EVIDENCE_DIRECTORY/package-plugin-api.json"
test "$(stat -c '%s' "$EVIDENCE_DIRECTORY/package-plugin-api.json")" -le 16777216
- name: Fetch protected review and Host merge facts
shell: bash
run: |
set -euo pipefail
evidence="$EVIDENCE_DIRECTORY"
gh api "repos/$HOST_REPOSITORY/pulls/$HOST_PULL_REQUEST" \
> "$evidence/host-pr.json"
merge_commit="$(jq -r '.merge_commit_sha' "$evidence/host-pr.json")"
test -n "$merge_commit"
gh api "repos/$HOST_REPOSITORY/compare/$merge_commit...$HOST_COMMIT" \
> "$evidence/host-compare.json"
gh api "repos/$HOST_REPOSITORY/releases/tags/$HOST_RELEASE_TAG" \
> "$evidence/host-release.json"
git ls-remote "https://github.com/$HOST_REPOSITORY.git" \
"refs/tags/$HOST_RELEASE_TAG" "refs/tags/$HOST_RELEASE_TAG^{}" \
| awk '$2 ~ /\^\{\}$/ { peeled=$1 } $2 !~ /\^\{\}$/ { direct=$1 } END { print peeled ? peeled : direct }' \
> "$evidence/host-tag-sha.txt"
gh api \
"repos/$GITHUB_REPOSITORY/environments/plugin-host-capability-governance" \
> "$evidence/environment.json"
gh api "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/approvals" \
> "$evidence/approvals.json"
gh api "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \
> "$evidence/run.json"
- name: Create exact decision receipt
shell: bash
run: |
set -euo pipefail
receipt="$RUNNER_TEMP/$REQUEST_ID.decision.json"
bun tooling/create-host-capability-decision-receipt.mjs \
--approvals "$EVIDENCE_DIRECTORY/approvals.json" \
--catalog "$EVIDENCE_DIRECTORY/$CATALOG_ASSET" \
--conformance "$EVIDENCE_DIRECTORY/$CONFORMANCE_ASSET" \
--environment "$EVIDENCE_DIRECTORY/environment.json" \
--host-compare "$EVIDENCE_DIRECTORY/host-compare.json" \
--host-pr "$EVIDENCE_DIRECTORY/host-pr.json" \
--host-release "$EVIDENCE_DIRECTORY/host-release.json" \
--host-tag-sha "$EVIDENCE_DIRECTORY/host-tag-sha.txt" \
--npm-metadata "$EVIDENCE_DIRECTORY/npm-metadata.json" \
--npm-tarball "$EVIDENCE_DIRECTORY/npm-package.tgz" \
--output "$receipt" \
--package-catalog "$EVIDENCE_DIRECTORY/package-plugin-api.json" \
--package-json "$EVIDENCE_DIRECTORY/package.json" \
--package-tarball "$EVIDENCE_DIRECTORY/$PACKAGE_ASSET" \
--run "$EVIDENCE_DIRECTORY/run.json"
echo "DECISION_RECEIPT=$receipt" >> "$GITHUB_ENV"
echo "DECISION_RECEIPT_SHA256=$(sha256sum "$receipt" | awk '{print $1}')" >> "$GITHUB_ENV"
echo "DECISION_RELEASE_TAG=host-capability-decision-v1-$REQUEST_ID-$CATALOG_SHA256" >> "$GITHUB_ENV"
- name: Attest protected workflow provenance
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: ${{ env.DECISION_RECEIPT }}
- name: Publish an immutable decision release
shell: bash
run: |
set -euo pipefail
if gh release view "$DECISION_RELEASE_TAG" \
--repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
exit 1
fi
gh release create "$DECISION_RELEASE_TAG" "$DECISION_RECEIPT" \
--repo "$GITHUB_REPOSITORY" \
--target "$GITHUB_SHA" \
--title "Host capability decision: $REQUEST_ID" \
--notes "Protected human decision bound to Host and Catalog evidence." \
--latest=false \
--draft
gh release edit "$DECISION_RELEASE_TAG" \
--repo "$GITHUB_REPOSITORY" \
--draft=false
gh release verify "$DECISION_RELEASE_TAG" \
--repo "$GITHUB_REPOSITORY" \
--format json
gh release verify-asset "$DECISION_RELEASE_TAG" "$DECISION_RECEIPT" \
--repo "$GITHUB_REPOSITORY" \
--format json
{
echo "### Protected Host capability decision"
echo
echo "- request: \`$REQUEST_ID\`"
echo "- immutable release: \`$DECISION_RELEASE_TAG\`"
echo "- receipt SHA-256: \`$DECISION_RECEIPT_SHA256\`"
echo "- Host: \`$HOST_REPOSITORY@$HOST_COMMIT\` PR #$HOST_PULL_REQUEST"
echo "- @convax/plugin-api: \`$PLUGIN_API_VERSION\` package \`$PACKAGE_SHA256\`, Catalog \`$CATALOG_SHA256\`"
} >> "$GITHUB_STEP_SUMMARY"
46 changes: 46 additions & 0 deletions .github/workflows/host-capability-governance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Host capability governance

on:
pull_request_target:
types: [opened, reopened, synchronize]

permissions:
actions: read
attestations: read
contents: read

jobs:
protected-base:
runs-on: ubuntu-latest
timeout-minutes: 15
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Check out the trusted protected-base verifier
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
path: trusted
persist-credentials: false
ref: ${{ github.event.pull_request.base.sha }}
- name: Check out candidate bytes as untrusted data
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
path: candidate
persist-credentials: false
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.14
- name: Install only trusted verifier dependencies
working-directory: trusted
run: bun install --frozen-lockfile --ignore-scripts
- name: Verify candidate against protected request high-water marks
run: >-
bun trusted/tooling/host-capability-history.mjs
--workspace "$GITHUB_WORKSPACE/candidate"
--base "${{ github.event.pull_request.base.sha }}"
--catalog "$GITHUB_WORKSPACE/candidate/vendor/host-packages/plugin-api/dist/generated/plugin-api.json"
5 changes: 0 additions & 5 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ jobs:
run: |
bun tooling/verify-marketplace-output.mjs dist/catalog
bun tooling/verify-product-lock-input.mjs dist/product-lock-input.json
test "$(find schemas -maxdepth 1 -type f -name '*.json' | wc -l | tr -d ' ')" = \
"$(find dist/catalog/site/schemas -maxdepth 1 -type f -name '*.json' | wc -l | tr -d ' ')"
for schema in schemas/*.json; do
cmp "$schema" "dist/catalog/site/schemas/$(basename "$schema")"
done
- name: Configure Pages
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
- name: Upload Pages artifact
Expand Down
Loading