fundamentum-cli 0.2.2 → 0.2.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.
Files changed (2) hide show
  1. package/install.js +42 -6
  2. package/package.json +8 -7
package/install.js CHANGED
@@ -132,7 +132,7 @@ function psEscape(s) {
132
132
  return s.replace(/'/g, "''");
133
133
  }
134
134
 
135
- function spawnOrFail(cmd, args, label) {
135
+ function spawnStdout(cmd, args, label) {
136
136
  const result = spawnSync(cmd, args, { stdio: "pipe" });
137
137
  if (result.error) {
138
138
  throw new Error(`${label}: ${result.error.message}`);
@@ -143,6 +143,11 @@ function spawnOrFail(cmd, args, label) {
143
143
  `${label} exited with code ${result.status}${stderr ? ": " + stderr : ""}`
144
144
  );
145
145
  }
146
+ return result.stdout.toString("utf8");
147
+ }
148
+
149
+ function spawnOrFail(cmd, args, label) {
150
+ spawnStdout(cmd, args, label);
146
151
  }
147
152
 
148
153
  function extract(buffer, archiveName, binDir) {
@@ -153,7 +158,13 @@ function extract(buffer, archiveName, binDir) {
153
158
  fs.writeFileSync(archivePath, buffer);
154
159
 
155
160
  try {
156
- if (archiveName.endsWith(".zip")) {
161
+ // Validate the member list before extraction: a crafted archive can name
162
+ // members like ../../.bashrc, and the extractor would happily write them
163
+ // outside tmpDir. Reject such members up front so nothing leaves the dir.
164
+ const isZip = archiveName.endsWith(".zip");
165
+ validateMembers(listMembers(archivePath, isZip));
166
+
167
+ if (isZip) {
157
168
  if (process.platform === "win32") {
158
169
  spawnOrFail(
159
170
  "powershell",
@@ -191,6 +202,27 @@ function extract(buffer, archiveName, binDir) {
191
202
  }
192
203
  }
193
204
 
205
+ function isPathEscape(name) {
206
+ return path.isAbsolute(name) || name.split(/[\\/]/).includes("..");
207
+ }
208
+
209
+ function listMembers(archivePath, isZip) {
210
+ const listing = isZip
211
+ ? spawnStdout("unzip", ["-Z1", archivePath], "unzip -Z1")
212
+ : spawnStdout("tar", ["-tzf", archivePath], "tar -tzf");
213
+ return listing.split(/\r?\n/).filter(Boolean);
214
+ }
215
+
216
+ function validateMembers(members) {
217
+ for (const member of members) {
218
+ if (isPathEscape(member)) {
219
+ throw new Error(
220
+ `Archive path escape detected: ${member} resolves outside the install directory`
221
+ );
222
+ }
223
+ }
224
+ }
225
+
194
226
  async function main() {
195
227
  const pkg = JSON.parse(
196
228
  fs.readFileSync(path.join(__dirname, "package.json"), "utf8")
@@ -224,7 +256,11 @@ async function main() {
224
256
  console.log("fundamentum: installed successfully");
225
257
  }
226
258
 
227
- main().catch((err) => {
228
- console.error(`fundamentum: installation failed: ${err.message}`);
229
- process.exit(1);
230
- });
259
+ if (require.main === module) {
260
+ main().catch((err) => {
261
+ console.error(`fundamentum: installation failed: ${err.message}`);
262
+ process.exit(1);
263
+ });
264
+ }
265
+
266
+ module.exports = { isPathEscape, listMembers, validateMembers };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fundamentum-cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Bootstrap and harden GitHub repos for OSS collaboration — community files, branch protection, security features, and starter workflows in one command.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -15,7 +15,8 @@
15
15
  "fundamentum": "run.js"
16
16
  },
17
17
  "scripts": {
18
- "postinstall": "node install.js"
18
+ "postinstall": "node install.js",
19
+ "test": "node --test install.test.js"
19
20
  },
20
21
  "os": [
21
22
  "linux",
@@ -57,10 +58,10 @@
57
58
  "bin/"
58
59
  ],
59
60
  "binaryChecksums": {
60
- "fundamentum_0.2.2_darwin_amd64.tar.gz": "1aa96b7579d57ff6cdcc2b14903516a15d6d28a1b1e5903e19b50ef4f2e8ab8e",
61
- "fundamentum_0.2.2_darwin_arm64.tar.gz": "b28f1af3db21d408b2f6121c9504bb7bd965f941cbaba24ee4ba14dac49b3636",
62
- "fundamentum_0.2.2_linux_amd64.tar.gz": "f0c4bcd3cf6e951d3c5caccd4cbd76d146b56d32e43bcfbf1e3b4973910c4f57",
63
- "fundamentum_0.2.2_linux_arm64.tar.gz": "f2aa4a1b73430c7108b0cb3a80bcfa2b887381eb9f6a93d09c9359c33d7afcc6",
64
- "fundamentum_0.2.2_windows_amd64.zip": "28799b1f6136cfd25f426c04aab94f602152646f150c526de6632be2360580ac"
61
+ "fundamentum_0.2.3_darwin_amd64.tar.gz": "699818edde5867a634d60823cb21bb256f1553df51c913e908c8bb5959339b30",
62
+ "fundamentum_0.2.3_darwin_arm64.tar.gz": "f022a92f78c7908897bd18478438a4dfb10cc59dfd6eb2663a89d35dc8e78fb3",
63
+ "fundamentum_0.2.3_linux_amd64.tar.gz": "b84615a7a0fe5c13a71560bf2688d0256c08fb44548ff81930cc5fc700ff7aae",
64
+ "fundamentum_0.2.3_linux_arm64.tar.gz": "f045af85c5a2fdf9215a08fa033881fd2f0baa483d48bd68929fe07a864970c0",
65
+ "fundamentum_0.2.3_windows_amd64.zip": "b67e7e5366837def2f77dcbb5e25cfb370de0e608da5dc0424b40d244794ec5b"
65
66
  }
66
67
  }