Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
55 changes: 55 additions & 0 deletions .github/workflows/close-prs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Close hand-written pull requests

# Review belongs where the source is. A pull request here would be edited compiled output
# with no policy manifest behind it, no evals, and no honesty-tier computation -- exactly
# the drift the generated-only invariant exists to prevent. Contributors are pointed at the
# catalog rather than left waiting on a review that cannot happen.

on:
pull_request_target:
types: [opened, reopened]

permissions:
pull-requests: write

jobs:
redirect:
# Fork PRs only. The redirect rationale -- your change belongs in the catalog --
# applies to outside contributions; a branch in this repository is the maintainer's
# own infrastructure work (workflows, config), which is not generated content. This
# guard closed the repo's own first hardening PR before the condition existed.
if: github.event.pull_request.head.repo.full_name != github.repository
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
env:
# Passed through the environment rather than inlined, so the message is plain
# text in one place instead of an escaped string inside JavaScript inside YAML.
BODY: |
Thanks for taking the time to open this.

This repository is **generated** -- every file here is compiled from policy sources in
[chock-catalog](https://github.com/open-coder-ai/chock-catalog) and overwritten on each
release. A change merged here would be erased by the next publish, and it would carry
none of the checks a policy gets: manifest validation, replayed evals, or the
coverage-honesty computation.

Please open your change against the catalog instead -- it reaches every client from
there, including this one. If you found a bug in how packages are generated rather than
in a policy, the emitter lives in [chock](https://github.com/open-coder-ai/chock).

Closing for that reason, not because the change is unwelcome.
with:
script: |
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: process.env.BODY,
});
await github.rest.pulls.update({
pull_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
state: 'closed',
});
85 changes: 85 additions & 0 deletions .github/workflows/generated-only.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Generated-only

# This repository is compiled output. The guarantee it offers users is that its contents
# are exactly what the catalog published -- so the check is not a lint, it is the security
# argument: regenerate from the pinned sources and fail on any difference. A hand edit, a
# tampered guard script, or a manually added plugin all surface here as a diff.

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
verify:
runs-on: ubuntu-latest
steps:
- name: Check out this distribution repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
path: dist

# The catalog is checked out first because it names the framework. `.framework-ref`
# is the emitter version this catalog's published output is defined against, so the
# only build that can prove this tree came from the catalog is a build with that
# framework. Checking out `main` here instead -- which is what this did -- compares a
# fixed tree against a moving emitter: the next merge that changes emitter output
# turns this check red on a tree nobody touched, while `publish` keeps building from
# a pinned ref. Deriving both from one file is what keeps verify and publish honest.
- name: Check out the catalog
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
repository: open-coder-ai/chock-catalog
path: catalog

- name: Read the framework ref the catalog declares
id: framework
working-directory: catalog
run: |
if [ ! -f .framework-ref ]; then
echo "::error::chock-catalog has no .framework-ref, so there is no declared framework to verify this tree against."
exit 1
fi
ref="$(tr -d '[:space:]' < .framework-ref)"
if [ -z "$ref" ]; then
echo "::error::chock-catalog/.framework-ref is empty, so there is no declared framework to verify this tree against."
exit 1
fi
echo "ref=$ref" >> "$GITHUB_OUTPUT"
echo "Verifying against framework $ref, from chock-catalog/.framework-ref."

- name: Check out the framework at the ref the catalog declares
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
repository: open-coder-ai/chock
ref: ${{ steps.framework.outputs.ref }}
path: framework

- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.12'

- name: Install the framework from source
run: pip install ./framework

- name: Verify the lockfile and index match the published tree
working-directory: dist
run: chock marketplace build --dist . --check --tree devin --name chock-devin --url https://github.com/open-coder-ai/chock-devin-plugins

- name: Regenerate from the catalog and diff
run: |
chock plugin build --repo catalog --policies-dir base --format devin --out-dir dist
chock marketplace build --dist dist --tree devin --name chock-devin --url https://github.com/open-coder-ai/chock-devin-plugins
cd dist
if ! git diff --exit-code; then
echo "::error::This repository is generated. Regenerating from the catalog produced a different tree, so something here was not published by the catalog. Open a pull request against open-coder-ai/chock-catalog instead."
exit 1
fi
echo "Tree matches a fresh build from the catalog."
143 changes: 143 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
name: Publish

# Rebuilds this repository from the catalog and pushes the result. Runs HERE rather than
# in the catalog so no long-lived cross-repo credential exists; publishing is a human
# decision, never a side effect of a merge.

on:
workflow_dispatch:
inputs:
catalog_ref:
description: Catalog ref to publish (tag, branch or SHA)
type: string
default: main
framework_ref:
# The framework the committed tree was built with: the emitter version whose output
# *is* this repository's content. Getting it wrong does not produce a stale build,
# it rewrites every published package against a different emitter.
#
# `auto` reads that value from the catalog ref being published, out of its
# `.framework-ref` file, so the default is right by construction. A literal default
# was tried and failed: it sat at v0.4.0 across three releases while the trees moved
# to v0.5.0, v0.6.0 and v0.7.0, because the comment asking a human to bump it does
# not execute. A sentinel is used rather than an empty default so that the resolved
# value is visible in the run log and an accidental blank still resolves the same
# way. An explicit tag, branch or SHA overrides it, which is why the input remains.
description: Framework ref to build with ("auto" = the ref chock-catalog declares)
type: string
default: auto
dry_run:
description: Build and show the diff without pushing
type: boolean
default: true

