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
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ An open-source Go module and verification CLI. Four operations:
PROOF_VERSION="$(gh release view --repo Clyra-AI/proof --json tagName -q .tagName 2>/dev/null || curl -fsSL https://api.github.com/repos/Clyra-AI/proof/releases/latest | python3 -c 'import json,sys; print(json.load(sys.stdin)[\"tag_name\"])')"
go install github.com/Clyra-AI/proof/cmd/proof@"${PROOF_VERSION}"

proof types list # 15 built-in record types
proof frameworks list # 8 built-in starter frameworks (11 controls)
proof types list # 16 built-in record types
proof frameworks list # 8 built-in starter frameworks (12 controls)
proof verify ./artifact # Verify any proof artifact offline
```

Expand Down Expand Up @@ -74,6 +74,19 @@ _ = proof.RegisterCustomTypeSchema("vendor.custom_event", "./custom.schema.json"

Custom types validate against the base proof record schema plus your type-specific schema. They chain and sign identically to built-in types.

### Governance Events

```go
record, _ := proof.NewRecordFromEvent(proof.GovernanceEvent{
EventID: "evt-1",
Timestamp: "2026-02-20T12:00:00Z",
EventType: "tool_gate",
Detail: map[string]any{"verdict": "allow"},
}, "axym")
```

Use `schemas/v1/governance-event-v1.schema.json` for event validation. See `docs/governance-events.md` and `docs/record-context-keys.md`.

### Bundle Signing and Verification

```go
Expand Down Expand Up @@ -120,7 +133,7 @@ Records are immutable, deterministic, and JSON-native — readable by any langua

## Built-in Record Types

15 types covering the full AI governance surface, each with its own JSON Schema:
16 types covering the full AI governance surface, each with its own JSON Schema:

| Type | Description |
|---|---|
Expand All @@ -139,6 +152,7 @@ Records are immutable, deterministic, and JSON-native — readable by any langua
| `data_pipeline_run` | A data pipeline executed |
| `replay_certification` | A replay was run and certified |
| `approval` | An approval or delegation was issued |
| `compiled_action` | A compound agent action was compiled for execution |

Record types are extensible. Define a custom type by providing a JSON Schema that extends the base record schema.

