diff --git a/.github/workflows/ci_local.yml b/.github/workflows/ci_local.yml index c23365e..856636f 100644 --- a/.github/workflows/ci_local.yml +++ b/.github/workflows/ci_local.yml @@ -51,3 +51,22 @@ jobs: run: | go test -race -coverprofile=coverage.out -covermode=atomic ./... go tool cover -func=coverage.out | tail -1 + + module-sync: + name: Module Sync Check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Verify module copies match sources + run: | + diff -r skills/mcp-setup module/skills/mcp-setup + diff -r skills/audit-pipeline module/skills/audit-pipeline + diff -r skills/pack-assessment module/skills/pack-assessment + diff .opencode/commands/comply-setup.md module/commands/comply-setup.md + diff .opencode/commands/comply-pipeline.md module/commands/comply-pipeline.md + diff .opencode/commands/comply-pack.md module/commands/comply-pack.md diff --git a/INSTALL.md b/INSTALL.md index 424a0c1..a09bade 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -189,6 +189,30 @@ Or use the setup command to generate it interactively: | `/comply-pack` | Generate Rego policies from the child policy | | `/comply-pipeline` | Run the comply pipeline (scoping, mapping, adherence)| +## Lola (any AI assistant) + +Install the complypack module with [lola](https://lobstertrap.org/lola/): + +```bash +lola mod add https://github.com/complytime/complypack.git +lola install complypack -a opencode --scope project +``` + +This installs skills and commands into `.opencode/skills/` and +`.opencode/commands/`. After installation, the `/comply-setup`, +`/comply-pipeline`, and `/comply-pack` commands are available in OpenCode. + +To update after complypack releases new skills: + +```bash +lola mod update complypack +lola install complypack -a opencode --scope project +``` + +> **Note:** The MCP server still requires separate configuration. Run +> `/comply-setup` after installation to generate the MCP config, or +> edit `mcps.json` manually with your registry and schema values. + ## SELinux (Fedora / RHEL) On systems with SELinux enforcing, volume mounts require the `:z` suffix so diff --git a/Taskfile.yml b/Taskfile.yml index 2a72f27..1852178 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -13,6 +13,29 @@ tasks: generates: - json-schema/*.json + sync-module: + desc: Copy skills and commands into module/ for lola distribution + cmds: + - rm -rf module/skills/mcp-setup module/skills/audit-pipeline module/skills/pack-assessment + - rm -f module/commands/comply-setup.md module/commands/comply-pipeline.md module/commands/comply-pack.md + - mkdir -p module/skills module/commands + - cp -r skills/mcp-setup module/skills/mcp-setup + - cp -r skills/audit-pipeline module/skills/audit-pipeline + - cp -r skills/pack-assessment module/skills/pack-assessment + - cp .opencode/commands/comply-setup.md module/commands/comply-setup.md + - cp .opencode/commands/comply-pipeline.md module/commands/comply-pipeline.md + - cp .opencode/commands/comply-pack.md module/commands/comply-pack.md + + check-module-sync: + desc: Verify module/ skills and commands match their sources + cmds: + - diff -r skills/mcp-setup module/skills/mcp-setup + - diff -r skills/audit-pipeline module/skills/audit-pipeline + - diff -r skills/pack-assessment module/skills/pack-assessment + - diff .opencode/commands/comply-setup.md module/commands/comply-setup.md + - diff .opencode/commands/comply-pipeline.md module/commands/comply-pipeline.md + - diff .opencode/commands/comply-pack.md module/commands/comply-pack.md + default: cmds: - task: generate-schemas diff --git a/docs/adr/018-lola-module-distribution.md b/docs/adr/018-lola-module-distribution.md new file mode 100644 index 0000000..5f8362f --- /dev/null +++ b/docs/adr/018-lola-module-distribution.md @@ -0,0 +1,57 @@ +# ADR 018: Lola Module for Skill Distribution + +**Status:** Proposed + +**Date:** 2026-07-13 + +**Context:** + +Complypack provides AI coding assistants with compliance pipeline skills (audit-pipeline, mcp-setup, pack-assessment) and slash commands (comply-setup, comply-pipeline, comply-pack). These artifacts are authored in two canonical locations: + +- `skills/` — skill definitions (markdown with frontmatter) +- `.opencode/commands/` — slash command definitions + +Consumer repositories need these skills and commands installed into their own tool-specific directories. Before this change, the only installation path was manual: clone the repo, copy files into the right directories, and repeat on every update. Tool-specific plugin directories (`.claude-plugin/`, `.cursor-plugin/`, `gemini-extension.json`) reference `skills/` directly but only work within the complypack repository itself. + +[Lola](https://lobstertrap.org/lola/concepts/skills-and-modules/) provides a standard layout (`module/`) and install command (`lola install`) for distributing AI coding assistant artifacts across repositories. It currently supports OpenCode as the install target. + +The challenge is maintaining two sets of files — canonical sources and distributable copies — without them silently drifting apart. + +**Decision:** + +Add a `module/` directory following the lola AI Context Module layout. Module files are exact copies of their canonical sources, not symlinks, because lola requires a self-contained directory that it can copy into consumer repositories. + +**Drift prevention** uses two Taskfile targets: + +1. **`task sync-module`** — copies canonical sources into `module/`. Run by contributors after editing canonical files. +2. **`task check-module-sync`** — diffs module copies against sources, exits non-zero on divergence. A `Module Sync Check` job in `ci_local.yml` runs this on every push and PR, preventing drift from reaching `main`. + +A pre-commit hook to automate step 1 is tracked separately. + +**`mcps.json` version strategy:** The module includes a `mcps.json` with `VERSION` placeholders rather than a pinned release tag or a floating tag like `latest`/`main`. Floating tags were rejected per the constitution's container standards ("MUST use a specific base image tag or digest. MUST NOT use `latest` or floating tags"). Pinning a release tag would go stale on next release. The `mcp-setup` skill handles interactive version resolution at runtime, so the placeholder is the honest representation — users run `/comply-setup` or substitute the version manually. + +**Command scope:** Only the three `/comply-*` commands (comply-setup, comply-pipeline, comply-pack) are included. The `review-pr.md` command (a general-purpose PR review workflow) is excluded because it is not a compliance command and consumer repos may have their own review workflows. + +**Module `AGENTS.md` scope:** The module's `AGENTS.md` is a consumer-facing overview — what complypack is, what the skills do, the pipeline flow, and how to invoke commands. It does not reuse the root `AGENTS.md`, which contains contributor-focused architecture notes (domain packages, transport layers, testing split) that are irrelevant to consumers. + +The existing tool-specific integrations (`.claude-plugin/`, `.cursor-plugin/`, `.opencode/skills/` symlinks, `gemini-extension.json`) remain unchanged. The `.opencode/skills/` symlinks serve local complypack development — they point back to `skills/` at the repo root so OpenCode discovers the skills when working on this repo. They are not part of any distribution mechanism. + +**Consequences:** + +**Benefits:** + +- Consumer repos install with `lola mod add` + `lola install` instead of manual file copying +- CI catches drift between canonical sources and module copies before merge +- Existing tool integrations are unaffected (backwards compatible) +- Canonical sources remain the single source of truth + +**Drawbacks:** + +- Every canonical file has an exact copy in `module/`, increasing maintenance surface +- Contributors must run `task sync-module` after editing canonical files (until pre-commit hook is added) +- Lola currently supports OpenCode only; other tools still require their own plugin directories + +**Related:** + +- ADR 012: Container-Based MCP Server Distribution +- ADR 015: Comply Pipeline as Plugin Skills diff --git a/module/AGENTS.md b/module/AGENTS.md new file mode 100644 index 0000000..3229dce --- /dev/null +++ b/module/AGENTS.md @@ -0,0 +1,45 @@ +# ComplyPack + +ComplyPack provides AI coding assistants with compliance pipeline skills +and an MCP server for working with [Gemara](https://github.com/gemaraproj) +control catalogs. + +## MCP Server + +The complypack MCP server serves Gemara artifacts (catalogs, policies, +mappings) and provides tools for policy validation, assessment triage, +and parameter analysis. Configure it via `/comply-setup` or manually +in your tool's MCP configuration. See `mcps.json` for the base template. + +## Skills + +| Skill | Trigger | Purpose | +|-------|---------|---------| +| `mcp-setup` | User wants to configure MCP servers | Interactive setup wizard for complypack and gemara MCP servers | +| `audit-pipeline` | User wants to build compliance artifacts or prepare for audit | Three-stage pipeline: scoping, mapping, adherence | +| `pack-assessment` | User mentions Rego, Conftest, OPA, or policy generation | Generate Rego policies from Gemara catalogs | + +### Pipeline Flow + +``` +scoping -> mapping -> adherence -> pack-assessment +``` + +1. **Scoping** -- Characterize the system, scope control catalogs, identify gaps +2. **Mapping** -- Crosswalk frameworks, harmonize parameters across layers +3. **Adherence** -- Compile a Gemara Policy with assessment plans +4. **Pack** -- Generate Rego policies for automated assessment plans + +## Commands + +| Command | Description | +|---------|-------------| +| `/comply-setup` | Configure complypack MCP server for this project | +| `/comply-pipeline` | Run the comply pipeline (scoping, mapping, adherence) | +| `/comply-pack` | Generate Rego policies from the child policy | + +## Safety + +All control IDs, requirement IDs, and parameter values MUST come from MCP +resources. Skills enforce this constraint to prevent hallucinated policy +content. The MCP server is the single source of truth. diff --git a/module/commands/comply-pack.md b/module/commands/comply-pack.md new file mode 100644 index 0000000..4d91537 --- /dev/null +++ b/module/commands/comply-pack.md @@ -0,0 +1,6 @@ +--- +description: Generate Rego policies from the child policy +--- + +Load the `pack` skill and execute it. Read `.complytime/child-policy.yaml` +for the assessment plans to generate Rego policies from. diff --git a/module/commands/comply-pipeline.md b/module/commands/comply-pipeline.md new file mode 100644 index 0000000..494e3c4 --- /dev/null +++ b/module/commands/comply-pipeline.md @@ -0,0 +1,6 @@ +--- +description: Run the comply pipeline (scoping, mapping, adherence) +--- + +Load the `pipeline` skill and execute it. Check `.complytime/` for existing +artifacts to determine which stage to resume from. diff --git a/module/commands/comply-setup.md b/module/commands/comply-setup.md new file mode 100644 index 0000000..5d12187 --- /dev/null +++ b/module/commands/comply-setup.md @@ -0,0 +1,6 @@ +--- +description: Configure complypack MCP server for this project +--- + +Load the `setup` skill and execute it. Generate `.mcp.json` with the +complypack MCP server configuration for the current project. diff --git a/module/mcps.json b/module/mcps.json new file mode 100644 index 0000000..4a58515 --- /dev/null +++ b/module/mcps.json @@ -0,0 +1,14 @@ +{ + "mcpServers": { + "complypack": { + "command": "podman", + "args": [ + "run", "--rm", "-i", + "ghcr.io/complytime/complypack:VERSION", + "mcp", "serve", + "--source", "oci://YOUR_REGISTRY/YOUR_CATALOG:VERSION", + "--schema", "YOUR_PLATFORM" + ] + } + } +} diff --git a/module/skills/audit-pipeline/SKILL.md b/module/skills/audit-pipeline/SKILL.md new file mode 100644 index 0000000..edb811a --- /dev/null +++ b/module/skills/audit-pipeline/SKILL.md @@ -0,0 +1,52 @@ +--- +name: audit-pipeline +description: Use when user wants to build Gemara Policy artifacts for audit preparation or compliance program setup +--- + +# /comply:audit-pipeline — ComplyTime Audit Pipeline + +Guide users through building a Gemara Policy (applicability statement) from their system architecture and governance sources. The Gemara Policy is the formal contract between audit and engineering, functionally equivalent to an ISO 27001 Statement of Applicability or a NIST System Security Plan. + +## Safety + +**CRITICAL:** Every stage MUST read control IDs, requirement IDs, and parameter values from MCP resources. DO NOT generate these from memory. The MCP server is the source of truth. + +## Pipeline Stages + +| Stage | Artifact | Purpose | +|-----------|-----------------------------------|------------------------------------------------------------------| +| scoping | `.complytime/scoping.yaml` | System profile + Control Catalog scoping + gap analysis | +| mapping | `.complytime/delta-report.yaml` | Parameter delta analysis + harmonization across framework layers | +| adherence | `.complytime/child-policy.yaml` | Compile the child Policy with adherence plan | + +After adherence, invoke `/comply:pack-assessment` to generate assessment logic for use with `complyctl`. + +## Router Logic + +1. Check if `.complytime/` directory exists and which artifacts are present +2. Determine pipeline state: + - No `.complytime/` directory → start at **scoping** + - `scoping.yaml` exists but no `delta-report.yaml` → offer **mapping** + - `delta-report.yaml` exists but no `child-policy.yaml` → offer **adherence** + - `child-policy.yaml` exists → pipeline complete, offer to re-run any stage or proceed to `/comply:pack-assessment` +3. If the user specified a stage, validate prerequisites: + - **mapping** requires `scoping.yaml` + - **adherence** requires `delta-report.yaml` +4. Dispatch to the appropriate stage skill + +## Dispatching + +Read the stage instructions from this skill's base directory before proceeding: + +- **scoping** → `scoping.md` +- **mapping** → `mapping.md` +- **adherence** → `adherence.md` + +## Status Display + +```text +/comply:audit-pipeline status: + [done] scoping — .complytime/scoping.yaml + [done] mapping — .complytime/delta-report.yaml + [next] adherence — not yet run +``` diff --git a/module/skills/audit-pipeline/adherence.md b/module/skills/audit-pipeline/adherence.md new file mode 100644 index 0000000..85e7519 --- /dev/null +++ b/module/skills/audit-pipeline/adherence.md @@ -0,0 +1,195 @@ +--- +name: adherence +description: Populate a Gemara Policy defining what controls apply, with what parameter values, and how evidence will be collected +user-invocable: false +--- + +# Adherence — Compile Policy + +Compile or alter a Gemara Policy artifact. Declares what controls apply, with exact parameter values, and defines the adherence plan: frequency, evaluation method, and evidence requirements. + +Evidence collection and Evaluation Logs are produced by `complyctl` at runtime. + +## Prerequisites + +- `.complytime/scoping.yaml` +- `.complytime/delta-report.yaml` + +Verify all parameters are resolved (no `pending_user_decision`). If unresolved, tell the user to re-run mapping. + +## Process + +### Step 1: Read Input Artifacts + +Read both `.complytime/scoping.yaml` and `.complytime/delta-report.yaml`. + +### Step 2: Build Mapping References + +From the delta report's `sources`, build `mapping_references`: +- One for the parent Policy +- One for each scoped Control Catalog +- One for each Guidance Catalog for the target framework + +> **Critical:** Set `mapping-reference.id` to match the referenced +> artifact's `metadata.id` exactly (e.g., `container-security-controls`, +> not `csc`). ComplyPack resolves policy imports by matching these IDs +> against loaded sources. Short aliases pass Gemara schema validation but +> fail at complypack runtime with: +> `failed to resolve effective policy: no imports could be resolved` + +### Step 3: Build Imports + +- `imports.catalogs` — one per Control Catalog +- `imports.guidance` — one per mandated Guidance Catalog + +### Step 4: Build Assessment Plans + +#### 4a: Identify the trusted evaluator + +Ask the user: "Who is the trusted evaluator for automated assessments?" Read `complypack://evaluator` to see available evaluators. Collect: +- `id` — evaluator plugin identifier +- `name` — display name +- `type` — `Software` +- `version` — evaluator version + +This becomes the **default** executor for all automated plans, set as a global evaluation method on `adherence.evaluation-methods`. Individual assessment plans can override this with their own `evaluation-methods` and `executor` when a specific requirement needs a different evaluator or mode. + +#### 4b: Triage requirements by automation eligibility + +Call `get_applicability_groups` to retrieve the catalog's applicability group definitions and see which requirements belong to each group. Use the group titles and descriptions to identify which group designates automation-eligible requirements. + +- **Automatable** (requirement belongs to the automation-eligible group): assessment plan inherits the global `mode: Automated` and executor — no per-plan `evaluation-methods` needed unless overriding +- **Not automatable**: assessment plan overrides with per-plan `evaluation-methods` set to `mode: Manual`, no executor +- **No applicability groups in catalog**: ask the user to classify each requirement as automated or manual + +The user may also override any individual plan's evaluation method and executor. Present the triage results and ask if any plans need a different evaluator or mode before compiling. + +#### 4c: Build each plan + +Group by `requirement-id`. Each plan: +- `id` — unique plan identifier +- `requirement-id` — the assessment requirement this plan addresses +- `frequency` (e.g., "30d", "90d", "365d") +- `evaluation-methods` — only when overriding the global default (e.g., manual plans or plans with a different executor) +- `evidence-requirements` — what evidence is collected +- `parameters` — frozen values from harmonization, each with `id`, `label`, `accepted-values`, `description` + +### Step 5: Compile the Policy + +```yaml +title: " Policy" +metadata: + id: -policy + gemara-version: v1.0.0 + type: Policy + description: "" + author: + id: + name: + type: Software Assisted + mapping-references: + - id: + title: "" + version: "" +contacts: + responsible: + - name: "" + accountable: + - name: "" +scope: + in: + technologies: + - + groups: + - +imports: + catalogs: + - reference-id: + guidance: + - reference-id: +adherence: + # Global default: applies to all plans unless overridden + evaluation-methods: + - id: default-eval + type: Behavioral + mode: Automated + executor: + id: + name: + type: Software + version: "" + assessment-plans: + # Automated plan — inherits global evaluation-methods and executor + - id: + requirement-id: "" + frequency: "" + evidence-requirements: "" + parameters: + - id: + label: "