opmsec 0.1.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/.env.example +14 -0
- package/.pnp.cjs +9953 -0
- package/.pnp.loader.mjs +2126 -0
- package/README.md +266 -0
- package/bun.lock +620 -0
- package/bunfig.toml +6 -0
- package/docker-compose.yml +10 -0
- package/package.json +39 -0
- package/packages/cli/package.json +7 -0
- package/packages/cli/src/commands/audit.tsx +142 -0
- package/packages/cli/src/commands/author-view.tsx +247 -0
- package/packages/cli/src/commands/info.tsx +109 -0
- package/packages/cli/src/commands/install.tsx +362 -0
- package/packages/cli/src/commands/passthrough.tsx +36 -0
- package/packages/cli/src/commands/push.tsx +321 -0
- package/packages/cli/src/components/AgentScores.tsx +32 -0
- package/packages/cli/src/components/AuthorInfo.tsx +45 -0
- package/packages/cli/src/components/Header.tsx +24 -0
- package/packages/cli/src/components/PackageCard.tsx +48 -0
- package/packages/cli/src/components/RiskBadge.tsx +32 -0
- package/packages/cli/src/components/ScanReport.tsx +50 -0
- package/packages/cli/src/components/StatusLine.tsx +30 -0
- package/packages/cli/src/index.tsx +111 -0
- package/packages/cli/src/services/avatar.ts +10 -0
- package/packages/cli/src/services/chainpatrol.ts +25 -0
- package/packages/cli/src/services/contract.ts +182 -0
- package/packages/cli/src/services/ens.ts +143 -0
- package/packages/cli/src/services/fileverse.ts +36 -0
- package/packages/cli/src/services/osv.ts +141 -0
- package/packages/cli/src/services/signature.ts +22 -0
- package/packages/cli/src/services/version.ts +10 -0
- package/packages/contracts/contracts/OPMRegistry.sol +253 -0
- package/packages/contracts/hardhat.config.ts +32 -0
- package/packages/contracts/package-lock.json +7772 -0
- package/packages/contracts/package.json +10 -0
- package/packages/contracts/scripts/deploy.ts +28 -0
- package/packages/contracts/test/OPMRegistry.test.ts +101 -0
- package/packages/contracts/tsconfig.json +11 -0
- package/packages/core/package.json +7 -0
- package/packages/core/src/abi.ts +629 -0
- package/packages/core/src/constants.ts +30 -0
- package/packages/core/src/index.ts +5 -0
- package/packages/core/src/prompt.ts +111 -0
- package/packages/core/src/types.ts +104 -0
- package/packages/core/src/utils.ts +50 -0
- package/packages/scanner/package.json +6 -0
- package/packages/scanner/src/agents/agent-configs.ts +24 -0
- package/packages/scanner/src/agents/base-agent.ts +75 -0
- package/packages/scanner/src/index.ts +25 -0
- package/packages/scanner/src/queue/memory-queue.ts +91 -0
- package/packages/scanner/src/services/contract-writer.ts +34 -0
- package/packages/scanner/src/services/fileverse.ts +89 -0
- package/packages/scanner/src/services/npm-registry.ts +159 -0
- package/packages/scanner/src/services/openrouter.ts +86 -0
- package/packages/scanner/src/services/osv.ts +87 -0
- package/packages/scanner/src/services/report-formatter.ts +134 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
contract OPMRegistry {
|
|
5
|
+
struct AuthorProfile {
|
|
6
|
+
address addr;
|
|
7
|
+
string ensName;
|
|
8
|
+
uint256 reputationTotal;
|
|
9
|
+
uint256 reputationCount;
|
|
10
|
+
uint256 packagesPublished;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
struct AgentScore {
|
|
14
|
+
address agent;
|
|
15
|
+
uint8 riskScore;
|
|
16
|
+
string reasoning;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
struct VersionData {
|
|
20
|
+
address author;
|
|
21
|
+
bytes32 checksum;
|
|
22
|
+
bytes signature;
|
|
23
|
+
string reportURI;
|
|
24
|
+
AgentScore[] scores;
|
|
25
|
+
bool exists;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
struct Package {
|
|
29
|
+
string name;
|
|
30
|
+
string[] versions;
|
|
31
|
+
bool exists;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
address public owner;
|
|
35
|
+
mapping(address => bool) public authorizedAgents;
|
|
36
|
+
mapping(address => AuthorProfile) public authors;
|
|
37
|
+
mapping(bytes32 => address) public ensToAuthor;
|
|
38
|
+
mapping(bytes32 => Package) internal packages;
|
|
39
|
+
mapping(bytes32 => mapping(bytes32 => VersionData)) internal versionData;
|
|
40
|
+
mapping(address => bytes32[]) internal authorPackages;
|
|
41
|
+
|
|
42
|
+
uint8 public constant HIGH_RISK_THRESHOLD = 70;
|
|
43
|
+
uint8 public constant MEDIUM_RISK_THRESHOLD = 40;
|
|
44
|
+
|
|
45
|
+
event PackageRegistered(string name, string version, address author, string ensName);
|
|
46
|
+
event ScoreSubmitted(string name, string version, address agent, uint8 riskScore, string reasoning);
|
|
47
|
+
event ReportURISet(string name, string version, string uri);
|
|
48
|
+
event AuthorRegistered(address addr, string ensName);
|
|
49
|
+
event AgentAuthorized(address agent, bool status);
|
|
50
|
+
|
|
51
|
+
modifier onlyOwner() {
|
|
52
|
+
require(msg.sender == owner, "Not owner");
|
|
53
|
+
_;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
modifier onlyAgent() {
|
|
57
|
+
require(authorizedAgents[msg.sender], "Not authorized agent");
|
|
58
|
+
_;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
constructor() {
|
|
62
|
+
owner = msg.sender;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function setAgent(address agent, bool status) external onlyOwner {
|
|
66
|
+
authorizedAgents[agent] = status;
|
|
67
|
+
emit AgentAuthorized(agent, status);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function registerPackage(
|
|
71
|
+
string calldata name,
|
|
72
|
+
string calldata version,
|
|
73
|
+
bytes32 checksum,
|
|
74
|
+
bytes calldata sig,
|
|
75
|
+
string calldata ensName
|
|
76
|
+
) external {
|
|
77
|
+
bytes32 nameHash = keccak256(bytes(name));
|
|
78
|
+
bytes32 versionHash = keccak256(bytes(version));
|
|
79
|
+
|
|
80
|
+
require(!versionData[nameHash][versionHash].exists, "Version already registered");
|
|
81
|
+
|
|
82
|
+
if (!packages[nameHash].exists) {
|
|
83
|
+
packages[nameHash].name = name;
|
|
84
|
+
packages[nameHash].exists = true;
|
|
85
|
+
}
|
|
86
|
+
packages[nameHash].versions.push(version);
|
|
87
|
+
|
|
88
|
+
VersionData storage vd = versionData[nameHash][versionHash];
|
|
89
|
+
vd.author = msg.sender;
|
|
90
|
+
vd.checksum = checksum;
|
|
91
|
+
vd.signature = sig;
|
|
92
|
+
vd.exists = true;
|
|
93
|
+
|
|
94
|
+
if (authors[msg.sender].addr == address(0)) {
|
|
95
|
+
authors[msg.sender].addr = msg.sender;
|
|
96
|
+
authors[msg.sender].ensName = ensName;
|
|
97
|
+
if (bytes(ensName).length > 0) {
|
|
98
|
+
ensToAuthor[keccak256(bytes(ensName))] = msg.sender;
|
|
99
|
+
}
|
|
100
|
+
emit AuthorRegistered(msg.sender, ensName);
|
|
101
|
+
}
|
|
102
|
+
authors[msg.sender].packagesPublished++;
|
|
103
|
+
authorPackages[msg.sender].push(nameHash);
|
|
104
|
+
|
|
105
|
+
emit PackageRegistered(name, version, msg.sender, ensName);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function submitScore(
|
|
109
|
+
string calldata name,
|
|
110
|
+
string calldata version,
|
|
111
|
+
uint8 riskScore,
|
|
112
|
+
string calldata reasoning
|
|
113
|
+
) external onlyAgent {
|
|
114
|
+
bytes32 nameHash = keccak256(bytes(name));
|
|
115
|
+
bytes32 versionHash = keccak256(bytes(version));
|
|
116
|
+
require(versionData[nameHash][versionHash].exists, "Version not found");
|
|
117
|
+
|
|
118
|
+
AgentScore[] storage scores = versionData[nameHash][versionHash].scores;
|
|
119
|
+
for (uint256 i = 0; i < scores.length; i++) {
|
|
120
|
+
require(scores[i].agent != msg.sender, "Agent already scored");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
scores.push(AgentScore({
|
|
124
|
+
agent: msg.sender,
|
|
125
|
+
riskScore: riskScore,
|
|
126
|
+
reasoning: reasoning
|
|
127
|
+
}));
|
|
128
|
+
|
|
129
|
+
authors[versionData[nameHash][versionHash].author].reputationTotal += riskScore;
|
|
130
|
+
authors[versionData[nameHash][versionHash].author].reputationCount++;
|
|
131
|
+
|
|
132
|
+
emit ScoreSubmitted(name, version, msg.sender, riskScore, reasoning);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function setReportURI(
|
|
136
|
+
string calldata name,
|
|
137
|
+
string calldata version,
|
|
138
|
+
string calldata uri
|
|
139
|
+
) external onlyAgent {
|
|
140
|
+
bytes32 nameHash = keccak256(bytes(name));
|
|
141
|
+
bytes32 versionHash = keccak256(bytes(version));
|
|
142
|
+
require(versionData[nameHash][versionHash].exists, "Version not found");
|
|
143
|
+
versionData[nameHash][versionHash].reportURI = uri;
|
|
144
|
+
emit ReportURISet(name, version, uri);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function getAggregateScore(string calldata name, string calldata version) external view returns (uint8) {
|
|
148
|
+
bytes32 nameHash = keccak256(bytes(name));
|
|
149
|
+
bytes32 versionHash = keccak256(bytes(version));
|
|
150
|
+
AgentScore[] storage scores = versionData[nameHash][versionHash].scores;
|
|
151
|
+
if (scores.length == 0) return 0;
|
|
152
|
+
|
|
153
|
+
uint256 total = 0;
|
|
154
|
+
for (uint256 i = 0; i < scores.length; i++) {
|
|
155
|
+
total += scores[i].riskScore;
|
|
156
|
+
}
|
|
157
|
+
return uint8(total / scores.length);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function getSafestVersion(string calldata name, uint8 lookback) external view returns (string memory) {
|
|
161
|
+
bytes32 nameHash = keccak256(bytes(name));
|
|
162
|
+
require(packages[nameHash].exists, "Package not found");
|
|
163
|
+
|
|
164
|
+
string[] storage vers = packages[nameHash].versions;
|
|
165
|
+
uint256 start = vers.length > lookback ? vers.length - lookback : 0;
|
|
166
|
+
uint256 bestScore = type(uint256).max;
|
|
167
|
+
string memory bestVersion = "";
|
|
168
|
+
|
|
169
|
+
for (uint256 i = start; i < vers.length; i++) {
|
|
170
|
+
bytes32 vh = keccak256(bytes(vers[i]));
|
|
171
|
+
AgentScore[] storage scores = versionData[nameHash][vh].scores;
|
|
172
|
+
if (scores.length == 0) continue;
|
|
173
|
+
|
|
174
|
+
uint256 total = 0;
|
|
175
|
+
for (uint256 j = 0; j < scores.length; j++) {
|
|
176
|
+
total += scores[j].riskScore;
|
|
177
|
+
}
|
|
178
|
+
uint256 avg = total / scores.length;
|
|
179
|
+
if (avg < bestScore) {
|
|
180
|
+
bestScore = avg;
|
|
181
|
+
bestVersion = vers[i];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return bestVersion;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function getPackageInfo(
|
|
188
|
+
string calldata name,
|
|
189
|
+
string calldata version
|
|
190
|
+
) external view returns (
|
|
191
|
+
address author,
|
|
192
|
+
bytes32 checksum,
|
|
193
|
+
bytes memory sig,
|
|
194
|
+
string memory ensName,
|
|
195
|
+
string memory reportURI,
|
|
196
|
+
uint8 aggregateScore,
|
|
197
|
+
bool exists
|
|
198
|
+
) {
|
|
199
|
+
bytes32 nameHash = keccak256(bytes(name));
|
|
200
|
+
bytes32 versionHash = keccak256(bytes(version));
|
|
201
|
+
VersionData storage vd = versionData[nameHash][versionHash];
|
|
202
|
+
|
|
203
|
+
if (!vd.exists) {
|
|
204
|
+
return (address(0), bytes32(0), "", "", "", 0, false);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
uint256 total = 0;
|
|
208
|
+
for (uint256 i = 0; i < vd.scores.length; i++) {
|
|
209
|
+
total += vd.scores[i].riskScore;
|
|
210
|
+
}
|
|
211
|
+
uint8 avgScore = vd.scores.length > 0 ? uint8(total / vd.scores.length) : 0;
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
vd.author,
|
|
215
|
+
vd.checksum,
|
|
216
|
+
vd.signature,
|
|
217
|
+
authors[vd.author].ensName,
|
|
218
|
+
vd.reportURI,
|
|
219
|
+
avgScore,
|
|
220
|
+
true
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function getScores(
|
|
225
|
+
string calldata name,
|
|
226
|
+
string calldata version
|
|
227
|
+
) external view returns (AgentScore[] memory) {
|
|
228
|
+
bytes32 nameHash = keccak256(bytes(name));
|
|
229
|
+
bytes32 versionHash = keccak256(bytes(version));
|
|
230
|
+
return versionData[nameHash][versionHash].scores;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function getVersions(string calldata name) external view returns (string[] memory) {
|
|
234
|
+
bytes32 nameHash = keccak256(bytes(name));
|
|
235
|
+
return packages[nameHash].versions;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function getAuthorByAddress(address addr) external view returns (AuthorProfile memory) {
|
|
239
|
+
return authors[addr];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function getAuthorByENS(string calldata ensName) external view returns (AuthorProfile memory) {
|
|
243
|
+
address addr = ensToAuthor[keccak256(bytes(ensName))];
|
|
244
|
+
require(addr != address(0), "ENS not found");
|
|
245
|
+
return authors[addr];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function getAuthorReputation(address addr) external view returns (uint256) {
|
|
249
|
+
AuthorProfile storage a = authors[addr];
|
|
250
|
+
if (a.reputationCount == 0) return 0;
|
|
251
|
+
return a.reputationTotal / a.reputationCount;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { HardhatUserConfig } from "hardhat/config";
|
|
2
|
+
import "@nomicfoundation/hardhat-toolbox";
|
|
3
|
+
import * as dotenv from "dotenv";
|
|
4
|
+
dotenv.config({ path: "../../.env" });
|
|
5
|
+
|
|
6
|
+
const config: HardhatUserConfig = {
|
|
7
|
+
solidity: "0.8.20",
|
|
8
|
+
networks: {
|
|
9
|
+
baseSepolia: {
|
|
10
|
+
url: process.env.BASE_SEPOLIA_RPC_URL || "https://sepolia.base.org",
|
|
11
|
+
accounts: process.env.OPM_PRIVATE_KEY ? [process.env.OPM_PRIVATE_KEY] : [],
|
|
12
|
+
chainId: 84532,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
etherscan: {
|
|
16
|
+
apiKey: {
|
|
17
|
+
baseSepolia: process.env.BASESCAN_API_KEY || "",
|
|
18
|
+
},
|
|
19
|
+
customChains: [
|
|
20
|
+
{
|
|
21
|
+
network: "baseSepolia",
|
|
22
|
+
chainId: 84532,
|
|
23
|
+
urls: {
|
|
24
|
+
apiURL: "https://api-sepolia.basescan.org/api",
|
|
25
|
+
browserURL: "https://sepolia.basescan.org",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default config;
|