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 .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
{
"name": "commitproof",
"source": "./",
"description": "Know which commits AI wrote, and prove the record wasn't rewritten. Start with /ai-history (no setup), then /receipt-init for signed, hash-chained receipts verified offline."
"description": "Works in Claude Code. Know which commits AI wrote, and prove the record wasn't rewritten. Start with /ai-history (no setup), then /receipt-init for signed, hash-chained receipts verified offline."
}
]
}
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "commitproof",
"displayName": "CommitProof: AI Audit Trail",
"version": "1.3.1",
"description": "An audit trail for AI-written code. /ai-history answers 'how much of this repo did Claude help write?' in seconds from git history, no setup. /receipt-init then gives every commit a tamper-evident receipt (AI-assisted or not, model, Claude Code version, file hashes): hash-chained, signed, verified offline. /receipt-report turns the chain into change-control evidence for SOC 2, HIPAA or PCI audits.",
"description": "Works in Claude Code. An audit trail for AI-written code. /ai-history answers 'how much of this repo did Claude help write?' in seconds from git history, no setup. /receipt-init then gives every commit a tamper-evident receipt (AI-assisted or not, model, Claude Code version, file hashes): hash-chained, signed, verified offline. /receipt-report turns the chain into a change-control report you can give SOC 2, HIPAA or PCI auditors as supporting evidence.",
"author": {
"name": "Rehan Masood",
"email": "rmasood524@gmail.com",
Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
Works in Claude Code. To install, run these two commands in a Claude Code session:

```
/plugin marketplace add Rmasood1122/commitproof
/plugin install commitproof@commitproof
```

# CommitProof

[![CI](https://github.com/Rmasood1122/commitproof/actions/workflows/ci.yml/badge.svg)](https://github.com/Rmasood1122/commitproof/actions/workflows/ci.yml)
Expand All @@ -11,8 +18,9 @@ Teams using Claude Code get asked two questions:
from the git history you already have. No setup, no key, writes nothing.
2. **"Can you prove that record hasn't been edited since?"** `/receipt-init`
gives every commit from then on a tamper-evident receipt: hash-chained,
signed, verifiable offline. `/receipt-report` turns the chain into the
change-control evidence a SOC 2, HIPAA or PCI auditor asks for.
signed, verifiable offline. `/receipt-report` turns the chain into a
change-control report you can give a SOC 2, HIPAA or PCI auditor as
supporting evidence.

## Try it in 30 seconds

Expand Down
52 changes: 52 additions & 0 deletions tests/test_install_routing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""The README and the directory listing send installers to Claude Code.

This plugin runs in Claude Code, so the first thing a reader sees says
"Works in Claude Code" and gives the two commands that install it there, and every
install command in the README must point at this repo's own marketplace by the
names the manifests declare, so a copied command installs this plugin.
"""
import json
import re
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
REPO_SLUG = "Rmasood1122/commitproof" # the public repo users install from
PREFIX = "Works in Claude Code"

PLUGIN = json.loads((ROOT / ".claude-plugin" / "plugin.json").read_text(encoding="utf-8"))
MARKET = json.loads((ROOT / ".claude-plugin" / "marketplace.json").read_text(encoding="utf-8"))
README = (ROOT / "README.md").read_text(encoding="utf-8")
INSTALL = [f"/plugin marketplace add {REPO_SLUG}",
f"/plugin install {PLUGIN['name']}@{MARKET['name']}"]


def _block_after_first_line(lines):
"""Lines of the fenced code block that directly follows line 1 (blank lines allowed between)."""
i = 1
while i < len(lines) and not lines[i].strip():
i += 1
assert i < len(lines) and lines[i].startswith("```"), "line 1 must be followed by the install code block"
end = next((j for j in range(i + 1, len(lines)) if lines[j].startswith("```")), None)
assert end is not None, "the install block after line 1 is never closed"
return [l.strip() for l in lines[i + 1:end] if l.strip()]


def test_readme_opens_with_claude_code_and_its_install_commands():
lines = README.splitlines()
assert lines[0].startswith(PREFIX), lines[0]
assert _block_after_first_line(lines) == INSTALL


def test_listing_descriptions_lead_with_claude_code():
assert PLUGIN["description"].startswith(PREFIX)
for entry in MARKET["plugins"]:
assert entry["description"].startswith(PREFIX), entry["name"]


def test_every_readme_install_command_points_at_this_repo():
# whole tokens, so a URL source or an install without @marketplace can't slip past
adds = re.findall(r"marketplace add ([^\s`]+)", README)
installs = re.findall(r"plugin install ([^\s`]+)", README)
assert adds and installs
assert set(adds) == {REPO_SLUG}, adds
assert set(installs) == {f"{PLUGIN['name']}@{MARKET['name']}"}, installs
43 changes: 43 additions & 0 deletions tests/test_listing_readiness.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Directory-listing readiness: the manifest checks the plugin directory applies.

Mirrors the manifest part of eval-conductor's readiness battery, so a listing edit
(description, keywords, names) can't silently break what the directory accepts.
"""
import json
import re
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
PLUGIN = json.loads((ROOT / ".claude-plugin" / "plugin.json").read_text(encoding="utf-8"))
MARKET = json.loads((ROOT / ".claude-plugin" / "marketplace.json").read_text(encoding="utf-8"))


def test_name_is_kebab_case():
assert re.fullmatch(r"[a-z0-9]+(-[a-z0-9]+)*", PLUGIN["name"]), PLUGIN["name"]


def test_description_length_fits_the_directory():
assert 30 <= len(PLUGIN["description"]) <= 2000, len(PLUGIN["description"])
for entry in MARKET["plugins"]:
assert 30 <= len(entry.get("description", "")) <= 2000, entry["name"]


def test_keywords_are_a_nonempty_list_of_strings():
kw = PLUGIN.get("keywords")
assert isinstance(kw, list) and kw and all(isinstance(k, str) and k for k in kw), kw


def test_marketplace_lists_exactly_this_plugin():
assert [p["name"] for p in MARKET["plugins"]] == [PLUGIN["name"]]


def test_compliance_wording_offers_evidence_and_claims_no_requirement():
"""No SOC 2, HIPAA or PCI control requires AI-code provenance, so the README and
listing may offer the report as supporting evidence, never as what an auditor asks for."""
readme = (ROOT / "README.md").read_text(encoding="utf-8")
for text in (readme, PLUGIN["description"]):
lowered = text.lower()
for overclaim in ("auditor asks for", "auditors ask for", "required by soc", "soc 2 requires"):
assert overclaim not in lowered, overclaim
if "soc 2" in lowered:
assert "supporting evidence" in lowered, "SOC 2 mentioned without the supporting-evidence framing"
Loading