Skip to content

Commit d32ebd0

Browse files
Merge pull request #4 from open-coder-ai/ci/derive-framework-ref-from-catalog
ci: derive the framework ref from the catalog instead of a typed default
2 parents 9c88c1a + 5b2cd5c commit d32ebd0

4 files changed

Lines changed: 154 additions & 18 deletions

File tree

.github/workflows/generated-only.yml

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,43 @@ jobs:
2424
persist-credentials: false
2525
path: dist
2626

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

34-
- name: Check out the catalog
41+
- name: Read the framework ref the catalog declares
42+
id: framework
43+
working-directory: catalog
44+
run: |
45+
if [ ! -f .framework-ref ]; then
46+
echo "::error::chock-catalog has no .framework-ref, so there is no declared framework to verify this tree against."
47+
exit 1
48+
fi
49+
ref="$(tr -d '[:space:]' < .framework-ref)"
50+
if [ -z "$ref" ]; then
51+
echo "::error::chock-catalog/.framework-ref is empty, so there is no declared framework to verify this tree against."
52+
exit 1
53+
fi
54+
echo "ref=$ref" >> "$GITHUB_OUTPUT"
55+
echo "Verifying against framework $ref, from chock-catalog/.framework-ref."
56+
57+
- name: Check out the framework at the ref the catalog declares
3558
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
3659
with:
3760
persist-credentials: false
38-
repository: open-coder-ai/chock-catalog
39-
path: catalog
61+
repository: open-coder-ai/chock
62+
ref: ${{ steps.framework.outputs.ref }}
63+
path: framework
4064

4165
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
4266
with:

.github/workflows/publish.yml

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,20 @@ on:
1919
type: string
2020
default: main
2121
framework_ref:
22-
# A tag is the right default -- a release should be reproducible from two pinned
23-
# refs. This names the framework the committed tree was last built with, so a
24-
# dispatch that accepts the defaults reproduces what is published rather than
25-
# rewriting it. It sat at v0.4.0 across three releases while the trees moved to
26-
# v0.5.0, v0.6.0 and v0.7.0, which made the safe-looking default the one that
27-
# would have rewritten every package. Bump it in the same change that republishes.
28-
description: Framework ref to build with
22+
# The framework the committed tree was built with: the emitter version whose output
23+
# *is* this repository's content. Getting it wrong does not produce a stale build,
24+
# it rewrites every published package against a different emitter.
25+
#
26+
# `auto` reads that value from the catalog ref being published, out of its
27+
# `.framework-ref` file, so the default is right by construction. A literal default
28+
# was tried and failed: it sat at v0.4.0 across three releases while the trees moved
29+
# to v0.5.0, v0.6.0 and v0.7.0, because the comment asking a human to bump it does
30+
# not execute. A sentinel is used rather than an empty default so that the resolved
31+
# value is visible in the run log and an accidental blank still resolves the same
32+
# way. An explicit tag, branch or SHA overrides it, which is why the input remains.
33+
description: Framework ref to build with ("auto" = the ref chock-catalog declares)
2934
type: string
30-
default: v0.7.0
35+
default: auto
3136
dry_run:
3237
description: Build and show the diff without pushing
3338
type: boolean
@@ -56,12 +61,37 @@ jobs:
5661
ref: ${{ inputs.catalog_ref }}
5762
path: catalog
5863

59-
- name: Check out the framework
64+
- name: Resolve the framework ref
65+
id: framework
66+
working-directory: catalog
67+
env:
68+
# Dispatch inputs are typed by whoever runs the workflow; expanded by the runner
69+
# into shell text they would execute, through the environment they stay data.
70+
FRAMEWORK_REF_INPUT: ${{ inputs.framework_ref }}
71+
run: |
72+
ref="$FRAMEWORK_REF_INPUT"
73+
origin="the framework_ref dispatch input"
74+
if [ -z "$ref" ] || [ "$ref" = auto ]; then
75+
if [ ! -f .framework-ref ]; then
76+
echo "::error::framework_ref is \"auto\" but the catalog ref being published has no .framework-ref; name a framework ref explicitly."
77+
exit 1
78+
fi
79+
ref="$(tr -d '[:space:]' < .framework-ref)"
80+
origin="chock-catalog/.framework-ref at the catalog ref being published"
81+
fi
82+
if [ -z "$ref" ]; then
83+
echo "::error::The framework ref resolved to nothing; name a framework ref explicitly."
84+
exit 1
85+
fi
86+
echo "ref=$ref" >> "$GITHUB_OUTPUT"
87+
echo "Building with framework $ref, from $origin."
88+
89+
- name: Check out the framework at the resolved ref
6090
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
6191
with:
6292
persist-credentials: false
6393
repository: open-coder-ai/chock
64-
ref: ${{ inputs.framework_ref }}
94+
ref: ${{ steps.framework.outputs.ref }}
6595
path: framework
6696