permissions:
contents: write

jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Check out this distribution repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# The one checkout that keeps credentials: this job commits and pushes the
# regenerated tree. Documented as the artipacked exception in .github/zizmor.yml.
persist-credentials: true
path: dist

- name: Check out the catalog at the ref being published
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
repository: open-coder-ai/chock-catalog
ref: ${{ inputs.catalog_ref }}
path: catalog

- name: Resolve the framework ref
id: framework
working-directory: catalog
env:
# Dispatch inputs are typed by whoever runs the workflow; expanded by the runner
# into shell text they would execute, through the environment they stay data.
FRAMEWORK_REF_INPUT: ${{ inputs.framework_ref }}
run: |
ref="$FRAMEWORK_REF_INPUT"
origin="the framework_ref dispatch input"
if [ -z "$ref" ] || [ "$ref" = auto ]; then
if [ ! -f .framework-ref ]; then
echo "::error::framework_ref is \"auto\" but the catalog ref being published has no .framework-ref; name a framework ref explicitly."
exit 1
fi
ref="$(tr -d '[:space:]' < .framework-ref)"
origin="chock-catalog/.framework-ref at the catalog ref being published"
fi
if [ -z "$ref" ]; then
echo "::error::The framework ref resolved to nothing; name a framework ref explicitly."
exit 1
fi
echo "ref=$ref" >> "$GITHUB_OUTPUT"
echo "Building with framework $ref, from $origin."

- name: Check out the framework at the resolved ref
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
repository: open-coder-ai/chock
ref: ${{ steps.framework.outputs.ref }}
path: framework

- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.12'

- name: Install the framework
run: pip install ./framework

- name: Gate on the catalog's own checks
working-directory: catalog
run: |
chock check
chock check --only evals

- name: Clear the generated trees
run: rm -rf dist/claude dist/agent-plugins dist/copilot dist/cursor dist/codex dist/devin dist/.devin-plugin

- name: Build the packages, index, lockfile and catalog page
run: |
chock plugin build --repo catalog --policies-dir base --format devin --out-dir dist
chock marketplace build --dist dist --tree devin --name chock-devin --url https://github.com/open-coder-ai/chock-devin-plugins

- name: Show what would change
working-directory: dist
run: |
# Record intent-to-add first. `git diff` reports tracked files only, so without
# this every *added* file is invisible and a human reading the dry run to decide
# whether to publish is shown only what disappears. The v0.7.0 dry run printed
# "15 files changed, 14 insertions(+), 2450 deletions(-)" for what was a rename
# into a larger file; staged, the same build reads 5677 insertions(+), 14
# deletions(-). `-N` records the paths without staging content, so the worktree
# is untouched and the commit below behaves exactly as it did.
git add -A -N .
git --no-pager diff --stat

- name: Publish
if: ${{ inputs.dry_run == false }}
working-directory: dist
env:
CATALOG_REF: ${{ inputs.catalog_ref }}
FRAMEWORK_REF: ${{ steps.framework.outputs.ref }}
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Same blindness as the dry run, with a worse consequence: on a publish whose
# only change is added files, an unstaged `git diff --quiet` is clean and this
# exits 0 reporting "No change to publish" while publishing nothing.
git add -A -N .
if git diff --quiet; then
echo "No change to publish."
exit 0
fi
git add -A
git commit -m "generated: catalog $CATALOG_REF (framework $FRAMEWORK_REF)"
git push
42 changes: 42 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Security checks

# zizmor audits the workflows (adoption-day: two input-injection sites in publish.yml,
# six credential-persisting checkouts, and two unpinned validator installs -- all fixed;
# the three deliberate exceptions live in .github/zizmor.yml with their reasons).
# actionlint checks workflow correctness. ShellCheck is deliberately NOT run here: every
# shell script in this repository is generated from the catalog and verified
# byte-identical to its source by the generated-only check, and the catalog lints the
# sources -- a second lint of the same bytes would be signal-free.

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
zizmor:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- uses: zizmorcore/zizmor-action@3dc1ecc9bcb9e94e9b2c709687979e1298497054 # v0.6.2
with:
min-severity: low

actionlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Run actionlint
run: |
go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.7
"$(go env GOPATH)/bin/actionlint" -color
22 changes: 22 additions & 0 deletions .github/zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# zizmor configuration: deliberate, documented exceptions only.
rules:
dangerous-triggers:
# close-prs.yml uses pull_request_target in the documented-safe pattern: it never
# checks out or executes PR code -- it only calls the GitHub API to comment and close.
# The trigger is required to act on fork PRs, which is this workflow's entire job.
ignore:
- close-prs.yml
artipacked:
# publish.yml's dist checkout is the one writer this repository exists to serve: it
# commits and pushes the regenerated tree with the workflow's own scoped token.
# Credential persistence there is the mechanism, not an oversight.
ignore:
- publish.yml
adhoc-packages:
# The claude-code CLI is npm-installed to run `claude plugin validate` -- there is no
# lockfile to install it from in a repo that contains no Node project. The material
# risk (a floating version changing the verification under us) is addressed by
# pinning the exact version in both install lines.
ignore:
- generated-only.yml
- publish.yml
Loading
Loading