feat(packaging): level-based source hub — Core + DevKit packaging, Platform/Enterprise scaffold
Organize CASAN as a reusable source hub with SPLIT releases so downstream adopts only the level it needs (packaging/levels.json is the single source of truth). Implemented now: - Level 1 Core: bin/casan CLI (run/gate/test/verify/reuse/dashboard) + VERSION. - Level 2 DevKit: packages/casan-devkit (install.sh, Dockerfile.harness, templates: project scaffold, domain-pack, gitea-workflow). - scripts/package-release.sh core|devkit|platform|all-in-one-demo — builds split bundles into dist/ (BUNDLE-MANIFEST + SHA256SUMS); platform is stamped PREVIEW/INCOMPLETE; enterprise (future) is REFUSED (exit 3, no fake-complete package). Bundles verified: extract → bin/casan works, deterministic + domain suites pass, casan reuse VALID. - docs/packaging: CASAN_PACKAGING_PLAN + ADOPTION + CI + DOMAIN_PACK + GITEA_PACKAGE + DOCKER. Structure + docs only: - Level 3 packages/casan-platform (dashboard exists; control-panel/viewers pending). - Level 4 packages/casan-enterprise (RBAC/tenant/KMS/WORM/approval exist in core; governed console pending). No Chat Console/RBAC-console/tenant-console/model-mgmt built in this task. Harness change (enables extracted bundles to self-resolve): casan-paths.sh + the Python project_root() walk-ups now accept a second root marker `packages/casan-harness` in addition to `.specify`, so a freshly-unpacked core/devkit/demo bundle (no `.specify` yet) roots correctly and creates state on first run. In an adopted repo `.specify` still matches first. policy-bundle.yaml paths corrected to packages/casan-harness (re-signed). Full gate 64/0/3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
4918012199
commit
8c20cfde9f
@@ -0,0 +1,55 @@
|
||||
# CASAN Adoption Guide
|
||||
|
||||
How a downstream project adopts the CASAN governance harness. Adoption is **config +
|
||||
domain only** — you never edit gate logic (H1→H7).
|
||||
|
||||
## Option A — DevKit install (recommended)
|
||||
From a CASAN source hub or an extracted `casan-devkit` bundle:
|
||||
```bash
|
||||
packages/casan-devkit/install.sh --target ../my-project --project ticketing --domain "Ticketing"
|
||||
```
|
||||
This copies the core harness + `bin/casan` into `../my-project`, scaffolds
|
||||
`apps/ticketing/domain/` from the domain-pack template, adds `.gitea/workflows/casan-ci.yml`,
|
||||
and registers the project in `project-registry.json`.
|
||||
|
||||
## Option B — Core tarball (harness-only / CI gate)
|
||||
```bash
|
||||
tar -xzf casan-core-v1.0.0.tar.gz
|
||||
cp -R casan-core-v1.0.0/{packages,bin,VERSION} /path/to/project/
|
||||
```
|
||||
Then create `apps/<project>/domain/` yourself (see `DOMAIN_PACK_GUIDE.md`).
|
||||
|
||||
## Option C — Docker (no install into repo)
|
||||
```bash
|
||||
docker run --rm -v "$PWD":/workspace -w /workspace casan-harness:1.0.0 casan gate
|
||||
```
|
||||
See `DOCKER_GUIDE.md`.
|
||||
|
||||
## After install
|
||||
1. Requirement → `apps/<project>/domain/input/requirement.md` (keep the `| FR-xx |` table).
|
||||
2. Golden baseline → `apps/<project>/domain/golden-runs/<artifact>.golden.txt`.
|
||||
3. Corpus → `apps/<project>/domain/corpus/` (redteam + benign) for H4 scoring.
|
||||
4. Requirement→code→test map → `apps/<project>/domain/traceability-map.json`.
|
||||
5. Run:
|
||||
```bash
|
||||
CASAN_DOMAIN_ROOT=apps/<project>/domain bin/casan gate # full governance gate
|
||||
bin/casan run in.txt out.txt my_step -- <command> # one governed step
|
||||
bin/casan reuse # HARNESS_REUSE_VALID
|
||||
```
|
||||
|
||||
## Path model (what lives where)
|
||||
- **Harness code** → `packages/casan-harness/` (never edited by adopters).
|
||||
- **Your domain data** → `apps/<project>/domain/` (via `CASAN_DOMAIN_ROOT`).
|
||||
- **Runtime state** → `.specify/` (logs, audit, governance — created on first run).
|
||||
Paths resolve via `packages/casan-harness/scripts/bash/casan-paths.sh` (marker walk-up:
|
||||
`.specify` or `packages/casan-harness`), so a freshly-extracted bundle works immediately.
|
||||
|
||||
## Proving reuse
|
||||
Two+ projects sharing the same harness package/version → `bin/casan reuse` prints
|
||||
`HARNESS_REUSE_VALID ... project_count=N`. This is the evidence that the harness is genuinely
|
||||
reusable, not copy-pasted. See `docs/plans/CASAN_PLAN_06_ONBOARD.md`.
|
||||
|
||||
## Upgrading
|
||||
Re-run `install.sh` from a newer DevKit (or re-extract a newer core tarball). Your
|
||||
`apps/<project>/domain/` and `.specify/` state are untouched — only `packages/casan-harness/`
|
||||
+ `bin/casan` are replaced. Keep `harness_version` aligned across projects for reuse to count.
|
||||
@@ -0,0 +1,67 @@
|
||||
# CASAN Packaging Plan — Level-Based Source Hub
|
||||
|
||||
CASAN is **not** packaged as "core only". This repository is a **reusable source hub** that
|
||||
holds (or scaffolds) all major CASAN components, and **releases are split by level** so a
|
||||
downstream project adopts only the level it needs. Single source of truth for bundle
|
||||
contents + maturity: [`packaging/levels.json`](../../packaging/levels.json).
|
||||
|
||||
## The four levels
|
||||
|
||||
| Lvl | Package names | Status | What it is |
|
||||
|---|---|:--:|---|
|
||||
| **1 — Core Harness** | `casan-core`, `casan-harness` | ✅ implemented | H1–H7 harness, security + action gates, evidence pack, audit, cost/telemetry, hardening tests, policy/config defaults, `bin/casan` CLI |
|
||||
| **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, Evidence/Attack/Run-History viewers, read-only Ask CASAN, Gitea webhook. **Only the AgentOps dashboard exists today.** |
|
||||
| **4 — Enterprise / Governed Console** | `casan-enterprise`, `casan-governed-console` | 📋 future | Governed Chat Console, Prompt Router, Model-Provider Mgmt, Operator/Codegen modes, Agent/Skill Registry, RBAC, approval, tenant isolation, KMS/WORM, policy versioning |
|
||||
|
||||
Levels are cumulative: DevKit extends Core, Platform extends DevKit, Enterprise extends
|
||||
Platform.
|
||||
|
||||
## Packaging principle
|
||||
The source hub may contain all levels, **but releases must be split**. Do NOT force a
|
||||
downstream project to install everything. A level that is not implemented must **fail
|
||||
clearly** or be stamped **PREVIEW/INCOMPLETE** — never a fake-complete package.
|
||||
|
||||
## Release artifacts
|
||||
Built by [`scripts/package-release.sh`](../../scripts/package-release.sh) into `dist/`:
|
||||
|
||||
| Command | Artifact | Status |
|
||||
|---|---|:--:|
|
||||
| `package-release.sh core` | `casan-core-vX.Y.Z.tar.gz` | ✅ builds |
|
||||
| `package-release.sh devkit` | `casan-devkit-vX.Y.Z.tar.gz` | ✅ builds |
|
||||
| `package-release.sh platform` | `casan-platform-preview-vX.Y.Z.tar.gz` | 🟡 preview (stamped) |
|
||||
| `package-release.sh all-in-one-demo` | `casan-all-in-one-demo-vX.Y.Z.tar.gz` | ✅ builds (full runnable snapshot) |
|
||||
| `package-release.sh enterprise` | — | 📋 refused (exit 3, future) |
|
||||
|
||||
Docker images (see `DOCKER_GUIDE.md`): `casan-harness:X.Y.Z` ✅ · `casan-platform:X.Y.Z` 🟡 preview · `casan-enterprise:X.Y.Z` 📋 future.
|
||||
|
||||
Every bundle carries `BUNDLE-MANIFEST.txt` + `SHA256SUMS`; preview bundles also carry
|
||||
`PREVIEW-INCOMPLETE.txt`.
|
||||
|
||||
## Who adopts what
|
||||
- **Governance-harness-only / BJT initial / CI gate** → `casan-core`.
|
||||
- **New project adopting CASAN** → `casan-devkit` (install.sh scaffolds domain + CI).
|
||||
- **Want dashboards/visibility** → `casan-platform` (preview; dashboard today).
|
||||
- **Enterprise governed console** → future; building blocks (RBAC/tenant/KMS/WORM/approval)
|
||||
already live in core.
|
||||
|
||||
## Repository map
|
||||
```
|
||||
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)
|
||||
bin/casan # CLI
|
||||
scripts/package-release.sh # release packager
|
||||
packaging/levels.json # bundle contents + maturity (source of truth)
|
||||
docs/packaging/ # this plan + adoption/CI/domain-pack/gitea/docker guides
|
||||
```
|
||||
|
||||
## Implemented now vs future
|
||||
- **Implemented now:** Level 1 Core packaging, Level 2 DevKit packaging, release script,
|
||||
`bin/casan`, templates, docs, all-in-one-demo bundle.
|
||||
- **Structure + docs only:** Level 3 Platform (dashboard exists; rest scaffolded),
|
||||
Level 4 Enterprise (RBAC/tenant/KMS/WORM/approval exist in core; governed console not built).
|
||||
- **Not built in this task (do not assume present):** Governed Chat Console, Prompt Mode
|
||||
Router, Model Provider Management, Operator/Codegen modes, Agent/Skill Registry, RBAC/
|
||||
tenant *console* UX.
|
||||
@@ -0,0 +1,47 @@
|
||||
# CASAN CI Guide (Gitea Actions)
|
||||
|
||||
Wire the CASAN governance gate into your project's CI so every push/PR is governed.
|
||||
|
||||
## 1. Add the workflow
|
||||
DevKit `install.sh` already drops `.gitea/workflows/casan-ci.yml`. To add manually, copy the
|
||||
template:
|
||||
```bash
|
||||
cp packages/casan-devkit/templates/gitea-workflow/ci.yml .gitea/workflows/casan-ci.yml
|
||||
```
|
||||
|
||||
## 2. What it runs
|
||||
```yaml
|
||||
- bash packages/casan-harness/scripts/bash/ci-harness-gate.sh # all governance suites
|
||||
- bash packages/casan-harness/scripts/bash/verify-audit-chain.sh
|
||||
- bash packages/casan-harness/scripts/bash/sign-policy-bundle.sh verify
|
||||
```
|
||||
|
||||
## 3. Environment knobs
|
||||
| Var | Default | Use |
|
||||
|---|---|---|
|
||||
| `CASAN_CI_RUN_FRONTEND` | 0 | 1 if you have a frontend workspace |
|
||||
| `CASAN_CI_RUN_BACKEND` | 0 | 1 to run backend tests |
|
||||
| `CASAN_CI_RUN_INFRA_LAB` | 0 | 1 to run the Docker infra lab |
|
||||
| `CASAN_CI_STEP_TIMEOUT_SEC` | 600 | raise to 1200 — some suites are model-backed and run ~450s; 600 flakes under load |
|
||||
| `CASAN_CI_SUITE_FILTER` | — | regex to run a subset of suites |
|
||||
| `CASAN_DOMAIN_ROOT` | apps/okr/domain | point at your project's domain |
|
||||
|
||||
## 4. Runner
|
||||
Uses `runs-on: ci-runner` (a self-hosted Gitea Actions runner). To set one up on your host,
|
||||
see `.gitea/vps-setup-runbook.md` and `scripts/setup-ci-runner.sh`. The runner needs
|
||||
`bash`, `python3`, `openssl` (and `node`/`npm` only if you enable frontend/backend tests).
|
||||
|
||||
## 5. Expected result
|
||||
`CI_GATE_SUMMARY PASS=<n> FAIL=0 SKIP=<k>`. Any FAIL fails the job (exit 1). The gate is
|
||||
**fail-closed**: missing signatures/policy in enforced mode (`CASAN_PROFILE=prod` or
|
||||
`CASAN_VERIFY_STRICT=1`) also fail.
|
||||
|
||||
## 6. This repo's own CI
|
||||
The source hub's active pipeline is `.gitea/workflows/ci.yml` (frontend tests → security
|
||||
gate → deploy). It already runs the gate from the promoted root layout
|
||||
(`packages/casan-harness/...`). Use it as a worked example.
|
||||
|
||||
## Tips
|
||||
- Keep the gate green as an invariant; every new control must ship a fail-able adversarial test.
|
||||
- Do not stage runtime log artifacts (`.specify/logs`, evidence) produced by gate runs.
|
||||
- For a quick local pre-push check: `bin/casan gate` (or a filtered subset).
|
||||
@@ -0,0 +1,50 @@
|
||||
# CASAN Docker Guide
|
||||
|
||||
Run the CASAN governance harness as a container against any mounted repo — no install into
|
||||
the target project.
|
||||
|
||||
## Image: `casan-harness` (Level 1/2)
|
||||
Dockerfile: [`packages/casan-devkit/Dockerfile.harness`](../../packages/casan-devkit/Dockerfile.harness).
|
||||
Minimal Debian + bash + python3 + openssl + git. Ships the core harness + `bin/casan`.
|
||||
|
||||
### Build
|
||||
```bash
|
||||
V=$(cat VERSION)
|
||||
docker build -f packages/casan-devkit/Dockerfile.harness -t casan-harness:$V .
|
||||
```
|
||||
|
||||
### Run the gate on a project
|
||||
```bash
|
||||
docker run --rm -v "$PWD":/workspace -w /workspace casan-harness:1.0.0 gate
|
||||
# (ENTRYPOINT is `casan`, so the CMD is a casan subcommand)
|
||||
docker run --rm -v "$PWD":/workspace casan-harness:1.0.0 reuse
|
||||
docker run --rm -v "$PWD":/workspace casan-harness:1.0.0 \
|
||||
run in.txt out.txt my_step -- echo hello
|
||||
```
|
||||
The harness inside the image lives at `/opt/casan` (`CASAN_HARNESS_ROOT` preset); your
|
||||
project is mounted at `/workspace`. Domain data is read from the mounted repo
|
||||
(`apps/<project>/domain` via `CASAN_DOMAIN_ROOT`).
|
||||
|
||||
### With a domain root
|
||||
```bash
|
||||
docker run --rm -v "$PWD":/workspace -w /workspace \
|
||||
-e CASAN_DOMAIN_ROOT=apps/ticketing/domain casan-harness:1.0.0 gate
|
||||
```
|
||||
|
||||
## Notes
|
||||
- **State** (`.specify/logs`, audit) is written under `/workspace` (your mounted repo), so it
|
||||
persists on the host and is inspectable after the run.
|
||||
- **Enforced mode:** add `-e CASAN_PROFILE=prod` (or `-e CASAN_VERIFY_STRICT=1`) to make
|
||||
missing signatures fail-closed.
|
||||
- **No app runtime:** this image runs the *harness*, not the OKR app. For the app, use the
|
||||
project's own `Dockerfile.backend` / `Dockerfile.frontend` + `docker-compose.prod.yml`.
|
||||
|
||||
## Other images
|
||||
| Image | Status | Notes |
|
||||
|---|:--:|---|
|
||||
| `casan-harness:X.Y.Z` | ✅ | this guide |
|
||||
| `casan-platform:X.Y.Z` | 🟡 preview | dashboard only today; build from platform preview when needed |
|
||||
| `casan-enterprise:X.Y.Z` | 📋 future | not built — governed console does not exist yet |
|
||||
|
||||
## Publish to Gitea container registry
|
||||
See `GITEA_PACKAGE_GUIDE.md` §3 (`docker login` + `docker push` to the Gitea registry).
|
||||
@@ -0,0 +1,52 @@
|
||||
# CASAN Domain Pack Guide
|
||||
|
||||
A **Domain Pack** is the per-project data the harness needs to govern YOUR domain. It lives
|
||||
at `apps/<project>/domain/` and is selected via `CASAN_DOMAIN_ROOT`. The harness code
|
||||
(`packages/casan-harness/`) never contains domain data — this is what makes it reusable.
|
||||
|
||||
Scaffold template: `packages/casan-devkit/templates/domain-pack/`.
|
||||
|
||||
## Layout
|
||||
```
|
||||
apps/<project>/domain/
|
||||
├── domain-pack.yaml # manifest describing this pack
|
||||
├── input/
|
||||
│ ├── requirement.md # FR-xx table drives the traceability gate
|
||||
│ └── architecture.md # optional tech-stack/context
|
||||
├── golden-runs/
|
||||
│ └── <artifact>.golden.txt # baseline for drift detection (H7)
|
||||
├── corpus/
|
||||
│ ├── redteam-corpus.jsonl # attack vectors (H4 recall) — one JSON per line
|
||||
│ ├── redteam-vectors.jsonl # vectors for benign-fp-report / redteam metrics
|
||||
│ └── benign-corpus/*.txt # benign samples (H4 false-positive budget)
|
||||
└── traceability-map.json # FR-xx → code files + test files (+ optional symbols/lines)
|
||||
```
|
||||
|
||||
## Each piece
|
||||
- **input/requirement.md** — must contain a `| FR-xx | ... |` table. The traceability gate
|
||||
(Plan-10) requires every `FR-xx` to map to ≥1 existing code file and ≥1 test file. No
|
||||
secrets/PII (the H4 input scan blocks them).
|
||||
- **golden-runs/** — a canonical "good" artifact per pipeline output. `drift-detect` compares
|
||||
a run against it; similarity 1.0 = no drift. Real drift detection is proven separately.
|
||||
- **corpus/** — red-team attack vectors (scored for H4 recall) + a benign corpus (bounds the
|
||||
false-positive rate). Domain-specific injections make the H4 score meaningful.
|
||||
- **traceability-map.json** — `{"FR-01": {"name": "...", "code": ["backend/src/...", {"file":"...","symbols":["Foo"],"lines":[12]}], "tests": ["..."]}}`. Symbol/line refs are
|
||||
optional but tighten the gate.
|
||||
- **domain-pack.yaml** — documents the above + optional threshold overrides.
|
||||
|
||||
## Wire it up
|
||||
```bash
|
||||
export CASAN_DOMAIN_ROOT=apps/<project>/domain
|
||||
bin/casan gate # runs domain-dependent suites against your pack
|
||||
```
|
||||
`domain_root` is also recorded per-project in `packages/casan-harness/level5/project-registry.json`
|
||||
so `bin/casan reuse` can prove multi-project reuse.
|
||||
|
||||
## Reference example
|
||||
The OKR app's own pack is the worked example: `apps/okr/domain/` (golden-runs, corpus,
|
||||
input, traceability-map). Copy its shape for your domain.
|
||||
|
||||
## Toward Plan-12 (Domain Pack SDK)
|
||||
Today a pack is a directory + `CASAN_DOMAIN_ROOT`. Plan-12 will make it fully declarative
|
||||
(register a pack by manifest, no manual wiring). The `domain-pack.yaml` here is the seed of
|
||||
that manifest.
|
||||
@@ -0,0 +1,73 @@
|
||||
# CASAN on Gitea — Source Hub + Package Registry
|
||||
|
||||
This repo uses the existing Gitea server (`ssh://git@161.33.139.73:2222/admin/casan5.git`)
|
||||
as the **source hub**. Gitea also ships a **package registry** (generic files) and a
|
||||
**container registry**, so CASAN release bundles and Docker images can live next to the
|
||||
source. This guide shows the release flow. No secrets are committed; use a Gitea token/PAT.
|
||||
|
||||
> Gitea host below is written as `$GITEA` (e.g. `http://161.33.139.73:3000`). Set
|
||||
> `GITEA_TOKEN` to a personal access token with `write:package` scope. Adjust `admin`/`casan5`
|
||||
> to your org/repo.
|
||||
|
||||
## 1. Build the bundles
|
||||
```bash
|
||||
scripts/package-release.sh core
|
||||
scripts/package-release.sh devkit
|
||||
scripts/package-release.sh platform # preview
|
||||
scripts/package-release.sh all-in-one-demo
|
||||
# enterprise → intentionally refused (future)
|
||||
ls dist/ # *.tar.gz + *.sha256
|
||||
```
|
||||
|
||||
## 2. Publish tarballs to the Gitea generic package registry
|
||||
Endpoint: `PUT $GITEA/api/packages/{owner}/generic/{name}/{version}/{file}`
|
||||
```bash
|
||||
GITEA=http://161.33.139.73:3000; OWNER=admin; V=$(cat VERSION)
|
||||
for lvl in core devkit; do
|
||||
f="dist/casan-$lvl-v$V.tar.gz"
|
||||
curl -fsSL -XPUT -H "Authorization: token $GITEA_TOKEN" \
|
||||
--upload-file "$f" \
|
||||
"$GITEA/api/packages/$OWNER/generic/casan-$lvl/$V/$(basename "$f")"
|
||||
curl -fsSL -XPUT -H "Authorization: token $GITEA_TOKEN" \
|
||||
--upload-file "$f.sha256" \
|
||||
"$GITEA/api/packages/$OWNER/generic/casan-$lvl/$V/$(basename "$f").sha256"
|
||||
done
|
||||
# platform is a preview artifact:
|
||||
curl -fsSL -XPUT -H "Authorization: token $GITEA_TOKEN" \
|
||||
--upload-file "dist/casan-platform-preview-v$V.tar.gz" \
|
||||
"$GITEA/api/packages/$OWNER/generic/casan-platform/$V-preview/casan-platform-preview-v$V.tar.gz"
|
||||
```
|
||||
Downstream then pulls:
|
||||
```bash
|
||||
curl -fsSL -H "Authorization: token $TOKEN" \
|
||||
"$GITEA/api/packages/admin/generic/casan-core/1.0.0/casan-core-v1.0.0.tar.gz" -o casan-core.tar.gz
|
||||
```
|
||||
|
||||
## 3. Publish Docker images to the Gitea container registry
|
||||
```bash
|
||||
V=$(cat VERSION)
|
||||
docker build -f packages/casan-devkit/Dockerfile.harness -t "$REG/admin/casan-harness:$V" .
|
||||
echo "$GITEA_TOKEN" | docker login "$REG" -u admin --password-stdin # REG=161.33.139.73:3000
|
||||
docker push "$REG/admin/casan-harness:$V"
|
||||
```
|
||||
See `DOCKER_GUIDE.md` for image details. `casan-platform:$V` is preview; `casan-enterprise:$V`
|
||||
is future (do not publish).
|
||||
|
||||
## 4. Attach bundles to a Gitea Release (optional, human-facing)
|
||||
Create a tag + release via the API and upload the tarballs as release attachments:
|
||||
```bash
|
||||
# create release for tag vX.Y.Z, then:
|
||||
curl -fsSL -XPOST -H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/casan-devkit-v$V.tar.gz" \
|
||||
"$GITEA/api/v1/repos/admin/casan5/releases/{release_id}/assets?name=casan-devkit-v$V.tar.gz"
|
||||
```
|
||||
|
||||
## 5. Recommended cadence
|
||||
- Tag `vX.Y.Z` on `main` → CI green → build bundles → publish `core` + `devkit` (always),
|
||||
`platform` as `-preview`, `all-in-one-demo` for demos. Never publish `enterprise`.
|
||||
- Keep `VERSION` and `packages/casan-harness/level5/harness-package.json` version in lockstep.
|
||||
|
||||
## Automating in CI
|
||||
Add a release job to `.gitea/workflows/` that runs after the gate, calls
|
||||
`scripts/package-release.sh`, and does the `curl` uploads with `${{ secrets.GITEA_TOKEN }}`.
|
||||
Keep it gated on tags (`on: push: tags: ['v*']`) so ordinary pushes don't publish.
|
||||
Reference in New Issue
Block a user