6797
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
@@ -107,7 +137,16 @@ jobs:
107137
108138
- name: Show what would change
109139
working-directory: dist
110-
run: git --no-pager diff --stat
140+
run: |
141+
# Record intent-to-add first. `git diff` reports tracked files only, so without
142+
# this every *added* file is invisible and a human reading the dry run to decide
143+
# whether to publish is shown only what disappears. The v0.7.0 dry run printed
144+
# "15 files changed, 14 insertions(+), 2450 deletions(-)" for what was a rename
145+
# into a larger file; staged, the same build reads 5677 insertions(+), 14
146+
# deletions(-). `-N` records the paths without staging content, so the worktree
147+
# is untouched and the commit below behaves exactly as it did.
148+
git add -A -N .
149+
git --no-pager diff --stat
111150
112151
- name: Publish
113152
if: ${{ inputs.dry_run == false }}
@@ -116,10 +155,14 @@ jobs:
116155
# Dispatch inputs are typed by whoever runs the workflow; expanded by the runner
117156
# into shell text they would execute, through the environment they stay data.
118157
CATALOG_REF: ${{ inputs.catalog_ref }}
119-
FRAMEWORK_REF: ${{ inputs.framework_ref }}
158+
FRAMEWORK_REF: ${{ steps.framework.outputs.ref }}
120159
run: |
121160
git config user.name "github-actions[bot]"
122161
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
162+
# Same blindness as the dry run, with a worse consequence: on a publish whose
163+
# only change is added files, an unstaged `git diff --quiet` is clean and this
164+
# exits 0 reporting "No change to publish" while publishing nothing.
165+
git add -A -N .
123166
if git diff --quiet; then
124167
echo "No change to publish."
125168
exit 0

SECURITY.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Security Policy
2+
3+
## What lives here, and what that means for a report
4+
5+
`chock-copilot-plugins` is **compiled output**. Every file under `copilot/`, `claude/` and `agent-plugins/`, along with the
6+
marketplace index, `chock-market.lock` and `PLUGINS.md`, is generated from policy sources in
7+
[chock-catalog](https://github.com/open-coder-ai/chock-catalog) by
8+
[chock](https://github.com/open-coder-ai/chock), and the
9+
[Generated-only](.github/workflows/generated-only.yml) check regenerates the tree on every
10+
push and pull request and fails on any difference. There is no hand-written code in this
11+
repository to hold a vulnerability of its own — a defect visible here was introduced either
12+
in the emitter or in the policy it emitted, so a fix landed here would be overwritten by the
13+
next publish. **Report it where it can actually be fixed:**
14+
15+
| What you found | Where it belongs |
16+
|---|---|
17+
| 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) |
18+
| 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) |
19+
| 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 |
20+
| 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 |
21+
22+
The last two are the only categories that are genuinely *this* repository's, and both are
23+
about distribution integrity rather than about policy behaviour.
24+
25+
## Reporting a vulnerability
26+
27+
Use chock's private advisory route:
28+
<https://github.com/open-coder-ai/chock/security/advisories/new>. Do **not** open a public
29+
issue for an exploitable finding, here or upstream. Include the affected path, how to
30+
reproduce it, and the impact. Acknowledgement and assessment follow the timelines stated in
31+
[chock's SECURITY.md](https://github.com/open-coder-ai/chock/blob/main/SECURITY.md); this
32+
repository does not set its own, and there is no PGP key — GitHub's advisory form is the
33+
private channel.
34+
35+
Pull requests are closed here automatically with a pointer to the catalog. That applies to
36+
security fixes too: a patch to a generated file cannot survive the next publish.
37+
38+
## Verifying what you installed
39+
40+
Two things are checkable without trusting this repository's README:
41+
42+
- **Every published plugin directory is hashed in `chock-market.lock`** (sha256 per
43+
directory), so a plugin's content can be compared against what the index claims.
44+
- **The tree is reproducible.** Check out this repository, the catalog and chock as
45+
siblings, install chock from source, and run the same two build commands the
46+
[Generated-only](.github/workflows/generated-only.yml) workflow runs. `git diff` and
47+
`git status --porcelain` should both be silent. That workflow derives the framework
48+
version from the catalog's own `.framework-ref`, so a rebuild from the catalog ref you
49+
care about uses the emitter that catalog declares rather than whatever is on a branch.
50+
51+
## What these plugins do not promise
52+
53+
Stated here rather than left to the README, because a security file that omits it is
54+
claiming more than the product does:
55+
56+
- A hook is enforcement **only where the host runs it**. Each plugin's description states
57+
its own fail posture, and several fail **open** — if the hook cannot run, the command is
58+
allowed. That is a property of the host agent, not a bug in the plugin.
59+
- Skills and ambient rules are **advisory** in every client. They are text the model reads.
60+
- Repository-level enforcement — git hooks and a CI gate, which apply with no agent running
61+
— is not part of an installed plugin. It comes from `chock sync` in the target
62+
repository.

assets/icon.svg

Lines changed: 7 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)