arisa 5.1.9 → 5.1.10
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 +1 -1
- package/src/runtime/slave-cli.js +18 -5
- package/test/slave-cli.test.js +20 -0
package/package.json
CHANGED
package/src/runtime/slave-cli.js
CHANGED
|
@@ -165,6 +165,14 @@ export function formatSlaveStatus({ systemd, diagnostic }) {
|
|
|
165
165
|
].join("\n");
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
function explainSlaveBootstrapError(error) {
|
|
169
|
+
if (error?.message !== "Socket closed before the protocol completed") return error;
|
|
170
|
+
return new Error(
|
|
171
|
+
"Master ended the pairing handshake before it completed. The bootstrap URL may be expired, rotated, already used, or invalid. Generate a new bootstrap URL on Master and retry before it expires.",
|
|
172
|
+
{ cause: error }
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
168
176
|
export async function runSlaveBootstrap(url, {
|
|
169
177
|
paths = getSlavePaths(resolveSlaveHome()),
|
|
170
178
|
ask = askFromTerminal,
|
|
@@ -181,11 +189,16 @@ export async function runSlaveBootstrap(url, {
|
|
|
181
189
|
const account = await selectAccount({ ask });
|
|
182
190
|
await ensureSlaveConfig(paths);
|
|
183
191
|
await ensureTool(paths);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
let result;
|
|
193
|
+
try {
|
|
194
|
+
result = await withSecureRequestFile({
|
|
195
|
+
directory: paths.tmpDir,
|
|
196
|
+
prefix: "bootstrap",
|
|
197
|
+
value: { url }
|
|
198
|
+
}, (bootstrapFile) => invokeTool(paths, { action: "slave.bootstrap", bootstrapFile }));
|
|
199
|
+
} catch (error) {
|
|
200
|
+
throw explainSlaveBootstrapError(error);
|
|
201
|
+
}
|
|
189
202
|
await installService({ account, slaveHome: paths.home, entryFile });
|
|
190
203
|
await writeSlaveServiceDescriptor(paths, { version: 1, account, installedAt: new Date().toISOString() });
|
|
191
204
|
output.log(`Arisa Slave paired and running as ${account.user}${account.root ? " (root)" : ""}.`);
|
package/test/slave-cli.test.js
CHANGED
|
@@ -176,6 +176,26 @@ test("validates before effects and keeps the bootstrap secret out of service met
|
|
|
176
176
|
assert.deepEqual(calls, []);
|
|
177
177
|
});
|
|
178
178
|
|
|
179
|
+
test("explains an incomplete Master pairing handshake", async (t) => {
|
|
180
|
+
const home = await mkdtemp(path.join(os.tmpdir(), "arisa-slave-handshake-"));
|
|
181
|
+
t.after(() => rm(home, { recursive: true, force: true }));
|
|
182
|
+
await assert.rejects(
|
|
183
|
+
() => runSlaveBootstrap(`tcp://198.51.100.12:4719/${secret}`, {
|
|
184
|
+
paths: getSlavePaths(home),
|
|
185
|
+
entryFile: "/opt/arisa/src/index.js",
|
|
186
|
+
platform: "linux",
|
|
187
|
+
selectAccount: async () => ({ scope: "user", user: "tester", root: false, dedicated: false }),
|
|
188
|
+
ensureTool: async () => {},
|
|
189
|
+
installService: async () => assert.fail("service must not be installed after a failed handshake"),
|
|
190
|
+
invokeTool: async () => {
|
|
191
|
+
throw new Error("Socket closed before the protocol completed");
|
|
192
|
+
},
|
|
193
|
+
output: { log: () => {} }
|
|
194
|
+
}),
|
|
195
|
+
/bootstrap URL may be expired, rotated, already used, or invalid.*before it expires/i
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
|
|
179
199
|
test("ships an immutable verified master-slave bootstrap lock", async (t) => {
|
|
180
200
|
const home = await mkdtemp(path.join(os.tmpdir(), "arisa-slave-lock-"));
|
|
181
201
|
t.after(() => rm(home, { recursive: true, force: true }));
|