@shield-agent/kya 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mcp.json +1 -1
- package/README.md +72 -30
- package/amp/settings.example.json +1 -1
- package/claude/claude_desktop_config.example.json +1 -1
- package/cline/cline_mcp_settings.example.json +1 -1
- package/copilot/mcp-config.example.json +1 -1
- package/dist/certify/attest.js +5 -5
- package/dist/certify/catalog.d.ts +1 -1
- package/dist/certify/catalog.js +3 -3
- package/dist/certify/context.js +1 -1
- package/dist/certify/evaluate.d.ts +2 -2
- package/dist/certify/evaluate.js +12 -12
- package/dist/certify/live.js +2 -2
- package/dist/certify/render.d.ts +1 -1
- package/dist/certify/render.js +10 -10
- package/dist/cli.d.ts +2 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +49 -16
- package/dist/cli.js.map +1 -1
- package/dist/commands/certify.d.ts +1 -1
- package/dist/commands/certify.js +3 -3
- package/dist/commands/connect.d.ts +2 -2
- package/dist/commands/connect.js +22 -22
- package/dist/commands/dash.js +4 -4
- package/dist/commands/gate-serve.js +3 -3
- package/dist/commands/gate.d.ts +1 -1
- package/dist/commands/gate.js +16 -16
- package/dist/commands/hook.d.ts +1 -1
- package/dist/commands/hook.d.ts.map +1 -1
- package/dist/commands/hook.js +55 -18
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/import-traces.d.ts +16 -0
- package/dist/commands/import-traces.d.ts.map +1 -0
- package/dist/commands/import-traces.js +18 -0
- package/dist/commands/import-traces.js.map +1 -0
- package/dist/commands/init.js +1 -1
- package/dist/commands/investigate.d.ts +13 -0
- package/dist/commands/investigate.d.ts.map +1 -0
- package/dist/commands/investigate.js +22 -0
- package/dist/commands/investigate.js.map +1 -0
- package/dist/commands/notify-flush.d.ts +2 -0
- package/dist/commands/notify-flush.d.ts.map +1 -0
- package/dist/commands/notify-flush.js +47 -0
- package/dist/commands/notify-flush.js.map +1 -0
- package/dist/commands/orr.d.ts +3 -3
- package/dist/commands/orr.js +5 -5
- package/dist/commands/receipt-serve.d.ts +1 -1
- package/dist/commands/receipt-serve.js +1 -1
- package/dist/commands/serve-mcp.js +1 -1
- package/dist/commands/start.d.ts +2 -2
- package/dist/commands/start.js +20 -20
- package/dist/commands/stop.d.ts +1 -1
- package/dist/commands/stop.js +6 -6
- package/dist/commands/update.d.ts +19 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +96 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/wire-hooks.d.ts +1 -1
- package/dist/commands/wire-hooks.js +14 -14
- package/dist/commands/wrap.d.ts.map +1 -1
- package/dist/commands/wrap.js +12 -7
- package/dist/commands/wrap.js.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.js +5 -5
- package/dist/dash/dash.d.ts +1 -1
- package/dist/dash/dash.js +3 -3
- package/dist/dash/entitlement.d.ts +1 -1
- package/dist/dash/entitlement.js +1 -1
- package/dist/dash/render.js +2 -2
- package/dist/dash/screens/enterprise.js +9 -9
- package/dist/dash/screens/free.js +5 -5
- package/dist/diff-preview.d.ts +1 -1
- package/dist/diff-preview.js +2 -2
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -1
- package/dist/fs-atomic.d.ts +1 -1
- package/dist/fs-atomic.js +2 -2
- package/dist/gate/binary.js +4 -4
- package/dist/gate/config-gen.d.ts +1 -1
- package/dist/gate/config-gen.js +7 -7
- package/dist/gate/config.d.ts +2 -2
- package/dist/gate/config.js +6 -6
- package/dist/gate/daemon.js +1 -1
- package/dist/gate/discover.d.ts +2 -2
- package/dist/gate/discover.js +7 -7
- package/dist/gate/hosted-sync.js +1 -1
- package/dist/gate/otlp-decode.d.ts +2 -2
- package/dist/gate/otlp-decode.js +2 -2
- package/dist/gate/otlp-receiver.d.ts +1 -1
- package/dist/gate/otlp-receiver.js +3 -3
- package/dist/host-reload.js +11 -11
- package/dist/host-tools.d.ts +1 -1
- package/dist/host-tools.js +1 -1
- package/dist/importers/formats.d.ts +26 -0
- package/dist/importers/formats.d.ts.map +1 -0
- package/dist/importers/formats.js +281 -0
- package/dist/importers/formats.js.map +1 -0
- package/dist/importers/index.d.ts +26 -0
- package/dist/importers/index.d.ts.map +1 -0
- package/dist/importers/index.js +122 -0
- package/dist/importers/index.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/investigate/detectors.d.ts +35 -0
- package/dist/investigate/detectors.d.ts.map +1 -0
- package/dist/investigate/detectors.js +277 -0
- package/dist/investigate/detectors.js.map +1 -0
- package/dist/investigate/fix-brief.d.ts +3 -0
- package/dist/investigate/fix-brief.d.ts.map +1 -0
- package/dist/investigate/fix-brief.js +88 -0
- package/dist/investigate/fix-brief.js.map +1 -0
- package/dist/investigate/incidents.d.ts +19 -0
- package/dist/investigate/incidents.d.ts.map +1 -0
- package/dist/investigate/incidents.js +84 -0
- package/dist/investigate/incidents.js.map +1 -0
- package/dist/investigate/index.d.ts +25 -0
- package/dist/investigate/index.d.ts.map +1 -0
- package/dist/investigate/index.js +46 -0
- package/dist/investigate/index.js.map +1 -0
- package/dist/mcp/protocol.d.ts +2 -2
- package/dist/mcp/protocol.d.ts.map +1 -1
- package/dist/mcp/protocol.js +39 -8
- package/dist/mcp/protocol.js.map +1 -1
- package/dist/mcp/stdio.d.ts +1 -1
- package/dist/mcp/stdio.js +2 -2
- package/dist/mcp-servers.d.ts +2 -2
- package/dist/mcp-servers.js +2 -2
- package/dist/node-upgrade.d.ts +2 -2
- package/dist/node-upgrade.js +9 -9
- package/dist/notify/dispatch.d.ts +20 -0
- package/dist/notify/dispatch.d.ts.map +1 -0
- package/dist/notify/dispatch.js +52 -0
- package/dist/notify/dispatch.js.map +1 -0
- package/dist/notify/index.d.ts +39 -0
- package/dist/notify/index.d.ts.map +1 -0
- package/dist/notify/index.js +119 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/notify/sender.d.ts +56 -0
- package/dist/notify/sender.d.ts.map +1 -0
- package/dist/notify/sender.js +139 -0
- package/dist/notify/sender.js.map +1 -0
- package/dist/notify/templates.d.ts +33 -0
- package/dist/notify/templates.d.ts.map +1 -0
- package/dist/notify/templates.js +119 -0
- package/dist/notify/templates.js.map +1 -0
- package/dist/offline-evaluate.d.ts +2 -2
- package/dist/offline-evaluate.js +3 -3
- package/dist/orr/agentshield.d.ts +2 -2
- package/dist/orr/agentshield.js +4 -4
- package/dist/orr/scorecard.d.ts +1 -1
- package/dist/orr/scorecard.js +3 -3
- package/dist/otel/exporter.d.ts +64 -0
- package/dist/otel/exporter.d.ts.map +1 -0
- package/dist/otel/exporter.js +243 -0
- package/dist/otel/exporter.js.map +1 -0
- package/dist/parse-args.d.ts +1 -1
- package/dist/parse-args.js +1 -1
- package/dist/receipt/auto-open.d.ts +1 -1
- package/dist/receipt/auto-open.js +1 -1
- package/dist/receipt/daemon.d.ts +6 -6
- package/dist/receipt/daemon.js +15 -15
- package/dist/receipt/dashboard.d.ts +1 -1
- package/dist/receipt/dashboard.js +2 -2
- package/dist/receipt/embeddings.d.ts +15 -4
- package/dist/receipt/embeddings.d.ts.map +1 -1
- package/dist/receipt/embeddings.js +116 -35
- package/dist/receipt/embeddings.js.map +1 -1
- package/dist/receipt/enrich.d.ts +2 -2
- package/dist/receipt/enrich.js +5 -5
- package/dist/receipt/gate-card.d.ts +2 -2
- package/dist/receipt/gate-card.d.ts.map +1 -1
- package/dist/receipt/gate-card.js +3 -3
- package/dist/receipt/live-server.d.ts.map +1 -1
- package/dist/receipt/live-server.js +22 -8
- package/dist/receipt/live-server.js.map +1 -1
- package/dist/receipt/receipt-css.d.ts +1 -1
- package/dist/receipt/receipt-css.d.ts.map +1 -1
- package/dist/receipt/receipt-css.js +72 -11
- package/dist/receipt/receipt-css.js.map +1 -1
- package/dist/receipt/render-receipt.d.ts +1 -1
- package/dist/receipt/render-receipt.d.ts.map +1 -1
- package/dist/receipt/render-receipt.js +138 -87
- package/dist/receipt/render-receipt.js.map +1 -1
- package/dist/receipt/share.d.ts +2 -2
- package/dist/receipt/share.js +5 -5
- package/dist/sample-tools.d.ts +1 -1
- package/dist/sample-tools.js +1 -1
- package/dist/sandbox/mock-driver.d.ts +1 -1
- package/dist/sandbox/mock-driver.js +1 -1
- package/dist/sdk/a2a.d.ts +2 -2
- package/dist/sdk/a2a.js +1 -1
- package/dist/sdk/adapters/claude-agent.d.ts +1 -1
- package/dist/sdk/adapters/claude-agent.js +1 -1
- package/dist/sdk/adapters/langgraph.d.ts +1 -1
- package/dist/sdk/adapters/langgraph.js +1 -1
- package/dist/sdk/adapters/mastra.d.ts +1 -1
- package/dist/sdk/adapters/mastra.js +1 -1
- package/dist/sdk/adapters/openai-agents.d.ts +1 -1
- package/dist/sdk/adapters/openai-agents.js +1 -1
- package/dist/sdk/adapters/vercel-ai.d.ts +2 -2
- package/dist/sdk/adapters/vercel-ai.js +1 -1
- package/dist/sdk/govern.d.ts +2 -2
- package/dist/sdk/govern.js +3 -3
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +1 -1
- package/dist/showback/trail-usage.d.ts +30 -0
- package/dist/showback/trail-usage.d.ts.map +1 -0
- package/dist/showback/trail-usage.js +50 -0
- package/dist/showback/trail-usage.js.map +1 -0
- package/dist/sign/evidence-bundle.d.ts +6 -6
- package/dist/sign/evidence-bundle.js +5 -5
- package/dist/star-cta.d.ts +1 -1
- package/dist/star-cta.d.ts.map +1 -1
- package/dist/star-cta.js +3 -3
- package/dist/trail-summary.d.ts +1 -1
- package/dist/trail-summary.js +3 -3
- package/dist/trail.d.ts +8 -2
- package/dist/trail.d.ts.map +1 -1
- package/dist/trail.js +18 -5
- package/dist/trail.js.map +1 -1
- package/dist/update-check.d.ts +17 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +134 -0
- package/dist/update-check.js.map +1 -0
- package/droid/README.md +1 -1
- package/droid/mcp.example.json +1 -1
- package/gemini/settings.example.json +1 -1
- package/grok/README.md +1 -1
- package/kilo/kilo.example.json +1 -1
- package/kimi/mcp.example.json +1 -1
- package/kiro/mcp.example.json +1 -1
- package/manifest.json +1 -1
- package/mastracode/mcp.example.json +1 -1
- package/mcp.json +1 -1
- package/openai/codex.config.example.toml +1 -1
- package/opencode/opencode.example.json +1 -1
- package/package.json +2 -2
- package/qwen/settings.example.json +1 -1
- package/server.json +2 -2
package/.mcp.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"shield-kya": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--no-install", "@shield-agent/kya@0.
|
|
5
|
+
"args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
|
|
6
6
|
"env": {
|
|
7
7
|
"KYA_BASE_URL": "https://shield-agent.com",
|
|
8
8
|
"KYA_API_KEY": "${KYA_API_KEY}",
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[](https://x.com/coscosmico)
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
**AI agents audit trail & traceability.** Every tool call your coding agents make
|
|
11
|
+
**AI agents audit trail & traceability.** Every tool call your coding agents make - gated (Allow / Review / Deny), recorded on a live local dashboard, and certifiable against the Agent Trust Baseline. One command. Free forever under MIT.
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
npm i -g @shield-agent/kya@latest && kya start
|
|
@@ -27,7 +27,7 @@ Walkthrough: [how you use it](https://shield-agent.com/how-kya-works#using).
|
|
|
27
27
|
npx @shield-agent/kya@latest --help
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
Requires **Node.js 24+** (`engines.node: >=24`). On an older Node the CLI offers to install 24 for you (via volta / fnm / nvm / brew), reinstall itself, and finish the command
|
|
30
|
+
Requires **Node.js 24+** (`engines.node: >=24`). On an older Node the CLI offers to install 24 for you (via volta / fnm / nvm / brew), reinstall itself, and finish the command - declining just prints a warning and continues.
|
|
31
31
|
|
|
32
32
|
It works with any host that speaks MCP or OpenAPI. Vertical packs are optional. Shield is the only policy decision point: this gate never auto-approves an irreversible side effect.
|
|
33
33
|
|
|
@@ -43,17 +43,17 @@ npm i -g @shield-agent/kya@latest && kya start
|
|
|
43
43
|
|
|
44
44
|
Run it in your project directory. (From a clone of this repo, `./scripts/install-local.sh` replaces the npm install.)
|
|
45
45
|
|
|
46
|
-
That **inits** `.kya/`, **wires** local MCP (`.mcp.json`, `mcp.json`, `.cursor/mcp.json` → `kya serve-mcp --stdio`), also **wires user-level configs for every installed host it detects** (`~/.claude.json`, `~/.kimi-code/`, `~/.grok/`, `~/.cursor/`, …), and **opens** the live activity report. The report runs in the background
|
|
46
|
+
That **inits** `.kya/`, **wires** local MCP (`.mcp.json`, `mcp.json`, `.cursor/mcp.json` → `kya serve-mcp --stdio`), also **wires user-level configs for every installed host it detects** (`~/.claude.json`, `~/.kimi-code/`, `~/.grok/`, `~/.cursor/`, …), and **opens** the live activity report. The report runs in the background - you get your terminal back; `kya stop` stops it, `kya receipt --open` reopens it. Cursor, Kiro, Qwen, Amp, Droid, Cline, and Grok pick the server up live with no restart (Kimi: just a new session); Claude Code, Codex, OpenCode, Gemini, Copilot CLI, and Kilo CLI load it on next launch - `claude --resume` keeps your conversation.
|
|
47
47
|
|
|
48
|
-

|
|
49
49
|
|
|
50
|
-

|
|
51
51
|
|
|
52
|
-

|
|
53
53
|
|
|
54
|
-

|
|
55
55
|
|
|
56
|
-

|
|
57
57
|
|
|
58
58
|
<!-- Local paths kept in package for offline viewers: assets/report-overview.png, assets/report-certify.png, assets/report-activity.png, assets/report-changes.png, assets/report-gateway.png (legacy: assets/activity-receipt.png) -->
|
|
59
59
|
|
|
@@ -66,7 +66,7 @@ kya start --force # rewrite MCP blocks
|
|
|
66
66
|
|
|
67
67
|
## One command per host
|
|
68
68
|
|
|
69
|
-
`kya start` covers Claude Code, Cursor, and any host that reads `.mcp.json`
|
|
69
|
+
`kya start` covers Claude Code, Cursor, and any host that reads `.mcp.json` - and auto-wires the user-level config of every installed host it detects. For the rest, `kya connect` writes the host's own config dialect directly:
|
|
70
70
|
|
|
71
71
|
```bash
|
|
72
72
|
kya connect claude # ~/.claude.json (merges mcpServers only)
|
|
@@ -78,7 +78,7 @@ kya connect qwen --project # project scope instead of global
|
|
|
78
78
|
kya connect kiro --force # overwrite an existing shield-kya entry
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
Connect merges
|
|
81
|
+
Connect merges - it never rewrites a host config it can't parse, and it keeps your other servers and keys. Supported hosts: `claude`, `grok`, `opencode`, `kilo`, `kiro`, `qwen`, `kimi`, `mastracode`, `amp`, `copilot`, `cursor`. Each wires `serve-mcp --stdio` with `KYA_OFFLINE=1` so the gate starts keyless; set `KYA_API_KEY` in the host env when you point at an authenticated plane.
|
|
82
82
|
|
|
83
83
|
Hosts without a `connect` target still work: `kya wrap --offline -- <agent command>` puts the same evaluate gate in front of any CLI. Per-host recipes with verify steps and troubleshooting live in [docs/hosts/](docs/hosts/).
|
|
84
84
|
|
|
@@ -88,7 +88,7 @@ Hosts without a `connect` target still work: `kya wrap --offline -- <agent comma
|
|
|
88
88
|
|
|
89
89
|
Decision mapping: a local never-list **DENY** blocks the tool call (exit `2` plus `hookSpecificOutput` deny JSON with `permissionDecision: "deny"`). **ALLOW** and **REQUIRE_APPROVE** are recorded on the trail as advisory and the call proceeds. Manual wiring can pass `--strict` on the hook command to also block **REQUIRE_APPROVE**.
|
|
90
90
|
|
|
91
|
-
Hooks are fail-open: any hook error or timeout allows the call. They are alerts plus local never-list enforcement, not the sole barrier
|
|
91
|
+
Hooks are fail-open: any hook error or timeout allows the call. They are alerts plus local never-list enforcement, not the sole barrier - plane enforcement remains the MCP `kya.policy_evaluate` path. Hooks take effect in new sessions; all three hosts load hooks at session start.
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
94
|
kya connect claude --hooks # wire the PreToolUse hook by hand
|
|
@@ -98,9 +98,9 @@ kya connect kimi --hooks
|
|
|
98
98
|
|
|
99
99
|
## Gate (local MCP gateway)
|
|
100
100
|
|
|
101
|
-
`kya gate` puts one loopback-only listener (`127.0.0.1`, default port `3930`) in front of any MCP server you already use. Your host talks to the gateway; the gateway fans out to the real servers. Per-tool policy is generated from the [top-20 server taxonomy](docs/mcp-servers.md)
|
|
101
|
+
`kya gate` puts one loopback-only listener (`127.0.0.1`, default port `3930`) in front of any MCP server you already use. Your host talks to the gateway; the gateway fans out to the real servers. Per-tool policy is generated from the [top-20 server taxonomy](docs/mcp-servers.md) - destructive names (`drop`/`truncate`/`purge`/`transfer`) and each server's ADMIN-tier tools are denied outright (and filtered from `tools/list`), everything else runs in observe mode: allowed, and audited. Every call is traced into the local trail and the live report, and can be forwarded as OTLP to the hosted intake.
|
|
102
102
|
|
|
103
|
-
**Zero-touch:** `kya start` already does this for you. It scans your detected host configs for third-party MCP servers, imports them into `.kya/gateways.json` (recorded with an `importedFrom` provenance field), installs the gateway binary, starts the listener, and rewrites each source host so the imported servers route through the gateway
|
|
103
|
+
**Zero-touch:** `kya start` already does this for you. It scans your detected host configs for third-party MCP servers, imports them into `.kya/gateways.json` (recorded with an `importedFrom` provenance field), installs the gateway binary, starts the listener, and rewrites each source host so the imported servers route through the gateway - the original host config is preserved under `.kya/backups/` before anything is removed. Nothing found → nothing downloaded, no listener. Opt out with `kya start --no-gate` or `KYA_GATE=off`. If the binary download fails (offline, no network), `kya start` warns once and continues without the gateway - host configs stay untouched. The manual path below is still there when you want full control:
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
106
|
kya gate init # scaffold .kya/gateways.json with ready-to-move recipes
|
|
@@ -111,7 +111,7 @@ kya connect claude --gate # point the host at the gateway (server key shield-k
|
|
|
111
111
|
kya gate doctor # binary, config, listener health, loopback-only posture
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
`kya gate stop` stops the supervisor and the binary with it. Honest notes: `kya gate setup` (and `kya start`'s auto-bootstrap, only when it found servers to govern) downloads the pinned gateway binary from our releases
|
|
114
|
+
`kya gate stop` stops the supervisor and the binary with it. Honest notes: `kya gate setup` (and `kya start`'s auto-bootstrap, only when it found servers to govern) downloads the pinned gateway binary from our releases - nothing else downloads anything (the only other network use is the opt-in anonymous usage stats in [docs/telemetry.md](docs/telemetry.md), off unless you say yes); `run` never downloads. Observe mode means allowed calls are recorded, not blocked - the deny set above is the only hard stop, and plane enforcement stays with `kya.policy_evaluate`. `kya connect <host> --gate` covers the same hosts as plain `connect` - grok gets a `[mcp_servers.shield-kya-gate]` url table in its config.toml (Grok supports remote MCP servers over HTTP). Per-server tiers and recipes: [docs/mcp-servers.md](docs/mcp-servers.md).
|
|
115
115
|
|
|
116
116
|
## Longer path (optional)
|
|
117
117
|
|
|
@@ -130,19 +130,19 @@ Install hub: [https://shield-agent.com/install](https://shield-agent.com/install
|
|
|
130
130
|
|
|
131
131
|
## Activity trail (global)
|
|
132
132
|
|
|
133
|
-
One trail for all projects: `~/.kya/trail.jsonl` (`KYA_HOME` overrides `~`). `kya receipt --open` from any directory shows activity from every project. Each event carries its project folder name
|
|
133
|
+
One trail for all projects: `~/.kya/trail.jsonl` (`KYA_HOME` overrides `~`). `kya receipt --open` from any directory shows activity from every project. Each event carries its project folder name - the report adds a Projects rollup once two or more projects appear, and shows the project on each feed entry. Older per-project `<project>/.kya/trail.jsonl` files are still read and merged; no migration. The trail is capped at 1 MB (tail-read: oldest events drop away), shared across all projects.
|
|
134
134
|
|
|
135
|
-
The report itself is a dashboard: a hero row on top (live **Certify** result, verdict mix, activity sparkline, showback) with tabbed sections below
|
|
135
|
+
The report itself is a dashboard: a hero row on top (live **Certify** result, verdict mix, activity sparkline, showback) with tabbed sections below - **Overview** (analytics, sessions, reasons), **Certify** (the full live requirement table - every requirement grouped by domain with status, evidence, and attestation), **Activity** (the filterable event feed), **System** (wired hosts, sandboxes, ORR). Everything is one standalone offline HTML page (the live view adds a single external link: "Star on GitHub"); the live daemon from `kya start` re-renders it on every event.
|
|
136
136
|
|
|
137
137
|
### Sharing a report
|
|
138
138
|
|
|
139
|
-
`kya receipt --share` publishes a **redacted summary** of the current window (aggregate verdict counts, product and reason-code rollups, and the Certify status
|
|
139
|
+
`kya receipt --share` publishes a **redacted summary** of the current window (aggregate verdict counts, product and reason-code rollups, and the Certify status - no paths, no tool arguments, no session IDs) to shield-agent.com and prints a public URL (`/r/<id>`, expires after 7 days) anyone can open - every shared page carries the one-line install so readers can audit their own agents. Point it at a different collector with `--share-url <base>` or `KYA_SHARE_URL`.
|
|
140
140
|
|
|
141
141
|
Sharing is a single attempt by design (storm-proof: no silent retries against the collector); `--share-retries <n>` (max 3) opts into bounded retries on 429/5xx/network failures with exponential backoff + jitter, honoring the server's `Retry-After`.
|
|
142
142
|
|
|
143
143
|
### Natural-language search
|
|
144
144
|
|
|
145
|
-
The **Activity** search box understands plain English. It runs a hybrid of BM25 over tool IDs, summaries, reason codes, projects, and MCP server labels, plus optional local MiniLM semantic reranking. You can type things like `failed stripe transfers`, `files written by grok`, or `approval required production`
|
|
145
|
+
The **Activity** search box understands plain English. It runs a hybrid of BM25 over tool IDs, summaries, reason codes, projects, and MCP server labels, plus optional local MiniLM semantic reranking. You can type things like `failed stripe transfers`, `files written by grok`, or `approval required production` - stopwords and stemming are handled automatically, and the same search works across the global trail.
|
|
146
146
|
|
|
147
147
|
- Offline or `KYA_OFFLINE=1` keeps search purely lexical (no model download).
|
|
148
148
|
- By default the live server downloads `BAAI/bge-small-en-v1.5` once into `~/.kya/models` and caches event vectors in `~/.kya/search-index.json`.
|
|
@@ -183,7 +183,7 @@ Tag sessions with `KYA_HOST=ide` or `KYA_HOST=runtime`. Same policy path either
|
|
|
183
183
|
| `DO_NOT_TRACK` | No | `1` forces anonymous usage stats off, same as `KYA_TELEMETRY=0` |
|
|
184
184
|
|
|
185
185
|
Gate mode can also be pinned in the project's `.kya/config.json`:
|
|
186
|
-
`{"gateMode": "hold"}` or `{"gateMode": "offline"}` (exact values only
|
|
186
|
+
`{"gateMode": "hold"}` or `{"gateMode": "offline"}` (exact values only -
|
|
187
187
|
anything else is ignored). The gate itself (wrap / hook / eval) honors it
|
|
188
188
|
with the precedence flags > env > config > observe, and `kya certify`
|
|
189
189
|
reports through the same resolver, so a certify pass on gate mode always
|
|
@@ -204,7 +204,7 @@ MCP Registry entry: `server.json` plus package `mcpName` `io.github.The-Pixel-Bo
|
|
|
204
204
|
"mcpServers": {
|
|
205
205
|
"shield-kya": {
|
|
206
206
|
"command": "npx",
|
|
207
|
-
"args": ["--no-install", "@shield-agent/kya@0.
|
|
207
|
+
"args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
|
|
208
208
|
"env": {
|
|
209
209
|
"KYA_BASE_URL": "http://127.0.0.1:8090",
|
|
210
210
|
"KYA_API_KEY": "${KYA_API_KEY}",
|
|
@@ -244,7 +244,7 @@ Offline evaluate by default (no network, no hosted plane); an explicit config ho
|
|
|
244
244
|
|
|
245
245
|
```bash
|
|
246
246
|
# Prefer a preinstalled package (no registry auto-install):
|
|
247
|
-
npx --no-install @shield-agent/kya@0.
|
|
247
|
+
npx --no-install @shield-agent/kya@0.23.0 serve-mcp --stdio
|
|
248
248
|
# Or after npm i -g / local install:
|
|
249
249
|
kya serve-mcp --stdio
|
|
250
250
|
```
|
|
@@ -255,7 +255,7 @@ Copy `claude/claude_desktop_config.example.json` into Claude Desktop MCP setting
|
|
|
255
255
|
|
|
256
256
|
## OpenAI (Codex / Responses)
|
|
257
257
|
|
|
258
|
-
**Codex CLI / IDE:** copy `openai/codex.config.example.toml` into `~/.codex/config.toml`. Local stdio uses `npx --no-install @shield-agent/kya@0.
|
|
258
|
+
**Codex CLI / IDE:** copy `openai/codex.config.example.toml` into `~/.codex/config.toml`. Local stdio uses `npx --no-install @shield-agent/kya@0.23.0 serve-mcp --stdio`. Hosted Codex uses `url = "https://shield-agent.com/mcp"` with `bearer_token_env_var = "KYA_API_KEY"`.
|
|
259
259
|
|
|
260
260
|
**Responses API:** see `openai/responses-mcp.example.json` (`server_url` + `Authorization: Bearer <KYA_API_KEY>`).
|
|
261
261
|
|
|
@@ -277,8 +277,8 @@ Each ships a copy-paste example in its own directory; `kya connect <host>` write
|
|
|
277
277
|
|
|
278
278
|
| Host | Setup | Example |
|
|
279
279
|
|------|-------|---------|
|
|
280
|
-
| Claude Code | `kya connect claude` (or `kya start`) |
|
|
281
|
-
| Grok CLI | `kya connect grok` |
|
|
280
|
+
| Claude Code | `kya connect claude` (or `kya start`) | - (merges `~/.claude.json` / `.mcp.json`) |
|
|
281
|
+
| Grok CLI | `kya connect grok` | - (appends `[mcp_servers.shield-kya]` to `~/.grok/config.toml`) |
|
|
282
282
|
| OpenCode | `kya connect opencode` | `opencode/opencode.example.json` |
|
|
283
283
|
| Kilo Code | `kya connect kilo` | `kilo/kilo.example.json` |
|
|
284
284
|
| Kiro | `kya connect kiro` | `kiro/mcp.example.json` |
|
|
@@ -307,7 +307,7 @@ ORR is a reporting board. Scanners, `--scorecard`, and `harness.agentshield` are
|
|
|
307
307
|
|
|
308
308
|
## Certify (continuous agent assurance)
|
|
309
309
|
|
|
310
|
-
`kya certify` evaluates the open **Agent Trust Baseline** catalog (`catalog/agent-trust-baseline-v0.json`
|
|
310
|
+
`kya certify` evaluates the open **Agent Trust Baseline** catalog (`catalog/agent-trust-baseline-v0.json` - 30 requirements across Data & Privacy, Security, Safety, Reliability, Accountability, Society) against local evidence: the global trail, ORR output, wired hosts, sandbox inventory, receipts, showback, and your recorded attestations. It writes a gap report to `.kya/certify/` (JSON + Markdown + HTML). The gap list is your work plan. The receipt report shows the same state live: a **Certify** panel recomputed on every render (so `kya start`'s live report updates as events stream in), plus a dedicated **Certify** tab with the full live requirement table - run `kya certify` for the full gap report + signed evidence bundle.
|
|
311
311
|
|
|
312
312
|
```bash
|
|
313
313
|
npx @shield-agent/kya certify # gap report; exit 1 when gaps exist (CI-friendly)
|
|
@@ -317,11 +317,49 @@ npx @shield-agent/kya certify --attest SOC-01 --text "Acceptable-use policy: htt
|
|
|
317
317
|
npx @shield-agent/kya certify --sign # also emit a signed evidence-bundle.json
|
|
318
318
|
```
|
|
319
319
|
|
|
320
|
-
Certify is **evidence-only**. It never ALLOWs, DENYs, or blocks anything
|
|
320
|
+
Certify is **evidence-only**. It never ALLOWs, DENYs, or blocks anything - the sole PEP remains Shield KYA. Trail-based machine checks never pass on an empty trail (they report `insufficient_evidence`). What a machine cannot check is covered by explicit local attestations (`--attest`), recorded in `.kya/attestations.json` - unverified operator statements, labeled as such.
|
|
321
321
|
|
|
322
|
-
`--sign` emits `evidence-bundle.json`: canonical JSON, ed25519-signed by a locally generated key (`~/.kya/keys/evidence-ed25519.json`, mode 0600, auto-created on first use). Each `--sign` run prints the signing key fingerprint; when the key was just created the CLI notes that key continuity resets there (earlier bundles stay verifiable only under the old pubkey). A self-signed developer key proves bundle **integrity** and **continuity of a key**
|
|
322
|
+
`--sign` emits `evidence-bundle.json`: canonical JSON, ed25519-signed by a locally generated key (`~/.kya/keys/evidence-ed25519.json`, mode 0600, auto-created on first use). Each `--sign` run prints the signing key fingerprint; when the key was just created the CLI notes that key continuity resets there (earlier bundles stay verifiable only under the old pubkey). A self-signed developer key proves bundle **integrity** and **continuity of a key** - **not identity**. Identity binding and the verified badge are the hosted verification product (separate). The bundle format is open and documented in `docs/certify.md`; anyone can verify a bundle offline with the embedded pubkey.
|
|
323
323
|
|
|
324
|
-
`kya certify` is local, free, and offline: no account, no network calls, no license check (it never sends usage stats). The catalog is MIT-licensed and PRs are welcome.
|
|
324
|
+
`kya certify` is local, free, and offline: no account, no network calls, no license check (it never sends usage stats). The catalog is MIT-licensed and PRs are welcome. An EU AI Act crosswalk (baseline requirements mapped to Articles 9-15, 26, 72) ships in [docs/certify-eu-ai-act.md](docs/certify-eu-ai-act.md) and `src/certify/eu-ai-act-map.json`.
|
|
325
|
+
|
|
326
|
+
## Import traces (LangSmith, Langfuse, Phoenix, OTel)
|
|
327
|
+
|
|
328
|
+
Bring existing observability exports into the trail so the receipt and certify see them:
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
kya import --from langsmith ./runs.json
|
|
332
|
+
kya import --from langfuse ./observations.jsonl
|
|
333
|
+
kya import --from otel ./otraces.json
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Imports land as observe-mode events (`host: import`, `reasonCode: IMPORTED`, error runs become `DENY`/`IMPORTED_ERROR`), with latency and token counts mapped when the source carries them. Files over 50MB are refused; malformed records are skipped, never fatal.
|
|
337
|
+
|
|
338
|
+
## Investigate (detections + fix briefs)
|
|
339
|
+
|
|
340
|
+
`kya investigate` runs deterministic local detectors over the trail - no LLM calls: PII leaks in summaries, DENY spikes, approval retry loops, repeated never-event attempts, unknown tools under hold, slow tools. Findings group into incidents, and each incident renders a markdown fix brief shaped to paste into Claude Code / Cursor / Codex.
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
kya investigate # summary: counts by severity + top incidents
|
|
344
|
+
kya investigate --json # findings + incidents + briefs, machine-readable
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Alert webhooks (verdict routing)
|
|
348
|
+
|
|
349
|
+
Route DENY / REQUIRE_APPROVE events to Slack, Linear, Jira, or any webhook. Config lives in `.kya/config.json` (project) or `~/.kya/config.json` (global):
|
|
350
|
+
|
|
351
|
+
```json
|
|
352
|
+
{
|
|
353
|
+
"notify": {
|
|
354
|
+
"webhooks": [
|
|
355
|
+
{ "url": "https://hooks.slack.com/services/...", "template": "slack", "events": ["DENY", "REQUIRE_APPROVE"] },
|
|
356
|
+
{ "url": "https://example.invalid/jira", "template": "jira", "events": ["DENY"] }
|
|
357
|
+
]
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
`KYA_NOTIFY_WEBHOOK=<url>` is the zero-config variant (generic payload). Delivery retries with exponential backoff (250ms/1s/4s + jitter), per-attempt timeouts, a per-URL circuit breaker, and a send rate limiter; payloads are built only from redacted trail fields, with an automatic minimized fallback if the secret scan trips. From short-lived hook/wrap spawns delivery rides a detached helper (`kya notify-flush`), so the gate path never waits on the network.
|
|
325
363
|
|
|
326
364
|
## Optional sandbox wrap (Firecracker)
|
|
327
365
|
|
|
@@ -337,7 +375,7 @@ KYA_SANDBOX=mock kya sandbox kill --sandbox-id <id>
|
|
|
337
375
|
|
|
338
376
|
## Cost showback (observe only)
|
|
339
377
|
|
|
340
|
-
`kya orr run --usage ./usage.json` (or `.kya/usage.json`) adds a showback section: tokens and estimated USD by agent and run. Subagents nest under `parentRunId`. That section is not a billing meter and not a policy gate. Hosted metrics show the same rollup when usage is ingested with a session.
|
|
378
|
+
`kya orr run --usage ./usage.json` (or `.kya/usage.json`) adds a showback section: tokens and estimated USD by agent and run. Subagents nest under `parentRunId`. That section is not a billing meter and not a policy gate. Hosted metrics show the same rollup when usage is ingested with a session. Trail events that carry host-reported token counts (hook payloads with a `usage` object, imported traces) are preferred over the static per-event estimate, and the report states how many window events had real usage.
|
|
341
379
|
|
|
342
380
|
## Enterprise (separate tier)
|
|
343
381
|
|
|
@@ -360,7 +398,9 @@ pnpm build
|
|
|
360
398
|
- [OTLP metrics (OSS + hosted)](docs/otlp.md)
|
|
361
399
|
- [Anonymous usage stats (opt-in): what is sent, controls, retention](docs/telemetry.md)
|
|
362
400
|
- [OWASP MCP governance map](docs/owasp-mcp-governance.md)
|
|
363
|
-
- [kya certify
|
|
401
|
+
- [kya certify - Agent Trust Baseline gap reports](docs/certify.md)
|
|
402
|
+
- [EU AI Act crosswalk for the Agent Trust Baseline](docs/certify-eu-ai-act.md)
|
|
403
|
+
- [Works with your observability stack](docs/marketing/observability-stack.md)
|
|
364
404
|
- [SDK & framework integrations (in-process shims)](docs/sdk-integrations.md)
|
|
365
405
|
- [Hosted operator SSO / SCIM (not in OSS CLI)](docs/hosted-operator-sso.md)
|
|
366
406
|
- See also `LIMITATIONS.md` in this repo
|
|
@@ -383,6 +423,8 @@ Opt-in. Default off.
|
|
|
383
423
|
|
|
384
424
|
**OSS CLI:** set `KYA_OTLP_ENDPOINT` (or `OTEL_EXPORTER_OTLP_ENDPOINT`) to export thin evaluate latency (`kya.client.evaluate.latency`) with tags `verdict` and `host` only. No tool args or API keys.
|
|
385
425
|
|
|
426
|
+
**Verdict span export:** set `KYA_OTLP_EXPORT_ENDPOINT` (or `"otlpExport": { "endpoint": ... }` in `.kya/config.json`) to emit every verdict as an OTLP/JSON GenAI span (`gen_ai.tool.name`, `kya.verdict`, `kya.reason_code`, token attributes when known) to any OTLP/HTTP backend. Long-lived processes (MCP gate, gateway) export every verdict; hook/wrap spawns export DENY / REQUIRE_APPROVE via the detached `notify-flush` helper. Plaintext http is accepted for loopback only unless `"insecure": true`.
|
|
427
|
+
|
|
386
428
|
**Hosted plane:** richer Micrometer gauges and timers when `KYA_OTLP_ENABLED=true`.
|
|
387
429
|
|
|
388
430
|
Full env, Grafana/Datadog notes, forbid list, and a Collector sample: [`docs/otlp.md`](docs/otlp.md).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"amp.mcpServers": {
|
|
3
3
|
"shield-kya": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--no-install", "@shield-agent/kya@0.
|
|
5
|
+
"args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
|
|
6
6
|
"env": {
|
|
7
7
|
"KYA_BASE_URL": "https://shield-agent.com",
|
|
8
8
|
"KYA_API_KEY": "${KYA_API_KEY}",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"shield-kya": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--no-install", "@shield-agent/kya@0.
|
|
5
|
+
"args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
|
|
6
6
|
"env": {
|
|
7
7
|
"KYA_BASE_URL": "https://shield-agent.com",
|
|
8
8
|
"KYA_API_KEY": "${KYA_API_KEY}",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"shield-kya": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--no-install", "@shield-agent/kya@0.
|
|
5
|
+
"args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
|
|
6
6
|
"env": {
|
|
7
7
|
"KYA_BASE_URL": "https://shield-agent.com",
|
|
8
8
|
"KYA_API_KEY": "${KYA_API_KEY}",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"shield-kya": {
|
|
4
4
|
"command": "npx",
|
|
5
|
-
"args": ["--no-install", "@shield-agent/kya@0.
|
|
5
|
+
"args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
|
|
6
6
|
"env": {
|
|
7
7
|
"KYA_BASE_URL": "https://shield-agent.com",
|
|
8
8
|
"KYA_API_KEY": "${KYA_API_KEY}",
|
package/dist/certify/attest.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Operator attestations
|
|
2
|
+
* Operator attestations - the explicit escape hatch for requirements a machine
|
|
3
3
|
* cannot check. Local file only (<cwd>/.kya/attestations.json); never uploaded,
|
|
4
4
|
* never a PEP. Latest attestation per requirement id wins.
|
|
5
5
|
*/
|
|
@@ -13,7 +13,7 @@ const MAX_ATTESTATIONS_BYTES = 256 * 1024;
|
|
|
13
13
|
const MAX_TEXT_CHARS = 2000;
|
|
14
14
|
const REQ_ID = /^[A-Z]+-\d+$/;
|
|
15
15
|
// Attestation text and timestamps are interpolated into single-line evidence
|
|
16
|
-
// strings, reports, and signed bundles
|
|
16
|
+
// strings, reports, and signed bundles - same rule as catalog attest prompts.
|
|
17
17
|
const CONTROL_CHARS = /[\x00-\x1f\x7f]/;
|
|
18
18
|
export function attestationsPath(cwd) {
|
|
19
19
|
return join(configDir(cwd), "attestations.json");
|
|
@@ -80,7 +80,7 @@ export function recordAttestation(cwd, requirementId, text) {
|
|
|
80
80
|
assertNoSecrets(clean);
|
|
81
81
|
}
|
|
82
82
|
catch {
|
|
83
|
-
throw new UsageError("--text looks like it contains a secret
|
|
83
|
+
throw new UsageError("--text looks like it contains a secret - attestations describe policy, never credentials");
|
|
84
84
|
}
|
|
85
85
|
const record = {
|
|
86
86
|
requirementId: id,
|
|
@@ -91,11 +91,11 @@ export function recordAttestation(cwd, requirementId, text) {
|
|
|
91
91
|
const store = { version: 1, attestations: [...others, record] };
|
|
92
92
|
mkdirSync(configDir(cwd), { recursive: true, mode: 0o700 });
|
|
93
93
|
// Atomic tmp+rename: a crash or concurrent run must never truncate the
|
|
94
|
-
// store
|
|
94
|
+
// store - the fail-safe load would silently discard all attestation history.
|
|
95
95
|
const path = attestationsPath(cwd);
|
|
96
96
|
atomicWriteSync(path, `${JSON.stringify(store, null, 2)}\n`);
|
|
97
97
|
try {
|
|
98
|
-
chmodSync(path, 0o600); // operator statements are sensitive
|
|
98
|
+
chmodSync(path, 0o600); // operator statements are sensitive - evidence-bundle perms
|
|
99
99
|
}
|
|
100
100
|
catch {
|
|
101
101
|
/* best-effort on non-POSIX */
|
|
@@ -63,7 +63,7 @@ export interface Catalog {
|
|
|
63
63
|
readonly requirements: readonly CatalogRequirement[];
|
|
64
64
|
}
|
|
65
65
|
export declare const MAX_CATALOG_BYTES: number;
|
|
66
|
-
/** Bundled catalog: <pkg>/catalog/…
|
|
66
|
+
/** Bundled catalog: <pkg>/catalog/… - works from both src/ (vitest) and dist/ (built). */
|
|
67
67
|
export declare function defaultCatalogPath(): string;
|
|
68
68
|
export declare function loadCatalog(path?: string): Catalog;
|
|
69
69
|
export declare function validateCatalog(raw: unknown): Catalog;
|
package/dist/certify/catalog.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent Trust Baseline catalog: types, loader, validator.
|
|
3
3
|
* The bundled catalog/agent-trust-baseline-v0.json at the package root is the
|
|
4
|
-
* source of truth (shipped via package.json "files"). Evidence only
|
|
4
|
+
* source of truth (shipped via package.json "files"). Evidence only - a
|
|
5
5
|
* catalog requirement never ALLOWs anything.
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
@@ -26,7 +26,7 @@ const CHECK_KINDS = new Set([
|
|
|
26
26
|
const ORR_MAX = new Set(["green", "amber"]);
|
|
27
27
|
const TRAIL_MODES = new Set(["observe", "hold", "offline"]);
|
|
28
28
|
const REQ_ID = /^[A-Z]+-\d+$/;
|
|
29
|
-
/** Bundled catalog: <pkg>/catalog/…
|
|
29
|
+
/** Bundled catalog: <pkg>/catalog/… - works from both src/ (vitest) and dist/ (built). */
|
|
30
30
|
export function defaultCatalogPath() {
|
|
31
31
|
return fileURLToPath(new URL("../../catalog/agent-trust-baseline-v0.json", import.meta.url));
|
|
32
32
|
}
|
|
@@ -172,7 +172,7 @@ function parseCheck(id, raw) {
|
|
|
172
172
|
case "attest": {
|
|
173
173
|
if (!nonEmpty(c.prompt))
|
|
174
174
|
throw reqErr(id, "attest requires non-empty prompt");
|
|
175
|
-
// Prompts are interpolated into one-line evidence
|
|
175
|
+
// Prompts are interpolated into one-line evidence - no control chars.
|
|
176
176
|
if (/[\x00-\x1f\x7f]/.test(c.prompt)) {
|
|
177
177
|
throw reqErr(id, "attest prompt must not contain control characters");
|
|
178
178
|
}
|
package/dist/certify/context.js
CHANGED
|
@@ -34,7 +34,7 @@ export function assembleEvidenceContext(cwd, env, now = new Date()) {
|
|
|
34
34
|
return {
|
|
35
35
|
now,
|
|
36
36
|
events,
|
|
37
|
-
// The shared resolver the gate itself uses (config.ts)
|
|
37
|
+
// The shared resolver the gate itself uses (config.ts) - certify can
|
|
38
38
|
// never report a mode the gate would not actually run.
|
|
39
39
|
gateMode: resolveGateMode({ cwd, env }),
|
|
40
40
|
wiredHostCount: wiredHosts.filter((h) => h.wired !== "none").length,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent Trust Baseline evaluators. Pure functions over a pre-assembled
|
|
3
|
-
* EvidenceContext
|
|
3
|
+
* EvidenceContext - no I/O here; all loading lives in certify/context.ts.
|
|
4
4
|
* Evidence only: never a second PEP, never ALLOWs anything. Empty evidence
|
|
5
5
|
* windows yield insufficient_evidence, never a vacuous pass.
|
|
6
6
|
*/
|
|
@@ -88,7 +88,7 @@ export interface CertifyOverallCounts {
|
|
|
88
88
|
export declare function countRequirements(requirements: readonly CertifyRequirementResult[]): CertifyOverallCounts;
|
|
89
89
|
/**
|
|
90
90
|
* Fail-closed overall: zero certifiable evidence (all insufficient_evidence)
|
|
91
|
-
* must never headline as pass
|
|
91
|
+
* must never headline as pass - a green badge requires real evidence.
|
|
92
92
|
* Shared by runCertify and computeLiveCertify so they can never diverge.
|
|
93
93
|
*/
|
|
94
94
|
export declare function computeOverall(counts: CertifyOverallCounts): CertifyReport["overall"];
|
package/dist/certify/evaluate.js
CHANGED
|
@@ -15,7 +15,7 @@ export function countRequirements(requirements) {
|
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* Fail-closed overall: zero certifiable evidence (all insufficient_evidence)
|
|
18
|
-
* must never headline as pass
|
|
18
|
+
* must never headline as pass - a green badge requires real evidence.
|
|
19
19
|
* Shared by runCertify and computeLiveCertify so they can never diverge.
|
|
20
20
|
*/
|
|
21
21
|
export function computeOverall(counts) {
|
|
@@ -138,7 +138,7 @@ export function evaluateRequirement(req, ctx) {
|
|
|
138
138
|
}
|
|
139
139
|
case "config_mode": {
|
|
140
140
|
if (ctx.gateMode === check.not) {
|
|
141
|
-
return result("gap", `gate mode is ${ctx.gateMode}
|
|
141
|
+
return result("gap", `gate mode is ${ctx.gateMode} - set KYA_HOLD=1 / KYA_OFFLINE=1 or "gateMode" in .kya/config.json`);
|
|
142
142
|
}
|
|
143
143
|
return result("pass", `gate mode is ${ctx.gateMode}`);
|
|
144
144
|
}
|
|
@@ -146,33 +146,33 @@ export function evaluateRequirement(req, ctx) {
|
|
|
146
146
|
if (ctx.wiredHostCount >= check.min) {
|
|
147
147
|
return result("pass", `${ctx.wiredHostCount} wired host(s) (need ${check.min})`);
|
|
148
148
|
}
|
|
149
|
-
return result("gap", `${ctx.wiredHostCount} wired host(s), need ${check.min}
|
|
149
|
+
return result("gap", `${ctx.wiredHostCount} wired host(s), need ${check.min} - kya connect <host> --hooks`);
|
|
150
150
|
}
|
|
151
151
|
case "sandbox_inventory": {
|
|
152
152
|
if (ctx.sandboxCount >= check.min) {
|
|
153
153
|
return result("pass", `${ctx.sandboxCount} sandbox record(s)`);
|
|
154
154
|
}
|
|
155
|
-
return result("gap", `no sandbox inventory
|
|
155
|
+
return result("gap", `no sandbox inventory - KYA_SANDBOX=mock kya sandbox spawn`);
|
|
156
156
|
}
|
|
157
157
|
case "receipts_present": {
|
|
158
158
|
if (ctx.receiptCount >= check.min) {
|
|
159
159
|
return result("pass", `${ctx.receiptCount} receipt file(s) in .kya/receipts`);
|
|
160
160
|
}
|
|
161
|
-
return result("gap", `no receipts yet
|
|
161
|
+
return result("gap", `no receipts yet - run kya receipt`);
|
|
162
162
|
}
|
|
163
163
|
case "showback_present": {
|
|
164
164
|
return ctx.showbackPresent
|
|
165
165
|
? result("pass", "showback card present (.kya/usage.json)")
|
|
166
|
-
: result("gap", "no showback card
|
|
166
|
+
: result("gap", "no showback card - add .kya/usage.json or run orr with --usage");
|
|
167
167
|
}
|
|
168
168
|
case "attest": {
|
|
169
169
|
if (attestation)
|
|
170
170
|
return result("attested", `attested ${attestation.at}`);
|
|
171
|
-
return result("gap", `no attestation recorded
|
|
171
|
+
return result("gap", `no attestation recorded - kya certify --attest ${req.id} --text "…" (${check.prompt})`);
|
|
172
172
|
}
|
|
173
173
|
case "orr_overall": {
|
|
174
174
|
if (!ctx.orr) {
|
|
175
|
-
return result("insufficient_evidence", "no ORR report
|
|
175
|
+
return result("insufficient_evidence", "no ORR report - kya orr run --path .");
|
|
176
176
|
}
|
|
177
177
|
if (RATING_RANK[ctx.orr.overall] <= RATING_RANK[check.max]) {
|
|
178
178
|
return result("pass", `ORR overall ${ctx.orr.overall} (max ${check.max})`);
|
|
@@ -181,7 +181,7 @@ export function evaluateRequirement(req, ctx) {
|
|
|
181
181
|
}
|
|
182
182
|
case "orr_category": {
|
|
183
183
|
if (!ctx.orrCategories) {
|
|
184
|
-
return result("insufficient_evidence", "no ORR report
|
|
184
|
+
return result("insufficient_evidence", "no ORR report - kya orr run --path .");
|
|
185
185
|
}
|
|
186
186
|
const rating = ctx.orrCategories[check.id];
|
|
187
187
|
if (!rating) {
|
|
@@ -194,7 +194,7 @@ export function evaluateRequirement(req, ctx) {
|
|
|
194
194
|
}
|
|
195
195
|
case "orr_fresh": {
|
|
196
196
|
if (!ctx.orr || !ctx.orr.generatedAt) {
|
|
197
|
-
return result("insufficient_evidence", "no ORR report
|
|
197
|
+
return result("insufficient_evidence", "no ORR report - kya orr run --path .");
|
|
198
198
|
}
|
|
199
199
|
const t = Date.parse(ctx.orr.generatedAt);
|
|
200
200
|
if (Number.isNaN(t)) {
|
|
@@ -202,7 +202,7 @@ export function evaluateRequirement(req, ctx) {
|
|
|
202
202
|
}
|
|
203
203
|
const nowMs = ctx.now.getTime();
|
|
204
204
|
if (t > nowMs) {
|
|
205
|
-
return result("insufficient_evidence", "ORR generatedAt is in the future
|
|
205
|
+
return result("insufficient_evidence", "ORR generatedAt is in the future - clock skew, re-run kya orr run");
|
|
206
206
|
}
|
|
207
207
|
const ageMs = nowMs - t;
|
|
208
208
|
// Exact ms comparison decides; the floored day count is display-only.
|
|
@@ -210,7 +210,7 @@ export function evaluateRequirement(req, ctx) {
|
|
|
210
210
|
if (ageMs <= check.maxAgeDays * DAY_MS) {
|
|
211
211
|
return result("pass", `ORR is ${ageDays}d old (max ${check.maxAgeDays}d)`);
|
|
212
212
|
}
|
|
213
|
-
return result("gap", `ORR is ${ageDays}d old (max ${check.maxAgeDays}d)
|
|
213
|
+
return result("gap", `ORR is ${ageDays}d old (max ${check.maxAgeDays}d) - re-run kya orr run`);
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
// Unreachable: RequirementCheck union is exhaustive (checked at compile time).
|
package/dist/certify/live.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Live in-memory certify evaluation
|
|
2
|
+
* Live in-memory certify evaluation - the "certified right now" panel data.
|
|
3
3
|
* Recomputes the full Agent Trust Baseline from local evidence on every call
|
|
4
4
|
* and returns a real CertifyReport, identical in shape to `kya certify` output
|
|
5
5
|
* so the receipt panel and any other consumer can treat them interchangeably.
|
|
@@ -11,7 +11,7 @@ import { loadCatalog } from "./catalog.js";
|
|
|
11
11
|
import { assembleEvidenceContext } from "./context.js";
|
|
12
12
|
import { computeOverall, countRequirements, DAY_MS, evaluateRequirement, trailStats, trailWindow, } from "./evaluate.js";
|
|
13
13
|
export function computeLiveCertify(cwd, env = process.env, windowDays = 30, now = new Date()) {
|
|
14
|
-
// Public SDK surface
|
|
14
|
+
// Public SDK surface - enforce the same window rule as the CLI boundary.
|
|
15
15
|
if (!Number.isInteger(windowDays) || windowDays < 1 || windowDays > 366) {
|
|
16
16
|
throw new UsageError("windowDays must be an integer between 1 and 366");
|
|
17
17
|
}
|
package/dist/certify/render.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CertifyReport } from "./evaluate.js";
|
|
2
|
-
/** Shared domain display labels
|
|
2
|
+
/** Shared domain display labels - the receipt Certify tab uses these too. */
|
|
3
3
|
export declare const DOMAIN_LABELS: Record<string, string>;
|
|
4
4
|
/** Catalog order of domains, derived from requirement order. */
|
|
5
5
|
export declare function domainOrder(requirements: readonly {
|
package/dist/certify/render.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markdown + standalone HTML rendering for the certify gap report.
|
|
3
3
|
* Same visual language as the activity receipt (pills, panels, dark/light),
|
|
4
|
-
* own minimal CSS
|
|
4
|
+
* own minimal CSS - the certify page is fully standalone and offline.
|
|
5
5
|
*/
|
|
6
6
|
import { assertNoSecrets, clip, stripEscapes } from "../dash/render.js";
|
|
7
|
-
/** Shared domain display labels
|
|
7
|
+
/** Shared domain display labels - the receipt Certify tab uses these too. */
|
|
8
8
|
export const DOMAIN_LABELS = {
|
|
9
9
|
"data-privacy": "Data & Privacy",
|
|
10
10
|
security: "Security",
|
|
@@ -37,7 +37,7 @@ export function formatCertifyMarkdown(report) {
|
|
|
37
37
|
`- **Result:** ${o.result === "gap" ? "GAP" : "PASS"}`,
|
|
38
38
|
`- **Generated:** ${mdText(report.generatedAt)}`,
|
|
39
39
|
`- **Window:** last ${report.window.days} days (${mdText(report.window.since)} → ${mdText(report.window.until)})`,
|
|
40
|
-
`- **Trail:** ${report.trail.eventCount} events in window
|
|
40
|
+
`- **Trail:** ${report.trail.eventCount} events in window - allow ${report.trail.verdictMix.ALLOW} · deny ${report.trail.verdictMix.DENY} · review ${report.trail.verdictMix.REQUIRE_APPROVE}`,
|
|
41
41
|
`- **Tally:** ${o.pass} pass · ${o.gap} gap · ${o.insufficientEvidence} insufficient evidence · ${o.attested} attested`,
|
|
42
42
|
"",
|
|
43
43
|
"## Gaps (work plan)",
|
|
@@ -45,12 +45,12 @@ export function formatCertifyMarkdown(report) {
|
|
|
45
45
|
const gaps = report.requirements.filter((r) => r.status === "gap");
|
|
46
46
|
if (gaps.length === 0) {
|
|
47
47
|
lines.push(o.result === "gap"
|
|
48
|
-
? "- No certifiable evidence in this window
|
|
48
|
+
? "- No certifiable evidence in this window - every requirement is insufficient_evidence. Run the gate first (kya wrap / kya connect), then re-run kya certify."
|
|
49
49
|
: "- (none)");
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
52
52
|
for (const r of gaps) {
|
|
53
|
-
lines.push(`- **${r.id}** [${r.severity}] ${mdText(r.title)}
|
|
53
|
+
lines.push(`- **${r.id}** [${r.severity}] ${mdText(r.title)} - ${mdText(r.evidence)}`);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
lines.push("");
|
|
@@ -84,7 +84,7 @@ const STATUS_TONE = {
|
|
|
84
84
|
};
|
|
85
85
|
function requirementRow(r) {
|
|
86
86
|
const att = r.attestation
|
|
87
|
-
? `<div class="att">attested ${esc(r.attestation.at)}
|
|
87
|
+
? `<div class="att">attested ${esc(r.attestation.at)} - ${esc(clip(r.attestation.text, 200))}</div>`
|
|
88
88
|
: "";
|
|
89
89
|
return ` <li class="req">
|
|
90
90
|
<span class="pill ${STATUS_TONE[r.status]}">${esc(r.status.replace(/_/g, " "))}</span>
|
|
@@ -102,8 +102,8 @@ export function renderCertifyHtml(report) {
|
|
|
102
102
|
const gaps = report.requirements.filter((r) => r.status === "gap");
|
|
103
103
|
const gapList = gaps.length === 0
|
|
104
104
|
? o.result === "gap"
|
|
105
|
-
? `<p class="empty">No certifiable evidence in this window
|
|
106
|
-
: `<p class="empty">No gaps. Evidence-only report
|
|
105
|
+
? `<p class="empty">No certifiable evidence in this window - every requirement is insufficient evidence. Run the gate first (kya wrap / kya connect), then re-run kya certify.</p>`
|
|
106
|
+
: `<p class="empty">No gaps. Evidence-only report - not a certificate.</p>`
|
|
107
107
|
: `<ol class="gaps">
|
|
108
108
|
${gaps
|
|
109
109
|
.map((r) => ` <li><strong>${esc(r.id)}</strong> <span class="sev ${esc(r.severity)}">${esc(r.severity)}</span> ${esc(clip(r.title, 120))}<br/><span class="mute">${esc(clip(r.evidence, 240))}</span></li>`)
|
|
@@ -127,7 +127,7 @@ ${rows.map((r) => requirementRow(r)).join("\n")}
|
|
|
127
127
|
<head>
|
|
128
128
|
<meta charset="utf-8"/>
|
|
129
129
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
130
|
-
<title>Certify
|
|
130
|
+
<title>Certify - ${esc(report.catalog.id)} v${esc(report.catalog.version)}</title>
|
|
131
131
|
<style>
|
|
132
132
|
:root {
|
|
133
133
|
color-scheme: dark;
|
|
@@ -215,7 +215,7 @@ ${rows.map((r) => requirementRow(r)).join("\n")}
|
|
|
215
215
|
</head>
|
|
216
216
|
<body>
|
|
217
217
|
<main>
|
|
218
|
-
<h1>Certify
|
|
218
|
+
<h1>Certify - <code>${esc(report.catalog.id)} v${esc(report.catalog.version)}</code></h1>
|
|
219
219
|
<div class="sub">generated ${esc(report.generatedAt)} · window last ${report.window.days} days (${esc(report.window.since)} → ${esc(report.window.until)}) · ${report.trail.eventCount} trail events in window</div>
|
|
220
220
|
<span class="result ${o.result}">${o.result === "gap" ? "GAP" : "PASS"}</span>
|
|
221
221
|
<div class="stats" role="group" aria-label="Tally">
|