fleetctl 4.92.3 → 4.93.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/package.json +2 -2
- package/run.js +62 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fleetctl",
|
|
3
|
-
"version": "v4.
|
|
3
|
+
"version": "v4.93.0",
|
|
4
4
|
"description": "Installer for the fleetctl CLI tool",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fleetctl": "./run.js"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"homepage": "https://fleetdm.com",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"axios": "1.
|
|
19
|
+
"axios": "1.20.0",
|
|
20
20
|
"rimraf": "6.1.2",
|
|
21
21
|
"tar": "7.5.22"
|
|
22
22
|
},
|
package/run.js
CHANGED
|
@@ -2,16 +2,29 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
3
3
|
|
|
4
4
|
const { spawnSync } = require("child_process");
|
|
5
|
-
const {
|
|
6
|
-
|
|
5
|
+
const {
|
|
6
|
+
chmodSync,
|
|
7
|
+
existsSync,
|
|
8
|
+
lstatSync,
|
|
9
|
+
mkdirSync,
|
|
10
|
+
mkdtempSync,
|
|
11
|
+
renameSync,
|
|
12
|
+
rmSync,
|
|
13
|
+
} = require("fs");
|
|
14
|
+
const { constants: osConstants, type } = require("os");
|
|
7
15
|
const { join } = require("path");
|
|
8
16
|
const { arch } = require("process");
|
|
17
|
+
const { pipeline } = require("stream/promises");
|
|
9
18
|
|
|
10
19
|
const axios = require("axios");
|
|
11
20
|
const { rimrafSync } = require("rimraf");
|
|
12
21
|
const { extract } = require("tar");
|
|
13
22
|
const { version } = require("./package.json");
|
|
14
23
|
|
|
24
|
+
// Fail closed: if anything below leaves a promise pending (e.g. a download stream that stops
|
|
25
|
+
// without an error event), the event loop drains and Node would otherwise exit 0 silently.
|
|
26
|
+
process.exitCode = 1;
|
|
27
|
+
|
|
15
28
|
// Strip any v4.0.0-1 style suffix (but not -rc1) so that the correct package is
|
|
16
29
|
// downloaded if there is a mistake in the NPM publish and we need to release a
|
|
17
30
|
// -1, etc. (because NPM packages are immutable and can't be fixed after a mistake).
|
|
@@ -34,36 +47,52 @@ const platform = (() => {
|
|
|
34
47
|
case "Darwin":
|
|
35
48
|
return "macos";
|
|
36
49
|
default:
|
|
37
|
-
throw new Error(`platform ${type} unrecognized`);
|
|
50
|
+
throw new Error(`platform ${type()} unrecognized`);
|
|
38
51
|
}
|
|
39
52
|
})();
|
|
40
53
|
|
|
41
|
-
const binName = platform
|
|
54
|
+
const binName = platform.startsWith("windows") ? "fleetctl.exe" : "fleetctl";
|
|
42
55
|
const binPath = join(installDir, binName);
|
|
43
56
|
|
|
44
57
|
const install = async () => {
|
|
45
58
|
const url = `https://github.com/fleetdm/fleet/releases/download/fleet-${strippedVersion}/fleetctl_${strippedVersion}_${platform}.tar.gz`;
|
|
46
59
|
|
|
47
|
-
mkdirSync(
|
|
60
|
+
mkdirSync(binDir, { recursive: true });
|
|
61
|
+
// Extract into a temporary directory and rename it into place, so an interrupted
|
|
62
|
+
// download never leaves a partial binary where the next run would find it.
|
|
63
|
+
const tmpDir = mkdtempSync(join(binDir, "tmp-"));
|
|
48
64
|
|
|
49
65
|
try {
|
|
50
|
-
|
|
66
|
+
let response;
|
|
67
|
+
try {
|
|
68
|
+
response = await axios({ url, responseType: "stream" });
|
|
69
|
+
} catch (err) {
|
|
70
|
+
if (axios.isAxiosError(err)) {
|
|
71
|
+
throw new Error(`download archive ${url}: ${err.message}`);
|
|
72
|
+
}
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
51
75
|
|
|
76
|
+
// Unlike stream.pipe(), pipeline() rejects on errors and premature close from either side.
|
|
52
77
|
// Strip the outer directory when extracting. Just get the binary.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
throw new Error(`download archive ${url}: ${err.message}`);
|
|
64
|
-
} else {
|
|
65
|
-
throw err;
|
|
78
|
+
await pipeline(response.data, extract({ strip: 1, cwd: tmpDir }));
|
|
79
|
+
|
|
80
|
+
// Validate before caching: a bad entry here would otherwise be reused on every later run.
|
|
81
|
+
const extracted = join(tmpDir, binName);
|
|
82
|
+
const stat = existsSync(extracted) ? lstatSync(extracted) : null;
|
|
83
|
+
if (!stat || !stat.isFile()) {
|
|
84
|
+
throw new Error(`archive ${url} does not contain a ${binName} file`);
|
|
85
|
+
}
|
|
86
|
+
if (!platform.startsWith("windows") && !(stat.mode & 0o111)) {
|
|
87
|
+
throw new Error(`${binName} in archive ${url} is not executable`);
|
|
66
88
|
}
|
|
89
|
+
// mkdtempSync creates the directory as 0700; keep it traversable for other users when
|
|
90
|
+
// installed as root (sudo npm install -g fleetctl), like the plain mkdirSync it replaced.
|
|
91
|
+
chmodSync(tmpDir, 0o755);
|
|
92
|
+
renameSync(tmpDir, installDir);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
95
|
+
throw err;
|
|
67
96
|
}
|
|
68
97
|
};
|
|
69
98
|
|
|
@@ -110,14 +139,26 @@ const run = async () => {
|
|
|
110
139
|
|
|
111
140
|
const [, , ...args] = process.argv;
|
|
112
141
|
const options = { cwd: process.cwd(), stdio: "inherit" };
|
|
113
|
-
const { status, error } = spawnSync(binPath, args, options);
|
|
142
|
+
const { status, signal, error } = spawnSync(binPath, args, options);
|
|
114
143
|
|
|
115
144
|
if (error) {
|
|
116
145
|
console.error(error);
|
|
117
146
|
process.exit(1);
|
|
118
147
|
}
|
|
148
|
+
if (status === null) {
|
|
149
|
+
// Killed by a signal: status is null and process.exit(null) would report success.
|
|
150
|
+
// Mirror the shell convention (128 + signal number) and stay quiet on SIGPIPE, which is
|
|
151
|
+
// routine when the output is piped to a command that exits early (e.g. `| head`).
|
|
152
|
+
if (signal !== "SIGPIPE") {
|
|
153
|
+
console.error(`Error: fleetctl was terminated by signal ${signal}`);
|
|
154
|
+
}
|
|
155
|
+
process.exit(128 + (osConstants.signals[signal] || 0));
|
|
156
|
+
}
|
|
119
157
|
|
|
120
158
|
process.exit(status);
|
|
121
159
|
};
|
|
122
160
|
|
|
123
|
-
run()
|
|
161
|
+
run().catch((err) => {
|
|
162
|
+
console.error(`Error: ${err.message}`);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
});
|