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
16 changes: 16 additions & 0 deletions plugins/molecule-audit/plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: molecule-audit
version: 1.0.0
description: >
Immutable append-only audit log for EU AI Act compliance (Articles 12/13/17).
Wraps builtin_tools/audit.py — JSON Lines format, SIEM-friendly, write-only.
Opt-in per workspace; usually paired with molecule-compliance.
author: Molecule AI
tags: [audit, compliance, eu-ai-act, logging, siem]

runtimes:
- langgraph
- claude_code
- deepagents

skills:
- ai-act-audit-log
133 changes: 133 additions & 0 deletions plugins/molecule-audit/skills/ai-act-audit-log/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
---
name: ai-act-audit-log
description: "Emit immutable audit events for EU AI Act compliance. Use when a workspace performs any action that needs to be legally reconstructable: delegations, approvals, RBAC decisions, memory read/write. JSON Lines, append-only, SIEM-friendly."
---

# EU AI Act Audit Log

Opt-in plugin that activates `builtin_tools/audit.py` — an append-only
JSON Lines log satisfying the record-keeping and transparency obligations
of the EU AI Act (Articles 12, 13, 17) for high-risk AI systems.

## When to install

Install on any workspace that:
- Must satisfy EU AI Act conformity assessment
- Needs a tamper-evident trail of agent decisions for a legal discovery
- Pairs with `molecule-compliance` to record OWASP OA-01 detections and
OA-03 terminations

Skip on disposable dev workspaces — the log fills disk over time and
isn't useful for throwaway agents.

## Event schema

Every line is one JSON object:

```json
{
"timestamp": "2026-04-15T21:30:00.123Z",
"event_type": "delegation",
"workspace_id": "ws-acme-pm-a1b2c3d4",
"actor": "ws-acme-pm-a1b2c3d4",
"action": "delegate",
"resource": "ws-acme-dev-lead-e5f6g7h8",
"outcome": "allowed",
"trace_id": "5e8b2f3c-9a1d-4e7b-8c6f-1234567890ab"
}
```

Required fields:

| Field | Meaning |
|---|---|
| `timestamp` | ISO-8601 UTC with offset — sort key + freshness indicator |
| `event_type` | `delegation` / `approval` / `memory` / `rbac` |
| `workspace_id` | Who generated the event |
| `actor` | Who triggered the action (defaults to workspace_id for automated events; human identity for approval decisions) |
| `action` | Verb: `delegate`, `approve`, `memory.read`, `memory.write`, `rbac.deny` |
| `resource` | Target of the action: another workspace id, memory scope, approval action string |
| `outcome` | `allowed` / `denied` / `success` / `failure` / `timeout` / `requested` / `granted` |
| `trace_id` | UUID v4 correlating related events across workspaces |

## Usage

Call `audit.log_event` from any tool or handler:

```python
from builtin_tools.audit import log_event

log_event(
event_type="delegation",
workspace_id=self.workspace_id,
actor=self.workspace_id,
action="delegate",
resource=target_workspace_id,
outcome="allowed",
trace_id=ctx.trace_id,
)
```

The function is synchronous and fire-and-forget — it opens the log file
in append mode, writes one line, closes. No buffering, no retry. If the
disk is full the call raises `IOError`; the caller decides whether to
surface that (usually yes — an audit gap is a compliance event itself).

## Configuration

Add to `config.yaml`:

```yaml
audit:
enabled: true
log_path: /var/log/molecule/audit.jsonl
max_size_mb: 100 # informational only; rotation is EXTERNAL
retention_days: 365 # informational only; the module never deletes
```

## Rotation (external)

This module is **write-only by design**. It does not rotate, compress,
or delete log lines. Use the host's `logrotate` (Linux) or equivalent:

```
/var/log/molecule/audit.jsonl {
daily
rotate 365
compress
copytruncate # NOT truncate — copytruncate leaves the file open
missingok
notifempty
}
```

`copytruncate` is load-bearing — the Python side holds the file
descriptor open for append, so a rename-based rotation would orphan the
new file and writes would continue to the rotated-away path.

## SIEM ingestion

The JSON Lines format is directly consumable by:
- Splunk (ingest via Universal Forwarder)
- Elastic (Filebeat + JSON decoder)
- Datadog (Agent in JSON mode)
- Self-hosted Loki

One ingestion pipeline per workspace volume. No post-processing needed.

## Anti-patterns

- **Don't** write to the same log path from multiple workspaces on the
same host — races corrupt the JSONL newlines. Use per-workspace paths.
- **Don't** truncate or edit the log. Tamper-evidence is the whole point.
- **Don't** log raw PII or secrets in the `resource` or `outcome` fields.
Use IDs or hashes; the audit story and the GDPR story have to coexist.
- **Don't** skip this on OA-01/OA-03 detections — they're exactly the
events an auditor wants to see.

## Related

