calllint 1.0.0 → 1.0.1
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/dist/index.js +60 -189
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4409,6 +4409,9 @@ function approveCommand(args, deps) {
|
|
|
4409
4409
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
|
|
4410
4410
|
import { resolve as resolve4 } from "node:path";
|
|
4411
4411
|
|
|
4412
|
+
// ../../packages/signature/src/ed25519.ts
|
|
4413
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
4414
|
+
|
|
4412
4415
|
// ../../node_modules/.pnpm/@noble+ed25519@2.3.0/node_modules/@noble/ed25519/index.js
|
|
4413
4416
|
var ed25519_CURVE = {
|
|
4414
4417
|
p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
|
|
@@ -4759,8 +4762,8 @@ var hash2extK = (hashed) => {
|
|
|
4759
4762
|
};
|
|
4760
4763
|
var getExtendedPublicKeyAsync = (priv) => sha512a(toU8(priv, L)).then(hash2extK);
|
|
4761
4764
|
var getExtendedPublicKey = (priv) => hash2extK(sha512s(toU8(priv, L)));
|
|
4762
|
-
var
|
|
4763
|
-
var
|
|
4765
|
+
var getPublicKey = (priv) => getExtendedPublicKey(priv).pointBytes;
|
|
4766
|
+
var hashFinishS = (res) => res.finish(sha512s(res.hashable));
|
|
4764
4767
|
var _sign = (e, rBytes, msg) => {
|
|
4765
4768
|
const { pointBytes: P2, scalar: s } = e;
|
|
4766
4769
|
const r = modL_LE(rBytes);
|
|
@@ -4772,11 +4775,11 @@ var _sign = (e, rBytes, msg) => {
|
|
|
4772
4775
|
};
|
|
4773
4776
|
return { hashable, finish };
|
|
4774
4777
|
};
|
|
4775
|
-
var
|
|
4778
|
+
var sign = (msg, privKey) => {
|
|
4776
4779
|
const m = toU8(msg);
|
|
4777
|
-
const e =
|
|
4778
|
-
const rBytes =
|
|
4779
|
-
return
|
|
4780
|
+
const e = getExtendedPublicKey(privKey);
|
|
4781
|
+
const rBytes = sha512s(e.prefix, m);
|
|
4782
|
+
return hashFinishS(_sign(e, rBytes, m));
|
|
4780
4783
|
};
|
|
4781
4784
|
var veriOpts = { zip215: true };
|
|
4782
4785
|
var _verify = (sig, msg, pub, opts = veriOpts) => {
|
|
@@ -4808,7 +4811,7 @@ var _verify = (sig, msg, pub, opts = veriOpts) => {
|
|
|
4808
4811
|
};
|
|
4809
4812
|
return { hashable, finish };
|
|
4810
4813
|
};
|
|
4811
|
-
var
|
|
4814
|
+
var verify = (s, m, p, opts = veriOpts) => hashFinishS(_verify(s, m, p, opts));
|
|
4812
4815
|
var etc = {
|
|
4813
4816
|
sha512Async: async (...messages) => {
|
|
4814
4817
|
const s = subtle();
|
|
@@ -4899,21 +4902,26 @@ function base64urlDecode(str) {
|
|
|
4899
4902
|
}
|
|
4900
4903
|
|
|
4901
4904
|
// ../../packages/signature/src/ed25519.ts
|
|
4902
|
-
|
|
4905
|
+
etc.sha512Sync = (...messages) => {
|
|
4906
|
+
const hash = createHash2("sha512");
|
|
4907
|
+
hash.update(etc.concatBytes(...messages));
|
|
4908
|
+
return new Uint8Array(hash.digest());
|
|
4909
|
+
};
|
|
4910
|
+
function generateKeypair(keyId) {
|
|
4903
4911
|
const privateKey = utils.randomPrivateKey();
|
|
4904
|
-
const publicKey =
|
|
4912
|
+
const publicKey = getPublicKey(privateKey);
|
|
4905
4913
|
return {
|
|
4906
4914
|
privateKey,
|
|
4907
4915
|
publicKey,
|
|
4908
4916
|
keyId
|
|
4909
4917
|
};
|
|
4910
4918
|
}
|
|
4911
|
-
|
|
4919
|
+
function signReceipt(unsignedReceipt, keypair) {
|
|
4912
4920
|
const canonical = stableStringify(unsignedReceipt);
|
|
4913
4921
|
const hash = sha256(canonical);
|
|
4914
4922
|
const hashHex = hash.slice(7);
|
|
4915
4923
|
const hashBytes = Buffer.from(hashHex, "hex");
|
|
4916
|
-
const signatureBytes =
|
|
4924
|
+
const signatureBytes = sign(hashBytes, keypair.privateKey);
|
|
4917
4925
|
const signatureBase64url = base64urlEncode(signatureBytes);
|
|
4918
4926
|
return {
|
|
4919
4927
|
algorithm: "ed25519",
|
|
@@ -4922,7 +4930,7 @@ async function signReceipt(unsignedReceipt, keypair) {
|
|
|
4922
4930
|
signed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4923
4931
|
};
|
|
4924
4932
|
}
|
|
4925
|
-
|
|
4933
|
+
function verifyReceipt2(signedReceipt, publicKey) {
|
|
4926
4934
|
try {
|
|
4927
4935
|
const sig = signedReceipt.signature;
|
|
4928
4936
|
if (!sig) {
|
|
@@ -4944,7 +4952,7 @@ async function verifyReceipt2(signedReceipt, publicKey) {
|
|
|
4944
4952
|
const hash = sha256(canonical);
|
|
4945
4953
|
const hashHex = hash.slice(7);
|
|
4946
4954
|
const hashBytes = Buffer.from(hashHex, "hex");
|
|
4947
|
-
const valid =
|
|
4955
|
+
const valid = verify(signatureBytes, hashBytes, publicKeyBytes);
|
|
4948
4956
|
return { valid, key_id: sig.key_id };
|
|
4949
4957
|
} catch (error) {
|
|
4950
4958
|
return {
|
|
@@ -5043,53 +5051,7 @@ function receiptVerify(args, deps) {
|
|
|
5043
5051
|
}
|
|
5044
5052
|
const receipt = parsed;
|
|
5045
5053
|
if (receipt.signature) {
|
|
5046
|
-
|
|
5047
|
-
let errorMsg = null;
|
|
5048
|
-
try {
|
|
5049
|
-
const promise = verifySignature(receipt, args);
|
|
5050
|
-
let done = false;
|
|
5051
|
-
promise.then(
|
|
5052
|
-
(r) => {
|
|
5053
|
-
cryptoResult = r;
|
|
5054
|
-
done = true;
|
|
5055
|
-
},
|
|
5056
|
-
(e) => {
|
|
5057
|
-
errorMsg = e instanceof Error ? e.message : String(e);
|
|
5058
|
-
done = true;
|
|
5059
|
-
}
|
|
5060
|
-
);
|
|
5061
|
-
const start = Date.now();
|
|
5062
|
-
while (!done && Date.now() - start < 5e3) {
|
|
5063
|
-
}
|
|
5064
|
-
if (!done) {
|
|
5065
|
-
return {
|
|
5066
|
-
stdout: "",
|
|
5067
|
-
stderr: "Signature verification timed out",
|
|
5068
|
-
exitCode: EXIT.ERROR
|
|
5069
|
-
};
|
|
5070
|
-
}
|
|
5071
|
-
if (errorMsg) {
|
|
5072
|
-
return {
|
|
5073
|
-
stdout: "",
|
|
5074
|
-
stderr: `Signature verification failed: ${errorMsg}`,
|
|
5075
|
-
exitCode: EXIT.ERROR
|
|
5076
|
-
};
|
|
5077
|
-
}
|
|
5078
|
-
if (!cryptoResult) {
|
|
5079
|
-
return {
|
|
5080
|
-
stdout: "",
|
|
5081
|
-
stderr: "Signature verification failed (no result)",
|
|
5082
|
-
exitCode: EXIT.ERROR
|
|
5083
|
-
};
|
|
5084
|
-
}
|
|
5085
|
-
return formatVerifyResult(receipt, cryptoResult, args);
|
|
5086
|
-
} catch (e) {
|
|
5087
|
-
return {
|
|
5088
|
-
stdout: "",
|
|
5089
|
-
stderr: `Signature verification error: ${e instanceof Error ? e.message : String(e)}`,
|
|
5090
|
-
exitCode: EXIT.ERROR
|
|
5091
|
-
};
|
|
5092
|
-
}
|
|
5054
|
+
return verifySignature(receipt, args, deps);
|
|
5093
5055
|
}
|
|
5094
5056
|
if (flagBool(args.flags, "json")) {
|
|
5095
5057
|
return {
|
|
@@ -5116,34 +5078,39 @@ function receiptVerify(args, deps) {
|
|
|
5116
5078
|
].join("\n");
|
|
5117
5079
|
return { stdout, exitCode: EXIT.OK };
|
|
5118
5080
|
}
|
|
5119
|
-
|
|
5081
|
+
function verifySignature(receipt, args, deps) {
|
|
5120
5082
|
const sig = receipt.signature;
|
|
5121
5083
|
const publicKeyUrl = sig.public_key_url || "https://calllint.com/.well-known/receipt-keys.json";
|
|
5122
|
-
let publicKey;
|
|
5123
5084
|
const publicKeyFlag = args.flags["public-key"];
|
|
5124
|
-
if (publicKeyFlag
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
`
|
|
5131
|
-
|
|
5085
|
+
if (!publicKeyFlag || typeof publicKeyFlag !== "string") {
|
|
5086
|
+
return {
|
|
5087
|
+
stdout: "",
|
|
5088
|
+
stderr: [
|
|
5089
|
+
"Receipt has a signature but no public key was provided.",
|
|
5090
|
+
` Signature key_id: ${sig.key_id}`,
|
|
5091
|
+
` Public key URL: ${publicKeyUrl}`,
|
|
5092
|
+
"",
|
|
5093
|
+
"Verify offline by passing the public key:",
|
|
5094
|
+
" calllint receipt verify <receipt.json> --public-key <keyfile>"
|
|
5095
|
+
].join("\n"),
|
|
5096
|
+
exitCode: EXIT.ERROR
|
|
5097
|
+
};
|
|
5098
|
+
}
|
|
5099
|
+
let publicKey;
|
|
5100
|
+
try {
|
|
5101
|
+
const keyJson = JSON.parse(readFileSync8(resolve4(deps.cwd, publicKeyFlag), "utf8"));
|
|
5102
|
+
publicKey = keyJson.public_key;
|
|
5103
|
+
if (typeof publicKey !== "string") {
|
|
5104
|
+
throw new Error("key file has no string 'public_key' field");
|
|
5132
5105
|
}
|
|
5133
|
-
}
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
To verify locally, provide public key with --public-key <keyfile>
|
|
5140
|
-
Example: calllint receipt verify receipt.json --public-key dev-key.json`
|
|
5141
|
-
);
|
|
5106
|
+
} catch (e) {
|
|
5107
|
+
return {
|
|
5108
|
+
stdout: "",
|
|
5109
|
+
stderr: `Could not read public key from ${publicKeyFlag}: ${e instanceof Error ? e.message : String(e)}`,
|
|
5110
|
+
exitCode: EXIT.ERROR
|
|
5111
|
+
};
|
|
5142
5112
|
}
|
|
5143
|
-
|
|
5144
|
-
}
|
|
5145
|
-
function formatVerifyResult(receipt, cryptoResult, args) {
|
|
5146
|
-
const sig = receipt.signature;
|
|
5113
|
+
const cryptoResult = verifyReceipt2(receipt, publicKey);
|
|
5147
5114
|
if (flagBool(args.flags, "json")) {
|
|
5148
5115
|
return {
|
|
5149
5116
|
stdout: JSON.stringify(
|
|
@@ -5202,23 +5169,13 @@ function receiptSign(args, deps) {
|
|
|
5202
5169
|
exitCode: EXIT.USAGE
|
|
5203
5170
|
};
|
|
5204
5171
|
}
|
|
5205
|
-
let receiptRaw;
|
|
5206
|
-
try {
|
|
5207
|
-
receiptRaw = readFileSync8(resolve4(deps.cwd, receiptFile), "utf8");
|
|
5208
|
-
} catch (e) {
|
|
5209
|
-
return {
|
|
5210
|
-
stdout: "",
|
|
5211
|
-
stderr: `Could not read receipt ${receiptFile}: ${e instanceof Error ? e.message : String(e)}`,
|
|
5212
|
-
exitCode: EXIT.ERROR
|
|
5213
|
-
};
|
|
5214
|
-
}
|
|
5215
5172
|
let unsignedReceipt;
|
|
5216
5173
|
try {
|
|
5217
|
-
unsignedReceipt = JSON.parse(
|
|
5174
|
+
unsignedReceipt = JSON.parse(readFileSync8(resolve4(deps.cwd, receiptFile), "utf8"));
|
|
5218
5175
|
} catch (e) {
|
|
5219
5176
|
return {
|
|
5220
5177
|
stdout: "",
|
|
5221
|
-
stderr: `
|
|
5178
|
+
stderr: `Could not read receipt ${receiptFile}: ${e instanceof Error ? e.message : String(e)}`,
|
|
5222
5179
|
exitCode: EXIT.ERROR
|
|
5223
5180
|
};
|
|
5224
5181
|
}
|
|
@@ -5229,69 +5186,21 @@ function receiptSign(args, deps) {
|
|
|
5229
5186
|
exitCode: EXIT.ERROR
|
|
5230
5187
|
};
|
|
5231
5188
|
}
|
|
5232
|
-
let keyJson;
|
|
5233
|
-
try {
|
|
5234
|
-
const keyRaw = readFileSync8(resolve4(deps.cwd, keyFile), "utf8");
|
|
5235
|
-
keyJson = JSON.parse(keyRaw);
|
|
5236
|
-
} catch (e) {
|
|
5237
|
-
return {
|
|
5238
|
-
stdout: "",
|
|
5239
|
-
stderr: `Could not read key file ${keyFile}: ${e instanceof Error ? e.message : String(e)}`,
|
|
5240
|
-
exitCode: EXIT.ERROR
|
|
5241
|
-
};
|
|
5242
|
-
}
|
|
5243
5189
|
let keypair;
|
|
5244
5190
|
try {
|
|
5191
|
+
const keyJson = JSON.parse(readFileSync8(resolve4(deps.cwd, keyFile), "utf8"));
|
|
5245
5192
|
keypair = importKeypair(keyJson);
|
|
5246
5193
|
} catch (e) {
|
|
5247
5194
|
return {
|
|
5248
5195
|
stdout: "",
|
|
5249
|
-
stderr: `
|
|
5250
|
-
exitCode: EXIT.ERROR
|
|
5251
|
-
};
|
|
5252
|
-
}
|
|
5253
|
-
let signature = null;
|
|
5254
|
-
let errorMsg = null;
|
|
5255
|
-
const promise = signReceipt(unsignedReceipt, keypair);
|
|
5256
|
-
let done = false;
|
|
5257
|
-
promise.then(
|
|
5258
|
-
(sig) => {
|
|
5259
|
-
signature = sig;
|
|
5260
|
-
done = true;
|
|
5261
|
-
},
|
|
5262
|
-
(e) => {
|
|
5263
|
-
errorMsg = e instanceof Error ? e.message : String(e);
|
|
5264
|
-
done = true;
|
|
5265
|
-
}
|
|
5266
|
-
);
|
|
5267
|
-
const start = Date.now();
|
|
5268
|
-
while (!done && Date.now() - start < 5e3) {
|
|
5269
|
-
}
|
|
5270
|
-
if (!done) {
|
|
5271
|
-
return {
|
|
5272
|
-
stdout: "",
|
|
5273
|
-
stderr: "Signing timed out",
|
|
5274
|
-
exitCode: EXIT.ERROR
|
|
5275
|
-
};
|
|
5276
|
-
}
|
|
5277
|
-
if (errorMsg) {
|
|
5278
|
-
return {
|
|
5279
|
-
stdout: "",
|
|
5280
|
-
stderr: `Signing failed: ${errorMsg}`,
|
|
5281
|
-
exitCode: EXIT.ERROR
|
|
5282
|
-
};
|
|
5283
|
-
}
|
|
5284
|
-
if (!signature) {
|
|
5285
|
-
return {
|
|
5286
|
-
stdout: "",
|
|
5287
|
-
stderr: "Signing failed (no result)",
|
|
5196
|
+
stderr: `Could not read key file ${keyFile}: ${e instanceof Error ? e.message : String(e)}`,
|
|
5288
5197
|
exitCode: EXIT.ERROR
|
|
5289
5198
|
};
|
|
5290
5199
|
}
|
|
5291
5200
|
try {
|
|
5201
|
+
const signature = signReceipt(unsignedReceipt, keypair);
|
|
5292
5202
|
const signedReceipt = { ...unsignedReceipt, signature };
|
|
5293
|
-
|
|
5294
|
-
writeFileSync6(outPath, JSON.stringify(signedReceipt, null, 2) + "\n", "utf8");
|
|
5203
|
+
writeFileSync6(resolve4(deps.cwd, outFile), JSON.stringify(signedReceipt, null, 2) + "\n", "utf8");
|
|
5295
5204
|
const stdout = [
|
|
5296
5205
|
"\u2713 Receipt signed successfully",
|
|
5297
5206
|
` Key ID: ${signature.key_id}`,
|
|
@@ -5303,7 +5212,7 @@ function receiptSign(args, deps) {
|
|
|
5303
5212
|
} catch (e) {
|
|
5304
5213
|
return {
|
|
5305
5214
|
stdout: "",
|
|
5306
|
-
stderr: `
|
|
5215
|
+
stderr: `Signing failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
5307
5216
|
exitCode: EXIT.ERROR
|
|
5308
5217
|
};
|
|
5309
5218
|
}
|
|
@@ -5323,48 +5232,10 @@ function receiptKeygen(args, deps) {
|
|
|
5323
5232
|
};
|
|
5324
5233
|
}
|
|
5325
5234
|
const keyId = args.flags["key-id"] || "calllint-dev-2026-h2";
|
|
5326
|
-
let keypair = null;
|
|
5327
|
-
let errorMsg = null;
|
|
5328
|
-
const promise = generateKeypair(keyId);
|
|
5329
|
-
let done = false;
|
|
5330
|
-
promise.then(
|
|
5331
|
-
(kp) => {
|
|
5332
|
-
keypair = kp;
|
|
5333
|
-
done = true;
|
|
5334
|
-
},
|
|
5335
|
-
(e) => {
|
|
5336
|
-
errorMsg = e instanceof Error ? e.message : String(e);
|
|
5337
|
-
done = true;
|
|
5338
|
-
}
|
|
5339
|
-
);
|
|
5340
|
-
const start = Date.now();
|
|
5341
|
-
while (!done && Date.now() - start < 5e3) {
|
|
5342
|
-
}
|
|
5343
|
-
if (!done) {
|
|
5344
|
-
return {
|
|
5345
|
-
stdout: "",
|
|
5346
|
-
stderr: "Keygen timed out",
|
|
5347
|
-
exitCode: EXIT.ERROR
|
|
5348
|
-
};
|
|
5349
|
-
}
|
|
5350
|
-
if (errorMsg) {
|
|
5351
|
-
return {
|
|
5352
|
-
stdout: "",
|
|
5353
|
-
stderr: `Keygen failed: ${errorMsg}`,
|
|
5354
|
-
exitCode: EXIT.ERROR
|
|
5355
|
-
};
|
|
5356
|
-
}
|
|
5357
|
-
if (!keypair) {
|
|
5358
|
-
return {
|
|
5359
|
-
stdout: "",
|
|
5360
|
-
stderr: "Keygen failed (no result)",
|
|
5361
|
-
exitCode: EXIT.ERROR
|
|
5362
|
-
};
|
|
5363
|
-
}
|
|
5364
5235
|
try {
|
|
5236
|
+
const keypair = generateKeypair(keyId);
|
|
5365
5237
|
const exported = exportKeypair(keypair);
|
|
5366
|
-
|
|
5367
|
-
writeFileSync6(outPath, JSON.stringify(exported, null, 2) + "\n", "utf8");
|
|
5238
|
+
writeFileSync6(resolve4(deps.cwd, outFile), JSON.stringify(exported, null, 2) + "\n", "utf8");
|
|
5368
5239
|
const stdout = [
|
|
5369
5240
|
"\u2713 Keypair generated successfully",
|
|
5370
5241
|
` Key ID: ${keyId}`,
|
|
@@ -5377,7 +5248,7 @@ function receiptKeygen(args, deps) {
|
|
|
5377
5248
|
} catch (e) {
|
|
5378
5249
|
return {
|
|
5379
5250
|
stdout: "",
|
|
5380
|
-
stderr: `
|
|
5251
|
+
stderr: `Keygen failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
5381
5252
|
exitCode: EXIT.ERROR
|
|
5382
5253
|
};
|
|
5383
5254
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "calllint",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Evidence-backed security verdicts for MCP servers and agent tools. Lint agent tool-call risk before tools run — SAFE / REVIEW / BLOCK / UNKNOWN, with evidence. Never executes the server it judges.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|