juggernaut-bedrock 4.0.0 → 4.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.
Files changed (3) hide show
  1. package/bin/.gitkeep +0 -0
  2. package/install.js +42 -61
  3. package/package.json +3 -3
package/bin/.gitkeep ADDED
File without changes
package/install.js CHANGED
@@ -3,11 +3,16 @@
3
3
  const https = require("https");
4
4
  const fs = require("fs");
5
5
  const path = require("path");
6
- const os = require("os");
6
+ const { Readable } = require("stream");
7
7
  const crypto = require("crypto");
8
8
 
9
9
  const REPO = "jpvelasco/juggernaut";
10
10
  const BIN_DIR = path.join(__dirname, "bin");
11
+ const ALLOWED_HOSTS = new Set([
12
+ "github.com",
13
+ "api.github.com",
14
+ "release-assets.githubusercontent.com"
15
+ ]);
11
16
 
12
17
  function getPlatform() {
13
18
  const osMap = { darwin: "darwin", linux: "linux", win32: "windows" };
@@ -20,12 +25,23 @@ function getPlatform() {
20
25
  return { os: p, arch: a, platform: `${p}_${a}` };
21
26
  }
22
27
 
23
- function httpsGet(url) {
28
+ function httpsGetBuffer(url) {
29
+ const parsed = new URL(url);
30
+ if (!ALLOWED_HOSTS.has(parsed.hostname)) {
31
+ throw new Error(`URL host not allowed: ${parsed.hostname}`);
32
+ }
24
33
  return new Promise((resolve, reject) => {
25
34
  https
26
35
  .get(url, { headers: { "User-Agent": "juggernaut-npm-installer/1.0" } }, (res) => {
27
36
  if (res.statusCode === 301 || res.statusCode === 302) {
28
- return httpsGet(res.headers.location).then(resolve).catch(reject);
37
+ const location = res.headers.location;
38
+ const redirectParsed = new URL(location);
39
+ if (!ALLOWED_HOSTS.has(redirectParsed.hostname)) {
40
+ reject(new Error(`Redirect host not allowed: ${redirectParsed.hostname}`));
41
+ return;
42
+ }
43
+ httpsGetBuffer(location).then(resolve).catch(reject);
44
+ return;
29
45
  }
30
46
  const chunks = [];
31
47
  res.on("data", (chunk) => chunks.push(chunk));
@@ -36,27 +52,8 @@ function httpsGet(url) {
36
52
  });
37
53
  }
38
54
 
39
- function downloadFile(url, dest) {
40
- return new Promise((resolve, reject) => {
41
- const file = fs.createWriteStream(dest);
42
- function fetch(fetchUrl) {
43
- https
44
- .get(fetchUrl, { headers: { "User-Agent": "juggernaut-npm-installer/1.0" } }, (res) => {
45
- if (res.statusCode === 301 || res.statusCode === 302) {
46
- return fetch(res.headers.location);
47
- }
48
- res.pipe(file);
49
- file.on("finish", () => file.close(resolve));
50
- file.on("error", reject);
51
- })
52
- .on("error", reject);
53
- }
54
- fetch(url);
55
- });
56
- }
57
-
58
55
  async function getLatestVersion() {
59
- const data = await httpsGet(`https://api.github.com/repos/${REPO}/releases/latest`);
56
+ const data = await httpsGetBuffer(`https://api.github.com/repos/${REPO}/releases/latest`);
60
57
  const release = JSON.parse(data.toString());
61
58
  return release.tag_name.replace(/^v/, "");
62
59
  }
@@ -68,49 +65,33 @@ async function main() {
68
65
  const archive = `juggernaut_${platform}.${ext}`;
69
66
  const baseUrl = `https://github.com/${REPO}/releases/download/v${version}`;
70
67
 
71
- const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "juggernaut-"));
72
- const archivePath = path.join(tmp, archive);
73
- const checksumPath = path.join(tmp, "checksums.txt");
74
-
75
- try {
76
- console.log(`Downloading Juggernaut v${version} (${platform})...`);
77
- await downloadFile(`${baseUrl}/${archive}`, archivePath);
78
- await downloadFile(`${baseUrl}/checksums.txt`, checksumPath);
79
-
80
- // Verify checksum.
81
- const checksums = fs.readFileSync(checksumPath, "utf8");
82
- const line = checksums.split("\n").find((l) => l.includes(archive));
83
- if (!line) throw new Error(`Checksum not found for ${archive}`);
84
- const expected = line.trim().split(/\s+/)[0].toLowerCase();
85
- const actual = crypto
86
- .createHash("sha256")
87
- .update(fs.readFileSync(archivePath))
88
- .digest("hex")
89
- .toLowerCase();
90
- if (actual !== expected) {
91
- throw new Error(`Checksum mismatch for ${archive}\n expected: ${expected}\n got: ${actual}`);
92
- }
68
+ console.log(`Downloading Juggernaut v${version} (${platform})...`);
69
+ const archiveBuf = await httpsGetBuffer(`${baseUrl}/${archive}`);
70
+ const checksumsBuf = await httpsGetBuffer(`${baseUrl}/checksums.txt`);
93
71
 
94
- fs.mkdirSync(BIN_DIR, { recursive: true });
95
-
96
- if (ext === "zip") {
97
- const AdmZip = require("adm-zip");
98
- const zip = new AdmZip(archivePath);
99
- zip.extractEntryTo("juggernaut.exe", BIN_DIR, false, true);
100
- } else {
101
- const tar = require("tar");
102
- await tar.x({ file: archivePath, cwd: BIN_DIR });
103
- fs.chmodSync(path.join(BIN_DIR, "juggernaut"), 0o755);
104
- }
72
+ const checksums = checksumsBuf.toString("utf8");
73
+ const line = checksums.split("\n").find((l) => l.includes(archive));
74
+ if (!line) throw new Error(`Checksum not found for ${archive}`);
75
+ const expected = line.trim().split(/\s+/)[0].toLowerCase();
76
+ const actual = crypto.createHash("sha256").update(archiveBuf).digest("hex").toLowerCase();
77
+ if (actual !== expected) {
78
+ throw new Error(`Checksum mismatch for ${archive}\n expected: ${expected}\n got: ${actual}`);
79
+ }
105
80
 
106
- console.log(`Juggernaut v${version} installed successfully.`);
107
- console.log(`Run: juggernaut apply`);
108
- } finally {
109
- fs.rmSync(tmp, { recursive: true, force: true });
81
+ if (ext === "zip") {
82
+ const AdmZip = require("adm-zip");
83
+ const zip = new AdmZip(archiveBuf);
84
+ zip.extractEntryTo("juggernaut.exe", BIN_DIR, false, true);
85
+ } else {
86
+ const tar = require("tar");
87
+ await tar.x({ cwd: BIN_DIR, mode: 0o700, strict: true }, Readable.from(archiveBuf));
110
88
  }
89
+
90
+ console.log(`Juggernaut v${version} installed successfully.`);
91
+ console.log(`Run: juggernaut apply`);
111
92
  }
112
93
 
113
94
  main().catch((err) => {
114
95
  console.error("Installation failed:", err.message);
115
96
  process.exit(1);
116
- });
97
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juggernaut-bedrock",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
4
4
  "description": "Configure Claude Code to use Amazon Bedrock — cross-platform installer",
5
5
  "bin": {
6
6
  "juggernaut": "./bin/juggernaut"
@@ -9,8 +9,8 @@
9
9
  "postinstall": "node install.js"
10
10
  },
11
11
  "dependencies": {
12
- "tar": "^6.0.0",
13
- "adm-zip": "^0.5.0"
12
+ "tar": "7.5.16",
13
+ "adm-zip": "0.5.17"
14
14
  },
15
15
  "os": ["darwin", "linux", "win32"],
16
16
  "cpu": ["x64", "arm64"],