agenteval-cli 0.8.3 → 0.8.5

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.
Files changed (2) hide show
  1. package/bin/agenteval.js +46 -35
  2. package/package.json +1 -1
package/bin/agenteval.js CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { execFileSync, execSync } = require("child_process");
4
- const { existsSync, mkdirSync, chmodSync, renameSync, unlinkSync } = require("fs");
3
+ const { execFileSync } = require("child_process");
4
+ const { createHash } = require("crypto");
5
+ const { existsSync, mkdirSync, chmodSync, renameSync, unlinkSync, readFileSync, writeFileSync } = require("fs");
5
6
  const { join } = require("path");
6
7
  const https = require("https");
7
8
 
@@ -10,41 +11,52 @@ const CACHE_DIR = join(require("os").homedir(), ".agenteval", "bin");
10
11
  const BIN_PATH = join(CACHE_DIR, "agenteval");
11
12
  const VERSION_PATH = join(CACHE_DIR, ".version");
12
13
 
14
+ // SHA256 checksums injected by the release workflow.
15
+ // If all zeros, integrity check is skipped (dev/unreleased builds).
16
+ const CHECKSUMS = {
17
+ "agenteval-linux-x64": "59729b785863d678fe80a97a728c95d557890c571eea66d8d2c8239630c0248b",
18
+ "agenteval-darwin-arm64": "b4d7d81a0be0cb7075cb651f2d5f0d365d8603b529839d4e158bda8007618718",
19
+ "agenteval-darwin-x64": "3712af2cfe0edb7de629da2a475d5903e4475eb3b828d1778ed83331bf7af4a5",
20
+ };
21
+
13
22
  function getPlatformKey() {
14
- const platform = process.platform;
15
- const arch = process.arch;
16
- if (platform === "darwin" && arch === "arm64") return "agenteval-darwin-arm64";
17
- if (platform === "darwin" && arch === "x64") return "agenteval-darwin-x64";
18
- if (platform === "linux" && arch === "x64") return "agenteval-linux-x64";
23
+ if (process.platform === "darwin" && process.arch === "arm64") return "agenteval-darwin-arm64";
24
+ if (process.platform === "darwin" && process.arch === "x64") return "agenteval-darwin-x64";
25
+ if (process.platform === "linux" && process.arch === "x64") return "agenteval-linux-x64";
19
26
  return null;
20
27
  }
21
28
 
22
29
  function getPackageVersion() {
23
- try {
24
- return require("../package.json").version;
25
- } catch {
26
- return null;
27
- }
30
+ try { return require("../package.json").version; } catch { return null; }
28
31
  }
29
32
 
30
33
  function getCachedVersion() {
31
- try {
32
- return require("fs").readFileSync(VERSION_PATH, "utf8").trim();
33
- } catch {
34
- return null;
35
- }
34
+ try { return readFileSync(VERSION_PATH, "utf8").trim(); } catch { return null; }
35
+ }
36
+
37
+ function verifySHA256(data, expected) {
38
+ // Skip verification if checksums are placeholder zeros
39
+ if (expected.startsWith("0000000000")) return true;
40
+ const actual = createHash("sha256").update(data).digest("hex");
41
+ return actual === expected;
36
42
  }
37
43
 
38
- function download(url) {
44
+ function download(url, maxRedirects) {
45
+ if (maxRedirects === undefined) maxRedirects = 5;
46
+ if (maxRedirects <= 0) return Promise.reject(new Error("Too many redirects"));
39
47
  return new Promise((resolve, reject) => {
40
- https.get(url, (res) => {
48
+ const parsedUrl = new URL(url);
49
+ const options = { hostname: parsedUrl.hostname, path: parsedUrl.pathname + parsedUrl.search, headers: { "User-Agent": "agenteval-cli" } };
50
+ https.get(options, (res) => {
41
51
  if (res.statusCode === 301 || res.statusCode === 302) {
42
- return download(res.headers.location).then(resolve, reject);
43
- }
44
- if (res.statusCode !== 200) {
45
- reject(new Error(`HTTP ${res.statusCode}`));
46
- return;
52
+ const location = res.headers.location;
53
+ if (!location || (!location.startsWith("https://") && !location.startsWith("https://github.com"))) {
54
+ reject(new Error(`Unsafe redirect to ${location}`));
55
+ return;
56
+ }
57
+ return download(location, maxRedirects - 1).then(resolve, reject);
47
58
  }
59
+ if (res.statusCode !== 200) { reject(new Error(`HTTP ${res.statusCode}`)); return; }
48
60
  const chunks = [];
49
61
  res.on("data", (chunk) => chunks.push(chunk));
50
62
  res.on("end", () => resolve(Buffer.concat(chunks)));
@@ -57,7 +69,6 @@ async function ensureBinary() {
57
69
  const pkgVersion = getPackageVersion();
58
70
  const cachedVersion = getCachedVersion();
59
71
 
60
- // Binary exists and matches current package version
61
72
  if (existsSync(BIN_PATH) && cachedVersion === pkgVersion) {
62
73
  return BIN_PATH;
63
74
  }
@@ -66,7 +77,6 @@ async function ensureBinary() {
66
77
  if (!binary) {
67
78
  console.error(`agenteval: unsupported platform ${process.platform}-${process.arch}`);
68
79
  console.error("Supported: linux-x64, darwin-arm64, darwin-x64");
69
- console.error("Install manually: https://github.com/lukasmetzler/agenteval/releases");
70
80
  process.exit(1);
71
81
  }
72
82
 
@@ -74,22 +84,23 @@ async function ensureBinary() {
74
84
  const url = `https://github.com/${REPO}/releases/download/${version}/${binary}`;
75
85
 
76
86
  console.error(`Downloading agenteval ${version} (${binary})...`);
77
-
78
87
  mkdirSync(CACHE_DIR, { recursive: true });
79
88
 
80
89
  const tmpPath = `${BIN_PATH}.tmp.${Date.now()}`;
81
90
  try {
82
91
  const data = await download(url);
83
- require("fs").writeFileSync(tmpPath, data);
84
- chmodSync(tmpPath, 0o755);
85
92
 
86
- // Atomic replace
87
- if (existsSync(BIN_PATH)) {
88
- try { unlinkSync(BIN_PATH); } catch {}
93
+ // Verify integrity
94
+ const expectedHash = CHECKSUMS[binary];
95
+ if (!verifySHA256(data, expectedHash)) {
96
+ throw new Error("SHA256 checksum mismatch — download may be corrupted or tampered with");
89
97
  }
90
- renameSync(tmpPath, BIN_PATH);
91
- require("fs").writeFileSync(VERSION_PATH, pkgVersion || version);
92
98
 
99
+ writeFileSync(tmpPath, data);
100
+ chmodSync(tmpPath, 0o755);
101
+ if (existsSync(BIN_PATH)) { try { unlinkSync(BIN_PATH); } catch {} }
102
+ renameSync(tmpPath, BIN_PATH);
103
+ writeFileSync(VERSION_PATH, pkgVersion || version);
93
104
  console.error("Done.");
94
105
  } catch (err) {
95
106
  try { unlinkSync(tmpPath); } catch {}
@@ -103,7 +114,7 @@ async function ensureBinary() {
103
114
 
104
115
  ensureBinary().then((binPath) => {
105
116
  try {
106
- const result = execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
117
+ execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
107
118
  } catch (err) {
108
119
  process.exit(err && typeof err === "object" && "status" in err ? err.status : 1);
109
120
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenteval-cli",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "Lint, benchmark, and CI gate for AI coding instructions",
5
5
  "keywords": [
6
6
  "cli",