Skip to content
Draft
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
36 changes: 30 additions & 6 deletions .github/workflows/generated-only.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,43 @@ jobs:
persist-credentials: false
path: dist

- name: Check out the framework
# 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
path: framework
repository: open-coder-ai/chock-catalog
path: catalog

- name: Check out the 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-catalog
path: catalog
repository: open-coder-ai/chock
ref: ${{ steps.framework.outputs.ref }}
path: framework

- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
Expand Down
67 changes: 55 additions & 12 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,20 @@ on:
type: string
default: main
framework_ref:
# A tag is the right default -- a release should be reproducible from two pinned
# refs. This names the framework the committed tree was last built with, so a
# dispatch that accepts the defaults reproduces what is published rather than
# rewriting it. It sat at v0.4.0 across three releases while the trees moved to
# v0.5.0, v0.6.0 and v0.7.0, which made the safe-looking default the one that
# would have rewritten every package. Bump it in the same change that republishes.
description: Framework ref to build with
# 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: v0.7.0
default: auto
dry_run:
description: Build and show the diff without pushing
type: boolean
Expand Down Expand Up @@ -49,12 +54,37 @@ jobs:
ref: ${{ inputs.catalog_ref }}
path: catalog

- name: Check out the framework
- 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: ${{ inputs.framework_ref }}
ref: ${{ steps.framework.outputs.ref }}
path: framework

- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
Expand All @@ -80,17 +110,30 @@ jobs:

- name: Show what would change
working-directory: dist
run: git --no-pager diff --stat
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: ${{ inputs.framework_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
Expand Down
62 changes: 62 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Security Policy

## What lives here, and what that means for a report

`chock-cursor-plugins` is **compiled output**. Every file under `cursor/`, along with the
marketplace index, `chock-market.lock` and `PLUGINS.md`, is generated from policy sources in
[chock-catalog](https://github.com/open-coder-ai/chock-catalog) by
[chock](https://github.com/open-coder-ai/chock), and the
[Generated-only](.github/workflows/generated-only.yml) check regenerates the tree on every
push and pull request and fails on any difference. There is no hand-written code in this
repository to hold a vulnerability of its own — a defect visible here was introduced either
in the emitter or in the policy it emitted, so a fix landed here would be overwritten by the
next publish. **Report it where it can actually be fixed:**

| What you found | Where it belongs |
|---|---|
| A defect in a guard script, hook wiring, plugin manifest, or anything about how policies are compiled into plugins | [open-coder-ai/chock](https://github.com/open-coder-ai/chock) — see its [SECURITY.md](https://github.com/open-coder-ai/chock/blob/main/SECURITY.md) |
| A defect in **policy content**: a guard that does not match what it claims to block, a pattern that can be trivially evaded, a policy whose description overstates its enforcement | [open-coder-ai/chock-catalog](https://github.com/open-coder-ai/chock-catalog) |
| This repository's tree does not match a rebuild from the catalog — i.e. something here was not published by the catalog | [chock](https://github.com/open-coder-ai/chock)'s private advisory route, as a supply-chain report against this repository |
| A defect in this repository's own workflows (`.github/workflows/`) | [chock](https://github.com/open-coder-ai/chock)'s private advisory route, naming this repository |

The last two are the only categories that are genuinely *this* repository's, and both are
about distribution integrity rather than about policy behaviour.

## Reporting a vulnerability

Use chock's private advisory route:
<https://github.com/open-coder-ai/chock/security/advisories/new>. Do **not** open a public
issue for an exploitable finding, here or upstream. Include the affected path, how to
reproduce it, and the impact. Acknowledgement and assessment follow the timelines stated in
[chock's SECURITY.md](https://github.com/open-coder-ai/chock/blob/main/SECURITY.md); this
repository does not set its own, and there is no PGP key — GitHub's advisory form is the
private channel.

Pull requests are closed here automatically with a pointer to the catalog. That applies to
security fixes too: a patch to a generated file cannot survive the next publish.

## Verifying what you installed

Two things are checkable without trusting this repository's README:

- **Every published plugin directory is hashed in `chock-market.lock`** (sha256 per
directory), so a plugin's content can be compared against what the index claims.
- **The tree is reproducible.** Check out this repository, the catalog and chock as
siblings, install chock from source, and run the same two build commands the
[Generated-only](.github/workflows/generated-only.yml) workflow runs. `git diff` and
`git status --porcelain` should both be silent. That workflow derives the framework
version from the catalog's own `.framework-ref`, so a rebuild from the catalog ref you
care about uses the emitter that catalog declares rather than whatever is on a branch.

## What these plugins do not promise

Stated here rather than left to the README, because a security file that omits it is
claiming more than the product does:

- A hook is enforcement **only where the host runs it**. Each plugin's description states
its own fail posture, and several fail **open** — if the hook cannot run, the command is
allowed. That is a property of the host agent, not a bug in the plugin.
- Skills and ambient rules are **advisory** in every client. They are text the model reads.
- Repository-level enforcement — git hooks and a CI gate, which apply with no agent running
— is not part of an installed plugin. It comes from `chock sync` in the target
repository.
7 changes: 7 additions & 0 deletions assets/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading