opmsec 0.1.0 → 0.1.3
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/.env.example +23 -13
- package/README.md +256 -173
- package/docs/architecture/agents.mdx +77 -0
- package/docs/architecture/benchmarks.mdx +65 -0
- package/docs/architecture/overview.mdx +58 -0
- package/docs/architecture/scanner.mdx +53 -0
- package/docs/cli/audit.mdx +35 -0
- package/docs/cli/check.mdx +44 -0
- package/docs/cli/fix.mdx +49 -0
- package/docs/cli/info.mdx +44 -0
- package/docs/cli/install.mdx +71 -0
- package/docs/cli/push.mdx +99 -0
- package/docs/cli/register-agent.mdx +80 -0
- package/docs/cli/view.mdx +52 -0
- package/docs/concepts/multi-agent-consensus.mdx +58 -0
- package/docs/concepts/on-chain-registry.mdx +74 -0
- package/docs/concepts/security-model.mdx +76 -0
- package/docs/concepts/zk-agent-verification.mdx +82 -0
- package/docs/configuration.mdx +82 -0
- package/docs/contract/deployment.mdx +57 -0
- package/docs/contract/events.mdx +115 -0
- package/docs/contract/functions.mdx +220 -0
- package/docs/contract/overview.mdx +58 -0
- package/docs/favicon.svg +5 -0
- package/docs/introduction.mdx +43 -0
- package/docs/logo/dark.svg +5 -0
- package/docs/logo/light.svg +5 -0
- package/docs/mint.json +106 -0
- package/docs/quickstart.mdx +133 -0
- package/package.json +3 -3
- package/packages/cli/src/commands/author-view.tsx +9 -1
- package/packages/cli/src/commands/check.tsx +318 -0
- package/packages/cli/src/commands/fix.tsx +294 -0
- package/packages/cli/src/commands/install.tsx +229 -33
- package/packages/cli/src/commands/push.tsx +53 -22
- package/packages/cli/src/commands/register-agent.tsx +227 -0
- package/packages/cli/src/components/AgentScores.tsx +20 -6
- package/packages/cli/src/components/Hyperlink.tsx +30 -0
- package/packages/cli/src/components/ScanReport.tsx +3 -2
- package/packages/cli/src/index.tsx +41 -5
- package/packages/cli/src/services/avatar.ts +43 -6
- package/packages/cli/src/services/chainpatrol.ts +20 -17
- package/packages/cli/src/services/contract.ts +41 -8
- package/packages/cli/src/services/ens.ts +3 -5
- package/packages/cli/src/services/fileverse.ts +12 -13
- package/packages/cli/src/services/typosquat.ts +166 -0
- package/packages/contracts/circuits/accuracy_verifier.circom +101 -0
- package/packages/contracts/contracts/OPMRegistry.sol +63 -0
- package/packages/contracts/scripts/deploy.ts +22 -3
- package/packages/core/src/abi.ts +221 -0
- package/packages/core/src/benchmarks.ts +450 -0
- package/packages/core/src/constants.ts +20 -0
- package/packages/core/src/index.ts +2 -0
- package/packages/core/src/model-rankings.ts +115 -0
- package/packages/core/src/prompt.ts +58 -0
- package/packages/core/src/types.ts +41 -0
- package/packages/core/src/utils.ts +7 -3
- package/packages/scanner/src/agents/base-agent.ts +13 -3
- package/packages/scanner/src/index.ts +5 -2
- package/packages/scanner/src/queue/memory-queue.ts +8 -3
- package/packages/scanner/src/services/benchmark-runner.ts +114 -0
- package/packages/scanner/src/services/contract-writer.ts +2 -3
- package/packages/scanner/src/services/fileverse.ts +26 -7
- package/packages/scanner/src/services/openrouter.ts +46 -0
- package/packages/scanner/src/services/report-formatter.ts +122 -3
- package/packages/scanner/src/services/zk-verifier.ts +118 -0
- package/packages/web/.next/app-build-manifest.json +15 -0
- package/packages/web/.next/build-manifest.json +20 -0
- package/packages/web/.next/package.json +1 -0
- package/packages/web/.next/prerender-manifest.json +11 -0
- package/packages/web/.next/react-loadable-manifest.json +1 -0
- package/packages/web/.next/routes-manifest.json +1 -0
- package/packages/web/.next/server/app/page.js +272 -0
- package/packages/web/.next/server/app/page_client-reference-manifest.js +1 -0
- package/packages/web/.next/server/app-paths-manifest.json +3 -0
- package/packages/web/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/packages/web/.next/server/middleware-build-manifest.js +22 -0
- package/packages/web/.next/server/middleware-manifest.json +6 -0
- package/packages/web/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/packages/web/.next/server/next-font-manifest.js +1 -0
- package/packages/web/.next/server/next-font-manifest.json +1 -0
- package/packages/web/.next/server/pages-manifest.json +1 -0
- package/packages/web/.next/server/server-reference-manifest.js +1 -0
- package/packages/web/.next/server/server-reference-manifest.json +5 -0
- package/packages/web/.next/server/vendor-chunks/@swc.js +55 -0
- package/packages/web/.next/server/vendor-chunks/next.js +3010 -0
- package/packages/web/.next/server/webpack-runtime.js +209 -0
- package/packages/web/.next/static/chunks/app/layout.js +39 -0
- package/packages/web/.next/static/chunks/app/page.js +61 -0
- package/packages/web/.next/static/chunks/app-pages-internals.js +182 -0
- package/packages/web/.next/static/chunks/main-app.js +1882 -0
- package/packages/web/.next/static/chunks/polyfills.js +1 -0
- package/packages/web/.next/static/chunks/webpack.js +1393 -0
- package/packages/web/.next/static/css/app/layout.css +1237 -0
- package/packages/web/.next/static/development/_buildManifest.js +1 -0
- package/packages/web/.next/static/development/_ssgManifest.js +1 -0
- package/packages/web/.next/static/webpack/633457081244afec._.hot-update.json +1 -0
- package/packages/web/.next/static/webpack/6fee6306e0f98869.webpack.hot-update.json +1 -0
- package/packages/web/.next/static/webpack/73e341375c8d429e.webpack.hot-update.json +1 -0
- package/packages/web/.next/static/webpack/app/layout.6fee6306e0f98869.hot-update.js +22 -0
- package/packages/web/.next/static/webpack/app/layout.73e341375c8d429e.hot-update.js +22 -0
- package/packages/web/.next/static/webpack/app/page.6fee6306e0f98869.hot-update.js +22 -0
- package/packages/web/.next/static/webpack/app/page.73e341375c8d429e.hot-update.js +22 -0
- package/packages/web/.next/static/webpack/webpack.6fee6306e0f98869.hot-update.js +12 -0
- package/packages/web/.next/static/webpack/webpack.73e341375c8d429e.hot-update.js +12 -0
- package/packages/web/.next/trace +5 -0
- package/packages/web/.next/types/app/layout.ts +84 -0
- package/packages/web/.next/types/app/page.ts +84 -0
- package/packages/web/.next/types/cache-life.d.ts +141 -0
- package/packages/web/.next/types/package.json +1 -0
- package/packages/web/.next/types/routes.d.ts +57 -0
- package/packages/web/.next/types/validator.ts +61 -0
- package/packages/web/app/globals.css +75 -0
- package/packages/web/app/layout.tsx +26 -0
- package/packages/web/app/page.tsx +358 -0
- package/packages/web/bun.lock +300 -0
- package/packages/web/next-env.d.ts +6 -0
- package/packages/web/next.config.ts +5 -0
- package/packages/web/package.json +26 -0
- package/packages/web/postcss.config.mjs +8 -0
- package/packages/web/public/favicon.svg +5 -0
- package/packages/web/public/logo.svg +7 -0
- package/packages/web/tailwind.config.ts +48 -0
- package/packages/web/tsconfig.json +21 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'opm view / opm whois'
|
|
3
|
+
description: 'Author profile and published packages.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# opm view / opm whois
|
|
7
|
+
|
|
8
|
+
Show author profile and published packages. Resolves ENS identity and displays on-chain reputation.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
<CodeGroup>
|
|
13
|
+
|
|
14
|
+
```bash View by ENS name
|
|
15
|
+
opm view vitalik.eth
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```bash Whois (auto-appends .eth)
|
|
19
|
+
opm whois vitalik
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
</CodeGroup>
|
|
23
|
+
|
|
24
|
+
<Note>
|
|
25
|
+
<code>opm view <name.eth></code> shows author profile. <code>opm view <pkg></code> (without <code>.eth</code>) delegates to <code>opm info</code>.
|
|
26
|
+
</Note>
|
|
27
|
+
|
|
28
|
+
## Output
|
|
29
|
+
|
|
30
|
+
### Identity
|
|
31
|
+
|
|
32
|
+
- **ENS name** — Resolved identity
|
|
33
|
+
- **Address** — Wallet address
|
|
34
|
+
- **Bio** — ENS description text record
|
|
35
|
+
- **URL** — ENS url record
|
|
36
|
+
- **GitHub** — <code>com.github</code> text record
|
|
37
|
+
- **Twitter** — <code>com.twitter</code> text record
|
|
38
|
+
- **Email** — ENS email record
|
|
39
|
+
- **Avatar** — Rendered from ENS avatar record
|
|
40
|
+
|
|
41
|
+
### Author Stats
|
|
42
|
+
|
|
43
|
+
- **Packages published** — Count from OPMRegistry
|
|
44
|
+
- **Avg reputation** — Risk badge (lower = better)
|
|
45
|
+
|
|
46
|
+
### Published Packages
|
|
47
|
+
|
|
48
|
+
For each package: name, version, risk score, checksum, signature status, and report URI link.
|
|
49
|
+
|
|
50
|
+
<Note>
|
|
51
|
+
No environment variables are required. ENS resolution uses public resolvers.
|
|
52
|
+
</Note>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Multi-Agent Consensus'
|
|
3
|
+
description: 'Three LLMs run in parallel, submit scores on-chain, and aggregate via intelligence-weighted averaging.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Multi-Agent Consensus
|
|
7
|
+
|
|
8
|
+
OPM uses **three heterogeneous AI agents** that run in parallel to analyze packages. Each agent independently evaluates source code, version history, and CVE data, then submits its risk score and reasoning on-chain. Scores are aggregated using **intelligence-weighted averaging** to produce a final risk assessment.
|
|
9
|
+
|
|
10
|
+
## Agent Configuration
|
|
11
|
+
|
|
12
|
+
| Agent | OpenRouter (preferred) | OpenAI (fallback) |
|
|
13
|
+
|-------|------------------------|--------------------|
|
|
14
|
+
| agent-1 | Claude Sonnet 4 | GPT-4.1 |
|
|
15
|
+
| agent-2 | Gemini 2.5 Flash | GPT-4.1 Mini |
|
|
16
|
+
| agent-3 | DeepSeek Chat | GPT-4.1 Nano |
|
|
17
|
+
|
|
18
|
+
Model diversity reduces single-model blind spots and improves consensus reliability. Override models via `AGENT1_MODEL`, `AGENT2_MODEL`, and `AGENT3_MODEL`.
|
|
19
|
+
|
|
20
|
+
## Analysis Pipeline
|
|
21
|
+
|
|
22
|
+
Each agent receives:
|
|
23
|
+
|
|
24
|
+
- Packed tarball contents (scannable extensions: `.js`, `.ts`, `.mjs`, `.cjs`, `.json`)
|
|
25
|
+
- `package.json` and dependency metadata
|
|
26
|
+
- Version history and changelog context
|
|
27
|
+
- CVE/OSV advisory data when available
|
|
28
|
+
|
|
29
|
+
Each agent produces structured JSON:
|
|
30
|
+
|
|
31
|
+
- **Risk score** (0–100) with categorical classification (LOW, MEDIUM, HIGH, CRITICAL)
|
|
32
|
+
- **Vulnerability enumeration** with severity, category, file path, and evidence
|
|
33
|
+
- **Supply chain indicators**: install scripts, native bindings, obfuscated code, network calls, filesystem access, process spawning, `eval` usage, environment variable access
|
|
34
|
+
- **Version history analysis**: changelog risk, maintainer changes, dependency graph mutations
|
|
35
|
+
- **Recommendation**: SAFE, CAUTION, WARN, or BLOCK
|
|
36
|
+
|
|
37
|
+
## On-Chain Submission
|
|
38
|
+
|
|
39
|
+
Agent wallets call `OPMRegistry.submitScore(name, version, riskScore, reasoning)` for each package version. Each agent may submit only once per version. Scores are stored in the contract's `versionData` mapping.
|
|
40
|
+
|
|
41
|
+
## Intelligence-Weighted Aggregation
|
|
42
|
+
|
|
43
|
+
Scores are aggregated using model weights from the **Artificial Analysis API**:
|
|
44
|
+
|
|
45
|
+
- **Intelligence Index**: General reasoning and knowledge
|
|
46
|
+
- **Coding Index**: Code generation and analysis capability
|
|
47
|
+
|
|
48
|
+
Weights are applied to each agent's score before computing the mean. This favors higher-capability models when consensus is ambiguous.
|
|
49
|
+
|
|
50
|
+
<Note>
|
|
51
|
+
If `ARTIFICIAL_ANALYSIS_API_KEY` is unset or the API is unavailable, OPM falls back to **equal weighting** (simple arithmetic mean).
|
|
52
|
+
</Note>
|
|
53
|
+
|
|
54
|
+
## Fallback Behavior
|
|
55
|
+
|
|
56
|
+
- **Provider**: When `OPENROUTER_API_KEY` is set, OPM routes through OpenRouter. Otherwise it uses `OPENAI_API_KEY` with the GPT-4.1 family.
|
|
57
|
+
- **Force provider**: Set `LLM_PROVIDER=openrouter` or `LLM_PROVIDER=openai` to override auto-detection.
|
|
58
|
+
- **OpenAI models**: `gpt-4.1`, `gpt-4.1-mini`, `gpt-4.1-nano` for agent-1, agent-2, agent-3 respectively.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'On-chain Registry'
|
|
3
|
+
description: 'OPMRegistry.sol stores packages, versions, author profiles, agent scores, and report URIs on Base Sepolia.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# On-chain Registry
|
|
7
|
+
|
|
8
|
+
The **OPMRegistry** smart contract is the canonical on-chain store for package metadata, author profiles, agent scores, and report URIs. It implements a domain-specific form of the [ERC-8004 (Trustless Agents)](https://eips.ethereum.org/EIPS/eip-8004) three-registry architecture.
|
|
9
|
+
|
|
10
|
+
## Deployment
|
|
11
|
+
|
|
12
|
+
| Property | Value |
|
|
13
|
+
|----------|-------|
|
|
14
|
+
| **Chain** | Base Sepolia |
|
|
15
|
+
| **Chain ID** | 84532 |
|
|
16
|
+
| **Contract Address** | `0x16684391fc9bf48246B08Afe16d1a57BFa181d48` |
|
|
17
|
+
| **Explorer** | [BaseScan](https://sepolia.basescan.org/address/0x16684391fc9bf48246B08Afe16d1a57BFa181d48) |
|
|
18
|
+
|
|
19
|
+
Override via `CONTRACT_ADDRESS` in your environment.
|
|
20
|
+
|
|
21
|
+
## Data Structures
|
|
22
|
+
|
|
23
|
+
| Struct | Fields |
|
|
24
|
+
|--------|--------|
|
|
25
|
+
| `AuthorProfile` | `addr`, `ensName`, `reputationTotal`, `reputationCount`, `packagesPublished` |
|
|
26
|
+
| `AgentScore` | `agent`, `riskScore`, `reasoning` |
|
|
27
|
+
| `VersionData` | `author`, `checksum`, `signature`, `reportURI`, `scores[]`, `exists` |
|
|
28
|
+
| `Package` | `name`, `versions[]`, `exists` |
|
|
29
|
+
| `RegisteredAgent` | `agentAddress`, `name`, `model`, `systemPromptHash`, `proofHash`, `registeredAt`, `active` |
|
|
30
|
+
|
|
31
|
+
## Key Functions
|
|
32
|
+
|
|
33
|
+
| Function | Access | Description |
|
|
34
|
+
|----------|--------|-------------|
|
|
35
|
+
| `registerPackage(name, version, checksum, sig, ensName)` | Public | Register a new package version with checksum, signature, and ENS binding |
|
|
36
|
+
| `submitScore(name, version, riskScore, reasoning)` | Authorized agents | Submit a risk score (0–100) and reasoning for a package version |
|
|
37
|
+
| `setReportURI(name, version, uri)` | Authorized agents | Attach a Fileverse report URI to a package version |
|
|
38
|
+
| `getPackageInfo(name, version)` | View | Retrieve full metadata and aggregate score for a package version |
|
|
39
|
+
| `getScores(name, version)` | View | Return all individual agent scores for a version |
|
|
40
|
+
| `getAggregateScore(name, version)` | View | Compute mean risk score across all agent submissions |
|
|
41
|
+
| `getSafestVersion(name, lookback)` | View | Return the lowest-risk version within a configurable lookback window |
|
|
42
|
+
| `getVersions(name)` | View | List all registered versions of a package |
|
|
43
|
+
| `getAuthorByAddress(addr)` | View | Retrieve author profile by Ethereum address |
|
|
44
|
+
| `getAuthorByENS(ensName)` | View | Resolve author profile by ENS name |
|
|
45
|
+
| `getAuthorReputation(addr)` | View | Compute author's mean risk score across all packages |
|
|
46
|
+
| `registerAgent(name, model, systemPromptHash, proofHash)` | Public | Permissionless agent registration (requires valid ZK proof) |
|
|
47
|
+
|
|
48
|
+
## Events
|
|
49
|
+
|
|
50
|
+
| Event | Parameters |
|
|
51
|
+
|-------|------------|
|
|
52
|
+
| `PackageRegistered` | `name`, `version`, `author`, `ensName` |
|
|
53
|
+
| `ScoreSubmitted` | `name`, `version`, `agent`, `riskScore`, `reasoning` |
|
|
54
|
+
| `ReportURISet` | `name`, `version`, `uri` |
|
|
55
|
+
| `AuthorRegistered` | `addr`, `ensName` |
|
|
56
|
+
| `AgentAuthorized` | `agent`, `status` |
|
|
57
|
+
| `AgentRegistered` | `agent`, `name`, `model`, `systemPromptHash`, `proofHash`, `timestamp` |
|
|
58
|
+
|
|
59
|
+
## Author Reputation
|
|
60
|
+
|
|
61
|
+
Author reputation is computed as:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
reputation = reputationTotal / reputationCount
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Where `reputationTotal` accumulates each agent's score for every version of every package authored by that address. This provides a cumulative risk score average across all published packages.
|
|
68
|
+
|
|
69
|
+
## Risk Thresholds (Contract)
|
|
70
|
+
|
|
71
|
+
| Constant | Value |
|
|
72
|
+
|----------|-------|
|
|
73
|
+
| `HIGH_RISK_THRESHOLD` | 70 |
|
|
74
|
+
| `MEDIUM_RISK_THRESHOLD` | 40 |
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Security Model'
|
|
3
|
+
description: 'OPM defense-in-depth: cryptographic attestation, multi-agent AI, CVE integration, supply chain checks, and ENS-based trust.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Security Model
|
|
7
|
+
|
|
8
|
+
OPM employs a **defense-in-depth** architecture across five layers. No single layer is sufficient; together they mitigate supply chain injection, typosquatting, dependency confusion, maintainer takeover, and known vulnerability exploitation.
|
|
9
|
+
|
|
10
|
+
## 1. Cryptographic Layer
|
|
11
|
+
|
|
12
|
+
- **SHA-256 checksum**: Computed over the packed tarball; stored on-chain and verified at install time
|
|
13
|
+
- **ECDSA signature**: secp256k1 signature over the checksum, derived from the author's Ethereum private key
|
|
14
|
+
- **On-chain registration**: Checksum, signature, and author binding stored in `OPMRegistry` on Base Sepolia
|
|
15
|
+
|
|
16
|
+
Installation is blocked if the tarball checksum does not match the on-chain value or if the signature verification fails.
|
|
17
|
+
|
|
18
|
+
## 2. AI Layer
|
|
19
|
+
|
|
20
|
+
Three heterogeneous LLMs analyze packages in parallel:
|
|
21
|
+
|
|
22
|
+
- Static analysis of source code, dependency metadata, and version history
|
|
23
|
+
- Each agent submits a risk score (0–100) and reasoning on-chain
|
|
24
|
+
- **Intelligence-weighted aggregation** via the Artificial Analysis API (Intelligence Index, Coding Index)
|
|
25
|
+
- Fallback to equal weighting if the API is unavailable
|
|
26
|
+
|
|
27
|
+
<CardGroup cols={2}>
|
|
28
|
+
<Card title="Agent 1" icon="robot">
|
|
29
|
+
Claude Sonnet 4 (OpenRouter) / GPT-4.1 (OpenAI fallback)
|
|
30
|
+
</Card>
|
|
31
|
+
<Card title="Agent 2" icon="robot">
|
|
32
|
+
Gemini 2.5 Flash (OpenRouter) / GPT-4.1 Mini (OpenAI fallback)
|
|
33
|
+
</Card>
|
|
34
|
+
<Card title="Agent 3" icon="robot">
|
|
35
|
+
DeepSeek Chat (OpenRouter) / GPT-4.1 Nano (OpenAI fallback)
|
|
36
|
+
</Card>
|
|
37
|
+
</CardGroup>
|
|
38
|
+
|
|
39
|
+
## 3. CVE Layer
|
|
40
|
+
|
|
41
|
+
- **OSV (Open Source Vulnerabilities)**: Real-time CVE and GHSA advisory data
|
|
42
|
+
- **GitHub Advisory Database**: Integrated via OSV API
|
|
43
|
+
- **CVSS v3** base score computation for severity classification
|
|
44
|
+
- **CRITICAL** severity: installation blocked
|
|
45
|
+
- **HIGH** severity: warning with suggested fix version
|
|
46
|
+
|
|
47
|
+
## 4. Supply Chain Layer
|
|
48
|
+
|
|
49
|
+
| Check | Description |
|
|
50
|
+
|-------|-------------|
|
|
51
|
+
| **Typosquat detection** | Package names compared against npm search results and download-count differentials; AI agents assess name similarity |
|
|
52
|
+
| **Dependency confusion** | Scoped vs unscoped name conflicts and internal package shadowing surfaced during `opm check` |
|
|
53
|
+
| **ChainPatrol blocklist** | Fallback blocklist for packages absent from the on-chain registry (requires `CHAINPATROL_API_KEY`) |
|
|
54
|
+
|
|
55
|
+
AI agents also flag: install scripts, native bindings, obfuscated code, network calls, filesystem access, process spawning, `eval` usage, and environment variable access.
|
|
56
|
+
|
|
57
|
+
## 5. Trust Layer
|
|
58
|
+
|
|
59
|
+
- **ENS identity resolution**: Author addresses resolved to ENS names (Sepolia, Mainnet fallback)
|
|
60
|
+
- **On-chain author reputation**: Cumulative risk score average across all published packages
|
|
61
|
+
- **Author profiles**: ENS text records (avatar, description, URL, GitHub, Twitter, email) for human verification
|
|
62
|
+
|
|
63
|
+
## Risk Thresholds
|
|
64
|
+
|
|
65
|
+
| Range | Level | Effect |
|
|
66
|
+
|-------|-------|--------|
|
|
67
|
+
| 0–20 | LOW | Safe to install |
|
|
68
|
+
| 21–40 | MEDIUM | Flagged for caution |
|
|
69
|
+
| 41–70 | HIGH | Warnings triggered |
|
|
70
|
+
| 71–100 | CRITICAL | High risk |
|
|
71
|
+
|
|
72
|
+
| Threshold | Value | Behavior |
|
|
73
|
+
|-----------|-------|----------|
|
|
74
|
+
| Block threshold (CLI) | 80 | `opm push` blocks publication; `opm install` blocks installation |
|
|
75
|
+
| `HIGH_RISK_THRESHOLD` (contract) | 70 | Packages above trigger warnings |
|
|
76
|
+
| `MEDIUM_RISK_THRESHOLD` (contract) | 40 | Packages above flagged for caution |
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'ZK Agent Verification'
|
|
3
|
+
description: 'Permissionless agent registration requires passing a benchmark suite and proving 100% accuracy via zero-knowledge proofs.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ZK Agent Verification
|
|
7
|
+
|
|
8
|
+
OPM supports **permissionless agent registration** on the on-chain registry. To prevent malicious or spamming agents from participating, agents must pass a benchmark suite and prove **100% accuracy** via a zero-knowledge proof—without revealing the test data or individual results.
|
|
9
|
+
|
|
10
|
+
## Benchmark Suite
|
|
11
|
+
|
|
12
|
+
The benchmark consists of **10 labeled test cases** covering:
|
|
13
|
+
|
|
14
|
+
| Category | Description |
|
|
15
|
+
|----------|-------------|
|
|
16
|
+
| Clean packages | Legitimate, low-risk packages |
|
|
17
|
+
| Typosquats | Name-similar malicious packages |
|
|
18
|
+
| Env exfiltration | Environment variable exfiltration attempts |
|
|
19
|
+
| Obfuscated code | Heavily obfuscated or minified payloads |
|
|
20
|
+
| Postinstall attacks | Malicious `postinstall` scripts |
|
|
21
|
+
| Known CVEs | Packages with known vulnerabilities |
|
|
22
|
+
| Dependency confusion | Scoped vs unscoped name conflicts |
|
|
23
|
+
|
|
24
|
+
Each test case has an **expected output**: a risk level (LOW, MEDIUM, HIGH, CRITICAL) and score range. Expected outputs are committed via a hash before the agent runs.
|
|
25
|
+
|
|
26
|
+
## Verification Flow
|
|
27
|
+
|
|
28
|
+
1. **Commitment**: Expected outputs hashed with a salt → `commitmentHash`
|
|
29
|
+
2. **Execution**: Candidate agent runs against all 10 cases
|
|
30
|
+
3. **Comparison**: Actual outputs compared to expected; `passed = 1` iff all match
|
|
31
|
+
4. **Proof**: ZK proof binds `commitmentHash`, `passed`, and `result_hash` without revealing test data or individual results
|
|
32
|
+
5. **Registration**: Only agents with `passed = 1` (100% accuracy) are registered on-chain
|
|
33
|
+
|
|
34
|
+
## Circom Circuit
|
|
35
|
+
|
|
36
|
+
The `accuracy_verifier.circom` circuit implements the verification logic:
|
|
37
|
+
|
|
38
|
+
- **Private inputs**: `expected[N]`, `actual[N]`, `salt`
|
|
39
|
+
- **Public input**: `commitmentHash` (Poseidon hash of `salt` and `expected[0..N-1]`)
|
|
40
|
+
- **Public outputs**: `passed` (1 if all match, 0 otherwise), `proofHash`
|
|
41
|
+
|
|
42
|
+
The circuit:
|
|
43
|
+
|
|
44
|
+
1. Verifies the commitment: `hash(salt, expected[0..N-1]) === commitmentHash`
|
|
45
|
+
2. Checks equality for each test case: `expected[i] === actual[i]`
|
|
46
|
+
3. Computes `passed` as the product of all match bits (1 iff all match)
|
|
47
|
+
4. Outputs `proofHash = hash(commitmentHash, passed, salt)` binding the result to the commitment
|
|
48
|
+
|
|
49
|
+
<CodeGroup>
|
|
50
|
+
|
|
51
|
+
```bash Compile
|
|
52
|
+
circom accuracy_verifier.circom --r1cs --wasm --sym -o build/
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```bash Trusted setup
|
|
56
|
+
snarkjs groth16 setup build/accuracy_verifier.r1cs pot12_final.ptau build/accuracy_verifier_0000.zkey
|
|
57
|
+
snarkjs zkey contribute build/accuracy_verifier_0000.zkey build/accuracy_verifier_final.zkey --name="opm-ceremony"
|
|
58
|
+
snarkjs zkey export verificationkey build/accuracy_verifier_final.zkey build/verification_key.json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```bash Prove
|
|
62
|
+
snarkjs groth16 prove build/accuracy_verifier_final.zkey build/accuracy_verifier_js/accuracy_verifier.wasm input.json build/proof.json build/public.json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```bash Verify
|
|
66
|
+
snarkjs groth16 verify build/verification_key.json build/public.json build/proof.json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
</CodeGroup>
|
|
70
|
+
|
|
71
|
+
## On-Chain Registration
|
|
72
|
+
|
|
73
|
+
Agents call `OPMRegistry.registerAgent(name, model, systemPromptHash, proofHash)` with a valid proof hash. The contract:
|
|
74
|
+
|
|
75
|
+
- Requires `proofHash != bytes32(0)`
|
|
76
|
+
- Rejects agents already authorized or registered
|
|
77
|
+
- Stores `RegisteredAgent` with `proofHash` for auditability
|
|
78
|
+
- Auto-authorizes the agent for `submitScore` and `setReportURI`
|
|
79
|
+
|
|
80
|
+
<Warning>
|
|
81
|
+
The Circom circuit is available for on-chain verification. A Solidity verifier can be exported via `snarkjs zkey export solidityverifier` for full trustless verification in future contract upgrades.
|
|
82
|
+
</Warning>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Configuration'
|
|
3
|
+
description: 'Environment variables for OPM: signing keys, API keys, RPC URLs, and model overrides.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Configuration
|
|
7
|
+
|
|
8
|
+
OPM is configured via environment variables. Read-only commands (`install`, `audit`, `info`, `view`, `whois`, `check`) work with zero configuration. Author-side commands (`push`, `register-agent`) require keys and optional overrides.
|
|
9
|
+
|
|
10
|
+
## Environment Variables
|
|
11
|
+
|
|
12
|
+
### Signing & Identity
|
|
13
|
+
|
|
14
|
+
| Variable | Description | Required For |
|
|
15
|
+
|----------|-------------|--------------|
|
|
16
|
+
| `OPM_SIGNING_KEY` | Author's Ethereum private key for package signing (ECDSA secp256k1) | `opm push` |
|
|
17
|
+
| `OPM_PRIVATE_KEY` | Alias for `OPM_SIGNING_KEY` | `opm push` |
|
|
18
|
+
| `AGENT_PRIVATE_KEY` | Agent wallet key for score submission and agent registration; must hold Base Sepolia ETH for gas | `opm push`, `register-agent` |
|
|
19
|
+
|
|
20
|
+
### npm
|
|
21
|
+
|
|
22
|
+
| Variable | Description | Required For |
|
|
23
|
+
|----------|-------------|--------------|
|
|
24
|
+
| `NPM_TOKEN` | npm automation token for publish (bypasses 2FA) | `opm push` (optional; use `--token` flag otherwise) |
|
|
25
|
+
|
|
26
|
+
### AI / LLM
|
|
27
|
+
|
|
28
|
+
| Variable | Description | Required For |
|
|
29
|
+
|----------|-------------|--------------|
|
|
30
|
+
| `OPENROUTER_API_KEY` | OpenRouter API key for multi-model access (Claude, Gemini, DeepSeek) | `opm push`, `opm check` (at least one of OPENROUTER or OPENAI) |
|
|
31
|
+
| `OPENAI_API_KEY` | OpenAI API key; fallback to GPT-4.1 family | `opm push`, `opm check` |
|
|
32
|
+
| `LLM_PROVIDER` | Force provider: `"openrouter"` or `"openai"` | Optional override |
|
|
33
|
+
| `AGENT1_MODEL` | Override agent-1 model (default: Claude Sonnet 4) | Optional |
|
|
34
|
+
| `AGENT2_MODEL` | Override agent-2 model (default: Gemini 2.5 Flash) | Optional |
|
|
35
|
+
| `AGENT3_MODEL` | Override agent-3 model (default: DeepSeek Chat) | Optional |
|
|
36
|
+
|
|
37
|
+
### Report Storage
|
|
38
|
+
|
|
39
|
+
| Variable | Description | Required For |
|
|
40
|
+
|----------|-------------|--------------|
|
|
41
|
+
| `FILEVERSE_API_KEY` | API key for report uploads to IPFS (generate at [ddocs.new](https://ddocs.new) → Settings → Developer Mode) | `opm push` report uploads |
|
|
42
|
+
| `FILEVERSE_API_URL` | Override Fileverse API base URL (default: `http://localhost:8001`) | Optional |
|
|
43
|
+
|
|
44
|
+
### On-Chain Registry
|
|
45
|
+
|
|
46
|
+
| Variable | Description | Default |
|
|
47
|
+
|----------|-------------|---------|
|
|
48
|
+
| `CONTRACT_ADDRESS` | OPMRegistry contract address | `0x16684391fc9bf48246B08Afe16d1a57BFa181d48` |
|
|
49
|
+
| `BASE_SEPOLIA_RPC_URL` | Base Sepolia RPC endpoint | `https://sepolia.base.org` |
|
|
50
|
+
|
|
51
|
+
### External Services
|
|
52
|
+
|
|
53
|
+
| Variable | Description | Required For |
|
|
54
|
+
|----------|-------------|--------------|
|
|
55
|
+
| `CHAINPATROL_API_KEY` | ChainPatrol API key for blocklist checks | Optional; enables blocklist fallback |
|
|
56
|
+
| `ARTIFICIAL_ANALYSIS_API_KEY` | API key for model intelligence rankings (intelligence-weighted scoring) | Optional; falls back to equal weighting if unset |
|
|
57
|
+
|
|
58
|
+
## Example `.env`
|
|
59
|
+
|
|
60
|
+
<CodeGroup>
|
|
61
|
+
|
|
62
|
+
```bash Minimal
|
|
63
|
+
# No env vars needed for: install, audit, info, view, whois, check
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```bash Full (push + reports)
|
|
67
|
+
OPM_SIGNING_KEY=0x...
|
|
68
|
+
AGENT_PRIVATE_KEY=0x...
|
|
69
|
+
NPM_TOKEN=npm_...
|
|
70
|
+
OPENROUTER_API_KEY=sk-or-...
|
|
71
|
+
FILEVERSE_API_KEY=...
|
|
72
|
+
CONTRACT_ADDRESS=0x16684391fc9bf48246B08Afe16d1a57BFa181d48
|
|
73
|
+
BASE_SEPOLIA_RPC_URL=https://sepolia.base.org
|
|
74
|
+
CHAINPATROL_API_KEY=...
|
|
75
|
+
ARTIFICIAL_ANALYSIS_API_KEY=...
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
</CodeGroup>
|
|
79
|
+
|
|
80
|
+
<Tip>
|
|
81
|
+
Start the Fileverse API server locally before `opm push` if using report uploads: `npx @fileverse/api --apiKey <YOUR_API_KEY>`
|
|
82
|
+
</Tip>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Deployment'
|
|
3
|
+
description: 'Deploy OPMRegistry to Base Sepolia.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Deployment
|
|
7
|
+
|
|
8
|
+
## Prerequisites
|
|
9
|
+
|
|
10
|
+
- **Node.js** (v18+)
|
|
11
|
+
- **Hardhat** (via <code>npx hardhat</code>)
|
|
12
|
+
- **Base Sepolia ETH** for gas (obtain from [Base Sepolia Faucet](https://www.coinbase.com/faucets/base-ethereum-goerli-faucet))
|
|
13
|
+
|
|
14
|
+
## Environment Variables
|
|
15
|
+
|
|
16
|
+
Create a <code>.env</code> file in <code>packages/contracts</code>:
|
|
17
|
+
|
|
18
|
+
<CodeGroup>
|
|
19
|
+
|
|
20
|
+
```bash .env
|
|
21
|
+
BASE_SEPOLIA_RPC_URL=https://sepolia.base.org
|
|
22
|
+
DEPLOYER_PRIVATE_KEY=0x... # Deployer wallet (receives owner role)
|
|
23
|
+
AGENT_PRIVATE_KEY=0x... # Optional: auto-authorize this agent after deploy
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
</CodeGroup>
|
|
27
|
+
|
|
28
|
+
## Commands
|
|
29
|
+
|
|
30
|
+
<Steps>
|
|
31
|
+
<Step title="Compile">
|
|
32
|
+
<CodeGroup>
|
|
33
|
+
```bash
|
|
34
|
+
npx hardhat compile
|
|
35
|
+
```
|
|
36
|
+
</CodeGroup>
|
|
37
|
+
</Step>
|
|
38
|
+
<Step title="Deploy">
|
|
39
|
+
<CodeGroup>
|
|
40
|
+
```bash
|
|
41
|
+
npx hardhat run scripts/deploy.ts --network baseSepolia
|
|
42
|
+
```
|
|
43
|
+
</CodeGroup>
|
|
44
|
+
</Step>
|
|
45
|
+
<Step title="Authorize initial agents">
|
|
46
|
+
If <code>AGENT_PRIVATE_KEY</code> is set, the deploy script automatically calls <code>setAgent(agentAddress, true)</code>. Otherwise, call <code>setAgent</code> on the contract via Hardhat console or a custom script.
|
|
47
|
+
</Step>
|
|
48
|
+
</Steps>
|
|
49
|
+
|
|
50
|
+
## Post-Deploy
|
|
51
|
+
|
|
52
|
+
1. **Set contract address** — Add <code>CONTRACT_ADDRESS=<deployed-address></code> to your CLI and scanner <code>.env</code>.
|
|
53
|
+
2. **Verify on BaseScan** — Run <code>npx hardhat verify --network baseSepolia <CONTRACT_ADDRESS></code> to publish source code for verification.
|
|
54
|
+
|
|
55
|
+
<Note>
|
|
56
|
+
The deploy script outputs the contract address. The default OPM contract is <code>0x16684391fc9bf48246B08Afe16d1a57BFa181d48</code> on Base Sepolia.
|
|
57
|
+
</Note>
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Contract Events'
|
|
3
|
+
description: 'All OPMRegistry events with parameters.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Contract Events
|
|
7
|
+
|
|
8
|
+
## PackageRegistration
|
|
9
|
+
|
|
10
|
+
### PackageRegistered
|
|
11
|
+
|
|
12
|
+
```solidity
|
|
13
|
+
event PackageRegistered(string name, string version, address author, string ensName);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Emitted when a package version is registered via <code>registerPackage</code>.
|
|
17
|
+
|
|
18
|
+
| Parameter | Type | Description |
|
|
19
|
+
|-----------|------|-------------|
|
|
20
|
+
| name | string | Package name |
|
|
21
|
+
| version | string | Semantic version |
|
|
22
|
+
| author | address | Author wallet address |
|
|
23
|
+
| ensName | string | Author ENS name |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Score Submission
|
|
28
|
+
|
|
29
|
+
### ScoreSubmitted
|
|
30
|
+
|
|
31
|
+
```solidity
|
|
32
|
+
event ScoreSubmitted(string name, string version, address agent, uint8 riskScore, string reasoning);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Emitted when an agent submits a risk score via <code>submitScore</code>.
|
|
36
|
+
|
|
37
|
+
| Parameter | Type | Description |
|
|
38
|
+
|-----------|------|-------------|
|
|
39
|
+
| name | string | Package name |
|
|
40
|
+
| version | string | Semantic version |
|
|
41
|
+
| agent | address | Agent wallet address |
|
|
42
|
+
| riskScore | uint8 | Risk score 0–100 |
|
|
43
|
+
| reasoning | string | Agent reasoning |
|
|
44
|
+
|
|
45
|
+
### ReportURISet
|
|
46
|
+
|
|
47
|
+
```solidity
|
|
48
|
+
event ReportURISet(string name, string version, string uri);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Emitted when an agent sets the report URI via <code>setReportURI</code>.
|
|
52
|
+
|
|
53
|
+
| Parameter | Type | Description |
|
|
54
|
+
|-----------|------|-------------|
|
|
55
|
+
| name | string | Package name |
|
|
56
|
+
| version | string | Semantic version |
|
|
57
|
+
| uri | string | Fileverse/IPFS report URI |
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Author
|
|
62
|
+
|
|
63
|
+
### AuthorRegistered
|
|
64
|
+
|
|
65
|
+
```solidity
|
|
66
|
+
event AuthorRegistered(address addr, string ensName);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Emitted when an author is first registered (on first <code>registerPackage</code> call).
|
|
70
|
+
|
|
71
|
+
| Parameter | Type | Description |
|
|
72
|
+
|-----------|------|-------------|
|
|
73
|
+
| addr | address | Author wallet address |
|
|
74
|
+
| ensName | string | Author ENS name |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Agent Management
|
|
79
|
+
|
|
80
|
+
### AgentAuthorized
|
|
81
|
+
|
|
82
|
+
```solidity
|
|
83
|
+
event AgentAuthorized(address agent, bool status);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Emitted when an agent is authorized or deauthorized via <code>setAgent</code> or <code>revokeAgent</code>, or when a new agent registers via <code>registerAgent</code>.
|
|
87
|
+
|
|
88
|
+
| Parameter | Type | Description |
|
|
89
|
+
|-----------|------|-------------|
|
|
90
|
+
| agent | address | Agent wallet address |
|
|
91
|
+
| status | bool | true = authorized, false = deauthorized |
|
|
92
|
+
|
|
93
|
+
### AgentRegistered
|
|
94
|
+
|
|
95
|
+
```solidity
|
|
96
|
+
event AgentRegistered(
|
|
97
|
+
address indexed agent,
|
|
98
|
+
string name,
|
|
99
|
+
string model,
|
|
100
|
+
bytes32 systemPromptHash,
|
|
101
|
+
bytes32 proofHash,
|
|
102
|
+
uint256 timestamp
|
|
103
|
+
);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Emitted when a new agent registers via <code>registerAgent</code> (permissionless ZK-verified registration).
|
|
107
|
+
|
|
108
|
+
| Parameter | Type | Description |
|
|
109
|
+
|-----------|------|-------------|
|
|
110
|
+
| agent | address | Agent wallet address (indexed) |
|
|
111
|
+
| name | string | Agent identifier |
|
|
112
|
+
| model | string | LLM model |
|
|
113
|
+
| systemPromptHash | bytes32 | Keccak256 of system prompt |
|
|
114
|
+
| proofHash | bytes32 | Keccak256 of ZK proof |
|
|
115
|
+
| timestamp | uint256 | Block timestamp |
|