From 06c404084d933f8481b842be5a7ca233dd22dd35 Mon Sep 17 00:00:00 2001 From: thanhnv Date: Tue, 18 Aug 2026 16:26:27 +0700 Subject: [PATCH] feat(casan): add native plugin facade --- .claude-plugin/marketplace.json | 37 +++++++++ .claude-plugin/plugin.json | 20 +++++ .codex-plugin/plugin.json | 30 ++++++++ .gitea/workflows/ci.yml | 3 + .github/workflows/ci.yml | 2 + README.md | 29 +++++++ docs/packaging/CASAN_PACKAGING_PLAN.md | 11 ++- .../tests/hybrid-install-tests.sh | 4 + .../casan-devkit/tests/native-plugin-tests.py | 76 +++++++++++++++++++ packaging/levels.json | 5 +- scripts/smoke-release-artifact.sh | 12 ++- skills/casan/SKILL.md | 58 ++++++++++++++ skills/casan/agents/openai.yaml | 4 + 13 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 .claude-plugin/marketplace.json create mode 100644 .claude-plugin/plugin.json create mode 100644 .codex-plugin/plugin.json create mode 100644 packages/casan-devkit/tests/native-plugin-tests.py create mode 100644 skills/casan/SKILL.md create mode 100644 skills/casan/agents/openai.yaml diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 0000000..695fad9 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,37 @@ +{ + "name": "casan", + "owner": { + "name": "CASAN Team" + }, + "metadata": { + "description": "Native operator facade for the CASAN governed AI coding assurance runtime" + }, + "plugins": [ + { + "name": "casan", + "source": "./", + "description": "Adopt, diagnose, verify, and operate CASAN from Claude Code without bypassing project-local hook trust or runtime integrity controls.", + "version": "1.0.7", + "author": { + "name": "CASAN Team" + }, + "license": "Proprietary", + "keywords": [ + "agentic-coding", + "assurance", + "governance", + "security", + "audit" + ], + "category": "workflow", + "tags": [ + "agentic-coding", + "assurance", + "governance", + "security", + "audit" + ], + "strict": true + } + ] +} diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..00736d7 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,20 @@ +{ + "name": "casan", + "version": "1.0.7", + "description": "Native Claude Code operator facade for the CASAN governed AI coding assurance runtime.", + "author": { + "name": "CASAN Team" + }, + "license": "Proprietary", + "keywords": [ + "claude-code", + "agentic-coding", + "assurance", + "governance", + "security", + "audit" + ], + "skills": [ + "./skills/" + ] +} diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json new file mode 100644 index 0000000..fa37684 --- /dev/null +++ b/.codex-plugin/plugin.json @@ -0,0 +1,30 @@ +{ + "name": "casan", + "version": "1.0.7", + "description": "Native Codex operator facade for the CASAN governed AI coding assurance runtime.", + "author": { + "name": "CASAN Team" + }, + "license": "Proprietary", + "keywords": [ + "agentic-coding", + "assurance", + "governance", + "security", + "audit" + ], + "skills": "./skills/", + "interface": { + "displayName": "CASAN", + "shortDescription": "Governed AI coding assurance", + "longDescription": "Adopt, diagnose, verify, and operate the CASAN assurance runtime from Codex while preserving project-local hook trust and the versioned shared runtime.", + "developerName": "CASAN Team", + "category": "Developer Tools", + "capabilities": [ + "Project adoption", + "Assurance verification", + "Governed execution" + ], + "defaultPrompt": "Use $casan to adopt and verify CASAN in this project." + } +} diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index d099c8f..62f20d9 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -102,6 +102,9 @@ jobs: - name: Prove managed and vendored Core adoption run: bash packages/casan-devkit/tests/hybrid-install-tests.sh + - name: Validate native Codex and Claude plugin facades + run: python3 packages/casan-devkit/tests/native-plugin-tests.py + - name: Run adversarial harness tests (44 tests) run: bash packages/casan-harness/tests/adversarial-harness-tests.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59bbe79..005f26a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,6 +56,8 @@ jobs: node-version: "20" cache: npm - run: npm ci + - name: Validate native Codex and Claude plugin facades + run: python3 packages/casan-devkit/tests/native-plugin-tests.py - name: Run reusable governance suites env: CASAN_CI_RUN_PROJECT: "0" diff --git a/README.md b/README.md index 0b8785c..c904f1c 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,33 @@ multi-project, RBAC tập trung, approvals và fleet operations. - Windows: PowerShell 5.1+, Python 3 và Git for Windows/Git Bash. - Client tương ứng nếu cần: Claude Code, Codex hoặc VS Code. +### Native plugin façade — tùy chọn + +Repository root đồng thời là marketplace source cho Codex và Claude Code. Plugin +chỉ cung cấp skill `$casan` để agent biết cách adopt, diagnose và verify CASAN; +nó **không** tự bật hook, không tự cài runtime và không thay thế bước trust của +client. + +Từ một checkout đã được tổ chức phê duyệt: + +```bash +# Codex +codex plugin marketplace add /absolute/path/to/CASAN +codex plugin add casan@casan +``` + +Trong Claude Code: + +```text +/plugin marketplace add /absolute/path/to/CASAN +/plugin install casan@casan +``` + +Sau khi cài plugin, mở session mới và gọi `$casan`. Runtime production vẫn được +cài một lần bằng `install.sh`/`install.ps1`, sau đó mỗi repository phải chạy +`casan init`. Không cài chồng native plugin và một bản skill copy thủ công vào +cùng client. + ### 1. Cài DevKit một lần trên máy Từ checkout hoặc release bundle đã được duyệt: @@ -611,6 +638,8 @@ Dùng explicit route `@casan ` và kiểm tra | Path | Trách nhiệm | |---|---| +| `.codex-plugin/`, `.claude-plugin/` | Native marketplace manifests; không tự bật enforcement | +| `skills/casan/` | Operator skill façade dùng chung cho Codex và Claude Code | | `bin/casan` | CLI entrypoint | | `install.sh`, `install.ps1` | Global installers | | `packages/casan-harness/` | Runtime controls, adapters, policies, evidence và source tests | diff --git a/docs/packaging/CASAN_PACKAGING_PLAN.md b/docs/packaging/CASAN_PACKAGING_PLAN.md index 5abcc78..5585342 100644 --- a/docs/packaging/CASAN_PACKAGING_PLAN.md +++ b/docs/packaging/CASAN_PACKAGING_PLAN.md @@ -9,7 +9,7 @@ contents + maturity: [`packaging/levels.json`](../../packaging/levels.json). | Edition | Package names | Status | What it is | |---|---|:--:|---| -| **1 — Core Harness** | `casan-core`, `casan-harness` | ✅ implemented | Minimal H1–H7 production runtime plus zero-dependency Local Assurance Viewer: latest/history, interactive H1–H7, H6 and on-demand export | +| **1 — Core Harness** | `casan-core`, `casan-harness` | ✅ implemented | Minimal H1–H7 production runtime, native Codex/Claude operator façade, plus zero-dependency Local Assurance Viewer: latest/history, interactive H1–H7, H6 and on-demand export | | **2 — DevKit / Adoption Kit** | `casan-devkit`, `casan-project-kit` | ✅ implemented | Level 1 + project templates, domain-pack scaffold, Gitea workflow template, harness Dockerfile, install script, adoption/CI/domain-pack guides | | **3 — Platform Components** | `casan-platform`, `casan-control-panel` | 🟡 preview | Control Panel, Dashboard, Run History, governed chat MVP and **Evidence Pack Viewer**. Attack Battery Viewer, Gitea evidence publishing, and managed rollout are still pending. | | **4 — Enterprise / Governed Console** | `casan-enterprise`, `casan-governed-console` | 📋 future | Promotion layer requiring managed deployment, KMS/Object Lock operations, HA/DR/SLA, external review and compliance/support evidence. | @@ -42,6 +42,12 @@ Docker images (see `DOCKER_GUIDE.md`): `casan-harness:X.Y.Z` ✅ · `casan-platf Every bundle carries `BUNDLE-MANIFEST.txt` + `SHA256SUMS`; preview bundles also carry `PREVIEW-INCOMPLETE.txt`. +Core and every cumulative bundle also carry `.codex-plugin/`, `.claude-plugin/` +and `skills/casan/`. These files expose an optional native `$casan` operator +surface. They do not install the shared runtime or enable project hooks; the +production trust path remains global/vendored runtime installation followed by +`casan init` and client hook review. + ## Production runtime boundary `packaging/runtime-layout.json` is the canonical allowlist used by macOS/Linux, @@ -77,6 +83,9 @@ packages/casan-harness/ # L1 core (implemented) packages/casan-devkit/ # L2 adoption kit (implemented) packages/casan-platform/ # L3 structure-only (preview; README) packages/casan-enterprise/ # L4 structure-only (future; README) +skills/casan/ # native operator skill shared by Codex + Claude +.codex-plugin/ # Codex plugin manifest +.claude-plugin/ # Claude plugin + marketplace manifests bin/casan # CLI scripts/package-release.sh # release packager packaging/levels.json # bundle contents + maturity (source of truth) diff --git a/packages/casan-devkit/tests/hybrid-install-tests.sh b/packages/casan-devkit/tests/hybrid-install-tests.sh index bcc598d..29e033f 100755 --- a/packages/casan-devkit/tests/hybrid-install-tests.sh +++ b/packages/casan-devkit/tests/hybrid-install-tests.sh @@ -70,6 +70,10 @@ for forbidden in ( ): assert not (root / forbidden).exists(), forbidden for required in ( + ".codex-plugin/plugin.json", + ".claude-plugin/plugin.json", + ".claude-plugin/marketplace.json", + "skills/casan/SKILL.md", "packages/casan-harness/assets/local-viewer/index.html", "packages/casan-harness/assets/local-viewer/app.css", "packages/casan-harness/assets/local-viewer/app.js", diff --git a/packages/casan-devkit/tests/native-plugin-tests.py b/packages/casan-devkit/tests/native-plugin-tests.py new file mode 100644 index 0000000..484ea48 --- /dev/null +++ b/packages/casan-devkit/tests/native-plugin-tests.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +"""Validate the repository-root CASAN native plugin facades.""" + +from __future__ import annotations + +import json +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[3] +VERSION = (ROOT / "VERSION").read_text(encoding="utf-8").strip() + + +def load_json(relative_path: str) -> dict[str, object]: + payload = json.loads((ROOT / relative_path).read_text(encoding="utf-8")) + assert isinstance(payload, dict), relative_path + return payload + + +def main() -> None: + codex = load_json(".codex-plugin/plugin.json") + assert codex["name"] == "casan" + assert codex["version"] == VERSION + assert codex["skills"] == "./skills/" + assert "hooks" not in codex + assert codex["license"] == "Proprietary" + + interface = codex["interface"] + assert isinstance(interface, dict) + for field in ( + "displayName", + "shortDescription", + "longDescription", + "developerName", + "category", + "capabilities", + "defaultPrompt", + ): + assert interface.get(field), field + + claude = load_json(".claude-plugin/plugin.json") + assert claude["name"] == "casan" + assert claude["version"] == VERSION + assert claude["skills"] == ["./skills/"] + assert "hooks" not in claude + + marketplace = load_json(".claude-plugin/marketplace.json") + plugins = marketplace["plugins"] + assert isinstance(plugins, list) and len(plugins) == 1 + entry = plugins[0] + assert isinstance(entry, dict) + assert entry["name"] == "casan" + assert entry["source"] == "./" + assert entry["version"] == VERSION + + skill = (ROOT / "skills/casan/SKILL.md").read_text(encoding="utf-8") + assert skill.startswith("---\nname: casan\n") + assert "description:" in skill + assert "[TODO:" not in skill + assert (ROOT / "skills/casan/agents/openai.yaml").is_file() + + levels = load_json("packaging/levels.json") + level_map = levels["levels"] + assert isinstance(level_map, dict) + core = level_map["core"] + assert isinstance(core, dict) + includes = core["includes"] + assert isinstance(includes, list) + for required in (".codex-plugin", ".claude-plugin", "skills"): + assert required in includes, required + + print(f"NATIVE_PLUGIN_PASS version={VERSION} codex=true claude=true") + + +if __name__ == "__main__": + main() diff --git a/packaging/levels.json b/packaging/levels.json index f2c367c..3b3d2cf 100644 --- a/packaging/levels.json +++ b/packaging/levels.json @@ -7,9 +7,12 @@ "level": 1, "package_names": ["casan-core", "casan-harness"], "status": "implemented", - "summary": "Minimal H1-H7 production runtime: security/action gates, evidence pack, audit, cost/telemetry, policy/config defaults, adapters, lightweight CLI, three-dimensional commercial readiness, and a zero-dependency single-project Local Assurance Viewer with H1-H7, H6, history and on-demand export. Source-only tests and Platform helpers are excluded.", + "summary": "Minimal H1-H7 production runtime: security/action gates, evidence pack, audit, cost/telemetry, policy/config defaults, adapters, lightweight CLI, native Codex/Claude operator facade, three-dimensional commercial readiness, and a zero-dependency single-project Local Assurance Viewer with H1-H7, H6, history and on-demand export. Source-only tests and Platform helpers are excluded.", "target_users": ["governance-harness-only projects", "BJT initial adoption", "CI gate usage"], "includes": [ + ".codex-plugin", + ".claude-plugin", + "skills", "packages/casan-harness", "bin/casan", "install.sh", diff --git a/scripts/smoke-release-artifact.sh b/scripts/smoke-release-artifact.sh index 1c41477..72396d3 100755 --- a/scripts/smoke-release-artifact.sh +++ b/scripts/smoke-release-artifact.sh @@ -29,7 +29,17 @@ done < <(find "$WORK" -mindepth 1 -maxdepth 1 -type d -print) } ROOT="${roots[0]}" -required=(BUNDLE-MANIFEST.txt SHA256SUMS VERSION bin/casan packages/casan-harness) +required=( + BUNDLE-MANIFEST.txt + SHA256SUMS + VERSION + bin/casan + packages/casan-harness + .codex-plugin/plugin.json + .claude-plugin/plugin.json + .claude-plugin/marketplace.json + skills/casan/SKILL.md +) for path in "${required[@]}"; do [[ -e "$ROOT/$path" ]] || { echo "ARTIFACT_SMOKE_FAIL reason=required_path_missing path=$path" >&2 diff --git a/skills/casan/SKILL.md b/skills/casan/SKILL.md new file mode 100644 index 0000000..ebf8300 --- /dev/null +++ b/skills/casan/SKILL.md @@ -0,0 +1,58 @@ +--- +name: casan +description: Operate the CASAN governed AI coding assurance runtime. Use when adopting CASAN into a repository, configuring Claude Code or Codex hooks, checking readiness or runtime integrity, running governance gates, inspecting assurance reports, exporting evidence, or diagnosing CASAN installation and enforcement problems. +--- + +# CASAN + +Use the installed CASAN CLI as the only operational entry point. This skill is +an operator facade; it does not duplicate the assurance kernel and installing +the plugin alone does not enable enforcement. + +## Resolve the runtime + +1. Work from the target repository root. +2. Resolve `casan` with `command -v casan`. +3. If it is unavailable, report that the DevKit runtime must be installed. Do + not install into the user's home directory unless the user explicitly asks. +4. If the current checkout is the CASAN source hub and installation is + requested, use `sh install.sh --level devkit` on macOS/Linux or + `pwsh ./install.ps1` on Windows. +5. Never treat plugin registration as proof that project hooks or enforcement + are active. + +## Route the request + +- Adopt or reconfigure a repository: run `casan init`. Preserve an existing + runtime and enforcement choice unless the user explicitly changes it. +- Configure automation: run `casan init --non-interactive --edition core + --runtime managed --mode enforce --client claude,codex` and adjust only the + options the user requested. +- Diagnose an installation or project: run `casan doctor`, then + `casan readiness --refresh` and `casan verify-harness` as needed. +- Verify governance: run `casan gate` for project checks and `casan verify` for + audit, tool, and policy verification. +- Inspect evidence: use `casan report latest`, `casan view`, or + `casan report export` according to the requested output. +- Inspect the product selection: use `casan edition show`. Do not equate an + installed edition with CASAN Maturity L1-L5. + +## Preserve the trust boundary + +- Check `.casan/config.json`, `.casan/version.lock`, and the selected client + hook projection before claiming CASAN is active. +- Require the user to review and trust native client hooks where the client + exposes a trust step. +- Never edit `version.lock` to suppress integrity drift. Restore or reinstall + the approved runtime and rerun `casan verify-harness`. +- Never silently change `observe` to `enforce`, switch managed/vendored mode, + or enable additional client integrations. +- Keep generated evidence and state in the target project. Do not write runtime + state into the plugin cache or global version directory. + +## Report results + +State the resolved runtime, project edition, enforcement mode, configured +clients, commands run, and any failing assurance control. Distinguish a missing +optional Domain Pipeline or provider telemetry integration from a failed Core +assurance control. diff --git a/skills/casan/agents/openai.yaml b/skills/casan/agents/openai.yaml new file mode 100644 index 0000000..186793b --- /dev/null +++ b/skills/casan/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "CASAN" + short_description: "Governed AI coding with CASAN assurance" + default_prompt: "Use $casan to adopt and verify CASAN in this project."