Expand Down Expand Up @@ -187,17 +201,17 @@ YAML files that declare what regulatory controls require — which record types,
controls:
- id: article-12
title: Record-Keeping
required_record_types: [tool_invocation, decision, guardrail_activation, permission_check]
required_record_types: [tool_invocation, decision, guardrail_activation, permission_check, compiled_action]
required_fields: [record_id, timestamp, source, source_product, record_type, event, integrity.record_hash]
minimum_frequency: continuous
```

8 built-in starter frameworks ship with v1 (11 controls total). Add custom frameworks via YAML.
8 built-in starter frameworks ship with v1 (12 controls total). Add custom frameworks via YAML.

| Framework | Scope |
|---|---|
| EU AI Act | Articles 9, 12, 14 (starter mapping) |
| SOC 2 | CC6, CC7 (starter mapping) |
| SOC 2 | CC6, CC7, CC8 (starter mapping) |
| SOX | Change management (starter mapping) |
| PCI-DSS | Requirement 10 (logging and monitoring) |
| Texas TRAIGA | State AI regulation |
Expand Down Expand Up @@ -302,8 +316,9 @@ canon/ Compatibility package (Gait migration)
schema/ Compatibility package (Gait migration)
exitcode/ Compatibility package (Gait migration)
schemas/v1/ JSON Schema spec files (language-agnostic contract)
types/ 15 record type schemas
types/ 16 record type schemas
frameworks/ 8 compliance framework YAML definitions
docs/ Supplementary format and interoperability documentation
testdata/ Golden vectors and test fixtures
scripts/ Test and validation scripts
perf/ Performance budgets
Expand Down
114 changes: 114 additions & 0 deletions compiled_action_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package proof

import (
"path/filepath"
"testing"
"time"

"github.com/stretchr/testify/require"
)

func TestCompiledActionGoldenRecordsValidate(t *testing.T) {
paths := []string{
filepath.Join("testdata", "records", "compiled_action_full.json"),
filepath.Join("testdata", "records", "compiled_action_minimal.json"),
}
for _, p := range paths {
r, err := ReadRecord(p)
require.NoError(t, err)
require.Equal(t, "compiled_action", r.RecordType)
require.NoError(t, ValidateRecord(r))
h, err := ComputeRecordHash(r)
require.NoError(t, err)
require.Equal(t, r.Integrity.RecordHash, h)
}
}

func TestCompiledActionSchemaRejectsInvalidFields(t *testing.T) {
_, err := NewRecord(RecordOpts{
Timestamp: time.Date(2026, 2, 20, 16, 0, 0, 0, time.UTC),
Source: "gait",
SourceProduct: "gait",
Type: "compiled_action",
Event: map[string]any{
"script_hash": "sha256:4444444444444444444444444444444444444444444444444444444444444444",
"tool_sequence": []string{},
"step_count": 1,
"has_conditionals": false,
"has_loops": false,
"composite_risk_class": "high",
},
})
require.Error(t, err)

_, err = NewRecord(RecordOpts{
Timestamp: time.Date(2026, 2, 20, 16, 1, 0, 0, time.UTC),
Source: "gait",
SourceProduct: "gait",
Type: "compiled_action",
Event: map[string]any{
"script_hash": "sha256:5555555555555555555555555555555555555555555555555555555555555555",
"tool_sequence": []string{"shell.exec"},
"step_count": 1,
"has_conditionals": false,
"has_loops": false,
"composite_risk_class": "critical",
},
})
require.Error(t, err)
}

func TestCompiledActionChainRoundTrip(t *testing.T) {
r, err := NewRecord(RecordOpts{
Timestamp: time.Date(2026, 2, 20, 16, 2, 0, 0, time.UTC),
Source: "gait",
SourceProduct: "gait",
Type: "compiled_action",
Event: map[string]any{
"script_hash": "sha256:6666666666666666666666666666666666666666666666666666666666666666",
"tool_sequence": []string{"shell.exec", "http.request", "db.query", "fs.write", "notify.send"},
"step_count": 5,
"has_conditionals": true,
"has_loops": false,
"composite_risk_class": "high",
"script_source": "ptc",
},
})
require.NoError(t, err)

chain := NewChain("compiled-action")
require.NoError(t, AppendToChain(chain, r))
v, err := VerifyChain(chain)
require.NoError(t, err)
require.True(t, v.Intact)
require.Equal(t, 1, v.Count)
}

func TestRecordContextMetadataKeysCompatibility(t *testing.T) {
withContext, err := NewRecord(RecordOpts{
Timestamp: time.Date(2026, 2, 20, 16, 3, 0, 0, time.UTC),
Source: "axym",
SourceProduct: "axym",
Type: "decision",
Event: map[string]any{"action": "allow"},
Metadata: map[string]any{
"data_class": "pii",
"endpoint_class": "write",
"risk_level": "high",
"business_process": "customer-support",
"affected_entities": []string{"ticket:10", "customer:42"},
},
})
require.NoError(t, err)
require.NoError(t, ValidateRecord(withContext))

withoutContext, err := NewRecord(RecordOpts{
Timestamp: time.Date(2026, 2, 20, 16, 4, 0, 0, time.UTC),
Source: "axym",
SourceProduct: "axym",
Type: "decision",
Event: map[string]any{"action": "allow"},
})
require.NoError(t, err)
require.NoError(t, ValidateRecord(withoutContext))
}
4 changes: 2 additions & 2 deletions core/framework/eu-ai-act.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ controls:
minimum_frequency: quarterly
- id: article-12
title: Record-Keeping
required_record_types: [tool_invocation, decision, guardrail_activation, permission_check]
required_record_types: [tool_invocation, decision, guardrail_activation, permission_check, compiled_action]
required_fields: [record_id, timestamp, source, source_product, record_type, event, integrity.record_hash]
minimum_frequency: continuous
- id: article-14
title: Human Oversight
required_record_types: [human_oversight, approval]
required_record_types: [human_oversight, approval, compiled_action]
required_fields: [record_id, timestamp, source, source_product, record_type, event, integrity.record_hash]
minimum_frequency: per-event
2 changes: 1 addition & 1 deletion core/framework/pci-dss.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ framework:
controls:
- id: req-10
title: Logging and Monitoring
required_record_types: [tool_invocation, permission_check, incident]
required_record_types: [tool_invocation, permission_check, incident, compiled_action]
required_fields: [record_id, timestamp, source, source_product, record_type, event, integrity.record_hash]
minimum_frequency: continuous
7 changes: 6 additions & 1 deletion core/framework/soc2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ controls:
minimum_frequency: continuous
- id: cc7
title: System Operations
required_record_types: [incident, guardrail_activation]
required_record_types: [incident, guardrail_activation, compiled_action]
required_fields: [record_id, timestamp, source, source_product, record_type, event, integrity.record_hash]
minimum_frequency: continuous
- id: cc8
title: Change Management
required_record_types: [approval, compiled_action]
required_fields: [record_id, timestamp, source, source_product, record_type, event, integrity.record_hash]
minimum_frequency: continuous
1 change: 1 addition & 0 deletions core/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var builtins = []RecordType{
{Name: "data_pipeline_run", Description: "A data pipeline executed", SchemaPath: "v1/types/data-pipeline-run.schema.json"},
{Name: "replay_certification", Description: "A replay was run and certified", SchemaPath: "v1/types/replay-certification.schema.json"},
{Name: "approval", Description: "An approval or delegation was issued", SchemaPath: "v1/types/approval.schema.json"},
{Name: "compiled_action", Description: "A compound agent action was compiled for execution", SchemaPath: "v1/types/compiled-action.schema.json"},
}

var customMu sync.RWMutex
Expand Down
8 changes: 8 additions & 0 deletions core/schema/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,11 @@ func TestValidateAgainstSchemaAndErrors(t *testing.T) {
require.Error(t, ValidateAgainstSchema([]byte("{"), "v1/chain-v1.schema.json"))
require.Error(t, ValidateAgainstSchema(raw, "v1/missing.schema.json"))
}

func TestValidateGovernanceEventSchema(t *testing.T) {
valid := []byte(`{"event_id":"evt-1","timestamp":"2026-02-20T12:00:00Z","event_type":"tool_gate"}`)
require.NoError(t, ValidateAgainstSchema(valid, "v1/governance-event-v1.schema.json"))

invalid := []byte(`{"timestamp":"2026-02-20T12:00:00Z","event_type":"tool_gate"}`)
require.Error(t, ValidateAgainstSchema(invalid, "v1/governance-event-v1.schema.json"))
}
35 changes: 35 additions & 0 deletions core/schema/v1/governance-event-v1.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://github.com/Clyra-AI/proof/schemas/v1/governance-event-v1.schema.json",
"type": "object",
"required": ["event_id", "timestamp", "event_type"],
"properties": {
"event_id": { "type": "string", "minLength": 1 },
"timestamp": { "type": "string", "format": "date-time" },
"event_type": {
"type": "string",
"enum": [
"tool_gate",
"permission_check",
"approval_request",
"policy_evaluation",
"guardrail_activation",
"script_evaluation"
]
},
"agent_id": { "type": "string", "minLength": 1 },
"tool_name": { "type": "string", "minLength": 1 },
"verdict": {
"type": "string",
"enum": ["allow", "block", "dry_run", "require_approval", "pending"]
},
"context": {
"type": "object",
"additionalProperties": true
},
"detail": {
"type": "object",
"additionalProperties": true
}
}
}
50 changes: 50 additions & 0 deletions core/schema/v1/types/compiled-action.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://github.com/Clyra-AI/proof/schemas/v1/types/compiled-action.schema.json",
"type": "object",
"required": ["record_type", "event"],
"properties": {
"record_type": { "const": "compiled_action" },
"event": {
"type": "object",
"required": [
"script_hash",
"tool_sequence",
"step_count",
"has_conditionals",
"has_loops",
"composite_risk_class"
],
"properties": {
"script_hash": { "type": "string", "pattern": "^sha256:[a-f0-9]{64}$" },
"tool_sequence": {
"type": "array",
"minItems": 1,
"items": { "type": "string", "minLength": 1 }
},
"step_count": { "type": "integer", "minimum": 1 },
"has_conditionals": { "type": "boolean" },
"has_loops": { "type": "boolean" },
"composite_risk_class": {
"type": "string",
"enum": ["minimal", "limited", "high", "unacceptable"]
},
"execution_trace_refs": {
"type": "array",
"items": {
"type": "string",
"pattern": "^prf-[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z-[a-f0-9]{8}$"
}
},
"gate_verdict": {
"type": "string",
"enum": ["allow", "block", "dry_run", "require_approval"]
},
"script_source": {
"type": "string",
"enum": ["ptc", "agent_planner", "workflow_engine", "unknown"]
}
}
}
}
}
46 changes: 46 additions & 0 deletions docs/governance-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Governance Events

Governance events are lightweight, unsigned JSON objects for real-time telemetry. They are intentionally simple to emit from any runtime (for example JSONL to stdout), then later promoted into signed proof records.

## Two-tier model

1. Emit `GovernanceEvent` JSON (`event_id`, `timestamp`, `event_type`, optional context/detail).
2. Validate against `schemas/v1/governance-event-v1.schema.json`.
3. Promote to a signed proof record with `proof.NewRecordFromEvent(...)`.

Events are not proof records. They are input artifacts for promotion.

## Event type vocabulary

- `tool_gate`
- `permission_check`
- `approval_request`
- `policy_evaluation`
- `guardrail_activation`
- `script_evaluation`

## Emission examples

```python
import json, datetime
print(json.dumps({"event_id":"evt-1","timestamp":datetime.datetime.now(datetime.timezone.utc).isoformat().replace("+00:00","Z"),"event_type":"tool_gate"}))
```

```ts
console.log(JSON.stringify({ event_id: "evt-1", timestamp: new Date().toISOString(), event_type: "tool_gate" }));
```

```go
_ = json.NewEncoder(os.Stdout).Encode(map[string]any{"event_id": "evt-1", "timestamp": time.Now().UTC().Format(time.RFC3339), "event_type": "tool_gate"})
```

## Promotion mapping

`proof.NewRecordFromEvent` maps governance event types to proof record types:

- `tool_gate` -> `policy_enforcement`
- `permission_check` -> `permission_check`
- `approval_request` -> `guardrail_activation`
- `policy_evaluation` -> `policy_enforcement`
- `guardrail_activation` -> `guardrail_activation`
- `script_evaluation` -> `compiled_action`
Loading
Loading