- `builtin_tools/audit.py` — the implementation
- `molecule-compliance` — emits OWASP OA-01 / OA-03 events into this log
- `molecule-security-scan` — emits CVE-scan results into this log
- Issue #256 — the proposal that led to this plugin split
17 changes: 17 additions & 0 deletions plugins/molecule-compliance/plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: molecule-compliance
version: 1.0.0
description: >
OWASP Top 10 for Agentic Applications (Dec 2025) compliance enforcement.
Wraps builtin_tools/compliance.py — prompt-injection detection/blocking,
excessive-agency limits (max tool calls + task duration). Opt-in per
workspace via config.yaml compliance block.
author: Molecule AI
tags: [compliance, owasp, security, prompt-injection]

runtimes:
- langgraph
- claude_code
- deepagents

skills:
- owasp-agentic
91 changes: 91 additions & 0 deletions plugins/molecule-compliance/skills/owasp-agentic/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
name: owasp-agentic
description: "Enforce OWASP Top 10 for Agentic Applications. Use when a workspace handles untrusted input (user messages, scraped web content, file uploads) or when it would be catastrophic if the agent ran away with unlimited tool calls. Gates prompt injection + excessive agency."
---

# OWASP Agentic Compliance

Opt-in compliance layer that wraps `builtin_tools/compliance.py`. The
Python primitives exist in every runtime image — installing this plugin
activates them via config and documents the policy.

## Coverage

| OWASP ID | Name | Primitive | Default mode |
|---|---|---|---|
| **OA-01** | Prompt Injection | `sanitize_input(text)` | `detect` |
| **OA-03** | Excessive Agency | `check_agency_limits(task_ctx)` | 50 calls / 300s |

## When to install

Install this plugin on any workspace that:
- Accepts free-form user input (chat interfaces, A2A message bodies)
- Scrapes or ingests untrusted web content
- Runs long-horizon tasks where a stuck loop could burn LLM budget
- Must satisfy compliance reviews that cite OWASP Top 10 for AI

## Configuration

Add to `config.yaml`:

```yaml
compliance:
mode: owasp_agentic
prompt_injection: detect # detect → log+pass, block → raise PromptInjectionError
max_tool_calls_per_task: 50 # OA-03 ceiling
max_task_duration_seconds: 300 # OA-03 wall-clock ceiling
```

Modes explained:

- **`detect`** (default) — logs an audit event via `audit.log_event` when a
trigger pattern is found, returns the original text. The agent still
processes the input. Good for rollout: you see what triggers before
committing to blocking.
- **`block`** — raises `PromptInjectionError` before the agent sees the
text. The caller (typically `a2a_executor.py`) catches it and returns a
400-shaped error to the sender.

## Trigger patterns (OA-01)

`sanitize_input` scans for:
- Instruction-override phrases ("ignore previous instructions", "new system prompt")
- Role-hijacking attempts ("you are now", "act as")
- System-prompt delimiter injection (`</s>`, `<|im_start|>`)
- Known jailbreak keywords (rotating list; update via compliance.py)

False positives on legitimate content are expected in `detect` mode —
that's why it's the default. Only flip to `block` after you've reviewed
audit logs for a week and confirmed the hit rate is low.

## Agency limits (OA-03)

Tracks per-task:
- Number of tool calls (`tool_call_count`)
- Elapsed wall-clock time (`started_at → now`)

When either exceeds the configured ceiling, `check_agency_limits` raises
`ExcessiveAgencyError`. The task terminates gracefully — the caller sees
a final message + `status=failed`.

## Anti-patterns

- **Don't** install on workspaces that only process trusted internal
input — the overhead isn't worth it.
- **Don't** set `max_tool_calls_per_task` below 20. Many legitimate
multi-step tasks need 15-30 tool calls; ceilings that low cause false
terminations.
- **Don't** flip `prompt_injection` to `block` without a rollout period.
- **Don't** rely on this as your only defense — it's a cheap policy
layer, not a substitute for proper sandboxing of the agent's
filesystem + network access.

## Related

- `builtin_tools/compliance.py` — the implementation
- `molecule-audit` — audit-log retention for the events this plugin
generates (OA-01 detections, OA-03 terminations). Install both to get
a coherent compliance story.
- `molecule-security-scan` — pre-load CVE gate for skill dependencies
(complements this runtime policy with supply-chain policy).
- Issue #256 — the proposal that led to this plugin split
16 changes: 16 additions & 0 deletions plugins/molecule-security-scan/plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: molecule-security-scan
version: 1.0.0
description: >
Supply-chain CVE gate for skill dependencies. Wraps builtin_tools/security_scan.py —
runs Snyk or pip-audit against a skill's requirements.txt before the skill
loads, blocking or warning on critical/high CVEs. Opt-in per workspace.
author: Molecule AI
tags: [security, cve, supply-chain, snyk, pip-audit]

runtimes:
- langgraph
- claude_code
- deepagents

skills:
- skill-cve-gate
Loading
Loading