diff --git a/CHANGELOG.md b/CHANGELOG.md index acbe834..bd39144 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 3.0.0 + +- Added receipt-backed skill routing, delivery, task binding, browser enforcement, Kali auto-backend selection, proof-based finding review, and semantic anti-stuck enforcement. +- Replaced marker-file authorization with two-turn skill preparation and receipt diagnostics; legacy markers can only infer a unique session ID during migration. + ## 2.0.8 - Expanded Duck Store benchmark challenges from 14 to 20 article-parity vulnerabilities, matching Redpick's verified findings across 7 categories with correct severity distribution. diff --git a/README.md b/README.md index a6952a9..13c23f9 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,7 @@ python scripts/violin_guard.py check-release Validates the plugin manifest and registered tools, isolated Hermes-style plugin import, stale skill references, Ruff, and the full pytest suite. -Hermes skills are loaded on demand. Start the profile with `hermes chat --skills pentest` when the launcher supports arguments; otherwise load `pentest` immediately, then confirm the engagement marker with `python scripts/violin_guard.py status --eng-dir "$ENG_DIR" --section skill`. Hermes does not currently expose a distribution-level setting that can truthfully force-load a profile skill. +Hermes skills are loaded on demand and enforced by Violin receipts. Start with `pentest`, then use `violin_record_ptt` to select the route-required skill. The first call prepares its real `skill_view` content without mutating the PTT; repeat the same transition on the next turn to bind it. `violin_status` reports the route, binding, context generation, recovery action, and any obsolete legacy marker. Target and browser activity are blocked in both the delivery and binding turns. --- diff --git a/config.yaml b/config.yaml index 3264783..a0b110e 100644 --- a/config.yaml +++ b/config.yaml @@ -67,6 +67,9 @@ memory: flush_min_turns: 8 skills: + write_approval: true + guard_agent_created: true + creation_nudge_interval: 20 disabled: - airtable - architecture-diagram @@ -154,7 +157,7 @@ updates: backup_keep: 5 non_interactive_local_changes: stash -_config_version: 33 +_config_version: 34 session_reset: mode: both diff --git a/distribution.yaml b/distribution.yaml index 44b36f8..5447bb7 100644 --- a/distribution.yaml +++ b/distribution.yaml @@ -1,5 +1,5 @@ name: violin -version: 2.0.8 +version: 3.0.0 description: A supervised agentic Hermes penetration testing profile for authorised Kali/Parrot-based security assessment, reconnaissance, exploit validation, and reporting workflows. diff --git a/plugins/violin_guard/plugin.yaml b/plugins/violin_guard/plugin.yaml index e5fc6b9..74775b2 100644 --- a/plugins/violin_guard/plugin.yaml +++ b/plugins/violin_guard/plugin.yaml @@ -1,5 +1,5 @@ name: violin-guard -version: 2.0.8 +version: 3.0.0 description: Typed scope guards and an execute-and-record boundary with bounded synchronization windows. kind: standalone diff --git a/plugins/violin_guard/release.py b/plugins/violin_guard/release.py index ecfdc83..47e17a9 100644 --- a/plugins/violin_guard/release.py +++ b/plugins/violin_guard/release.py @@ -21,6 +21,7 @@ from dataclasses import dataclass from pathlib import Path from .results import GuardResult +from .skill_policy import catalog_snapshot, validate_catalog __all__ = [ "GuardResult", @@ -138,6 +139,28 @@ def check_release() -> ReleaseCheckResult: else: result.add_info("provides_tools matches registered tools") + # 3c. Checked-in external-skill dependency manifest is deterministic. + snapshot_path = root.parent.parent / "skills.snapshot.json" + catalog_errors = validate_catalog() + if catalog_errors: + result.errors.extend(catalog_errors) + elif not snapshot_path.exists(): + result.add_error("skills.snapshot.json not found") + else: + import json + + try: + checked_in = json.loads(snapshot_path.read_text(encoding="utf-8")) + expected = catalog_snapshot(root.parent.parent) + for entry in expected["skills"]: + entry.pop("path", None) + if checked_in != expected: + result.add_error("skills.snapshot.json does not match the approved skill catalog") + else: + result.add_info("external skill dependency snapshot matches catalog") + except (OSError, json.JSONDecodeError) as exc: + result.add_error(f"skills.snapshot.json is invalid: {exc}") + # 4. Heavy checks (ruff + pytest), opt-out via env. if os.environ.get("VIOLIN_CHECK_RELEASE_SKIP_HEAVY") != "1": repo_path = root.parent.parent diff --git a/pyproject.toml b/pyproject.toml index c647197..bcb7665 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "violin" -version = "2.0.6" +version = "3.0.0" description = "Supervised agentic Hermes penetration-testing profile" requires-python = ">=3.11" dependencies = ["filelock>=3.13,<4"] diff --git a/scripts/violin_guard.py b/scripts/violin_guard.py index 17f6630..72fb977 100644 --- a/scripts/violin_guard.py +++ b/scripts/violin_guard.py @@ -255,7 +255,7 @@ def main() -> int: p.add_argument("--host", default="") p.add_argument("--ctf", action="store_true", help="Create an HTB/CTF-ready scope and PTT") p.add_argument( - "--session-id", default="", help="Mark this session skill-loaded for CTF bootstrap" + "--session-id", default="", help="Record the Hermes session ID for receipt-backed CTF bootstrap" ) p.set_defaults(func=cmd_init_engagement) diff --git a/skills/access-control/SKILL.md b/skills/access-control/SKILL.md index 0a0d1bf..8f701cf 100644 --- a/skills/access-control/SKILL.md +++ b/skills/access-control/SKILL.md @@ -1,6 +1,6 @@ --- name: access-control -description: "Use when access-control vuln classes surface (authentication bypass, JWT attacks, IDOR). Load the matching playbook/ file for detection, token analysis, and evidence templates." +description: "Use when an authorized engagement's PTT or hypothesis identifies authentication bypass, JWT weakness, IDOR, or broken authorization. Select it through the Violin receipt flow, then load the matching playbook for controlled validation and evidence." version: 1.0.0 author: Violin license: MIT diff --git a/skills/pentest/SKILL.md b/skills/pentest/SKILL.md index 6fd6509..2a8935c 100644 --- a/skills/pentest/SKILL.md +++ b/skills/pentest/SKILL.md @@ -1,6 +1,6 @@ --- name: pentest -description: Supervised agentic penetration testing orchestrator — approved recon, vulnerability research, safe exploit validation, and reporting. Routes to per-vulnerability-class playbooks based on scoping and discovery. +description: Supervised authorized-pentest orchestrator for scoping, recon, research, safe validation, review, and reporting. Use at engagement start and whenever a PTT update selects the phase-routed skill; routes web injection and access-control work to focused sibling skills. version: 1.1.0 author: Violin license: MIT @@ -116,10 +116,10 @@ The phase workflow is mandatory for the entire session, including long, compress - `violin_heartbeat_done` clears the periodic review lock after re-reading this skill and reviewing engagement files. 0. **Bootstrap gate** — at session start, after `/goal set`, or after context compression that loses track of state, verify the engagement is bootstrapped: `python $HOME/.hermes/profiles/violin/scripts/violin_guard.py check-bootstrap --eng-dir "$ENG_DIR"`. Exit `0` = proceed. Exit `1` = **STOP and run `playbooks/scoping.md §0`** (creates `$ENG_DIR/`, `scope/scope.yaml`, `state/ptt.md`, `hypotheses.md`, `state/history.md`). Exit `2` = fix the warning, then proceed. This gate is non-negotiable: no `curl`, `nmap`, `browser_navigate`, or other target-touching tool call is allowed until exit 0. -0.1. **Skill-load gate** — launch with `hermes chat --skills pentest` when possible; otherwise load this skill immediately. After reading it, create `state/.skill-loaded-` containing `skill-loaded: `, then verify it with `status --eng-dir "$ENG_DIR" --section skill`. Missing marker = **BLOCK**. If the marker exists but belongs to another session, create the canonical marker for the current session and re-run the check; do not silently rely on a stale marker. CTF bootstrap creates it when `--session-id` is supplied. +0.1. **Skill receipt gate** — select the phase-routed skill through `violin_record_ptt`. The first transition returns real `skill_view` content and makes no PTT change; repeat it on the next model turn to bind the delivered receipt. `violin_status` reports binding readiness and recovery steps. Never create or rely on `.skill-loaded-*` markers: old markers are migration-only session hints, not authorization proof. 1. Check/update `todo` with a single active `phase-gate` item named for the current phase. 2. Confirm an approved `$ENG_DIR/scope/scope.yaml` exists before touching any target. If it does not, remain in SCOPING and ask via `clarify`. Verify with `python $HOME/.hermes/profiles/violin/scripts/violin_guard.py validate-scope --scope $ENG_DIR/scope/scope.yaml` (exit 0 required). - For an authorized HTB/CTF lab, `init-engagement --ctf --host --session-id "$ENG_DIR"` creates a ready-to-test scope, active RECON PTT row, and skill marker. + For an authorized HTB/CTF lab, `init-engagement --ctf --host --session-id "$ENG_DIR"` creates a ready-to-test scope and active RECON PTT row; prepare and bind the routed skill before target activity. 3. **Read and activate the PTT task** — `read_file path="$ENG_DIR/state/ptt.md"` — and select the next open `[ ]` task for the current phase. Before any target command, mark exactly one task `[~]`: ```bash python $HOME/.hermes/profiles/violin/scripts/violin_guard.py record-ptt --eng-dir "$ENG_DIR" --id PT-XXX --status "[~]" --note "starting task" diff --git a/skills/pentest/playbooks/scoping.md b/skills/pentest/playbooks/scoping.md index 5887299..96af0a3 100644 --- a/skills/pentest/playbooks/scoping.md +++ b/skills/pentest/playbooks/scoping.md @@ -30,7 +30,7 @@ ENG_ROOT="$(python3 scripts/violin_guard.py eng-root | sed -n 's/^ENG_ROOT=//p') ENG_DIR="$ENG_ROOT/engagements/-$(date +%F)" python3 scripts/violin_guard.py init-engagement --host "$ENG_DIR" -# Authorized HTB/CTF lab: ready-to-test scope, active RECON task, and skill marker. +# Authorized HTB/CTF lab: ready-to-test scope and active RECON task. # python3 scripts/violin_guard.py init-engagement --ctf --session-id htb1 --host "$ENG_DIR" ``` diff --git a/skills/web-attacks/SKILL.md b/skills/web-attacks/SKILL.md index 025bb43..218e1ea 100644 --- a/skills/web-attacks/SKILL.md +++ b/skills/web-attacks/SKILL.md @@ -1,6 +1,6 @@ --- name: web-attacks -description: "Use when web-application injection vuln classes surface (SQLi, XSS, command injection, SSRF, path traversal). Load the matching playbook/ file for detection, payloads, and evidence templates." +description: "Use when an authorized engagement's PTT or hypothesis identifies web injection: SQLi, XSS, command injection, SSRF, or path traversal. Select it through the Violin receipt flow, then load only the matching playbook for safe validation and evidence." version: 1.0.0 author: Violin license: MIT diff --git a/uv.lock b/uv.lock index 1b680f2..a109d78 100644 --- a/uv.lock +++ b/uv.lock @@ -154,7 +154,7 @@ wheels = [ [[package]] name = "violin" -version = "2.0.6" +version = "3.0.0" source = { virtual = "." } dependencies = [ { name = "filelock" },