first commit
CI / Build & Test (push) Successful in 45s

This commit is contained in:
Raven Scott
2026-03-16 13:05:58 -04:00
commit 0c054707bd
15 changed files with 3488 additions and 0 deletions
+147
View File
@@ -0,0 +1,147 @@
/**
* anisail-tunnel: Bare-compatible Holesail client that binds a local port and
* prints it to stdout for the Ansible connection plugin. Keeps running until
* stdin closes or SIGTERM/SIGINT.
*
* Usage: anisail-tunnel --key <hs://...> [--remote-port 22] [--local-port 0] [--timeout 30000]
* Output: exactly one JSON line to stdout: {"local_port": <number>, "ready": true}
*/
import 'bare-process/global';
const DEFAULT_REMOTE_PORT = 22;
const DEFAULT_LOCAL_PORT = 0;
const DEFAULT_TIMEOUT_MS = 30000;
const LOCAL_HOST = '127.0.0.1';
function parseArgs() {
const args = process.argv.slice(2);
let key = null;
let remotePort = DEFAULT_REMOTE_PORT;
let localPort = DEFAULT_LOCAL_PORT;
let timeoutMs = DEFAULT_TIMEOUT_MS;
for (let i = 0; i < args.length; i++) {
if (args[i] === '--key' && args[i + 1]) {
key = args[++i].trim();
} else if (args[i] === '--remote-port' && args[i + 1]) {
remotePort = parseInt(args[++i], 10) || DEFAULT_REMOTE_PORT;
} else if (args[i] === '--local-port' && args[i + 1]) {
localPort = parseInt(args[++i], 10);
if (isNaN(localPort) || localPort < 0) localPort = DEFAULT_LOCAL_PORT;
} else if (args[i] === '--timeout' && args[i + 1]) {
timeoutMs = parseInt(args[++i], 10) || DEFAULT_TIMEOUT_MS;
}
}
return { key, remotePort, localPort, timeoutMs };
}
function emit(line) {
try {
process.stdout.write(line + '\n');
} catch (_) {}
}
async function run() {
const mod = await import('holesail');
const Holesail = mod.default || mod;
const { key, remotePort, localPort, timeoutMs } = parseArgs();
if (!key || key.length === 0) {
const msg = 'anisail-tunnel: --key <hs://...> is required';
try {
process.stderr.write(msg + '\n');
} catch (_) {}
process.exitCode = 1;
return;
}
const portToUse = (localPort > 0 ? localPort : 19200 + Math.floor(Math.random() * 1000)) || 19200;
const readyPromise = new Promise((resolve, reject) => {
const t = timeoutMs > 0
? setTimeout(() => reject(new Error('Tunnel ready timeout after ' + timeoutMs + 'ms')), timeoutMs)
: null;
const done = (err, port) => {
if (t) clearTimeout(t);
if (err) reject(err);
else resolve(port);
};
const hs = new Holesail({
client: true,
key,
host: LOCAL_HOST,
port: portToUse
});
if (typeof hs.on === 'function') {
hs.on('error', (err) => {
done(err || new Error('Tunnel error'));
});
}
hs.ready()
.then(() => {
const info = typeof hs.info === 'function' ? hs.info() : (hs.info || {});
const boundPort = (info && typeof info.port === 'number')
? info.port
: portToUse;
if (boundPort == null || boundPort < 1 || boundPort > 65535) {
done(new Error('Could not determine local tunnel port'));
return;
}
done(null, boundPort);
return hs;
})
.catch(done);
run._hs = hs;
});
let hs;
try {
const port = await readyPromise;
hs = run._hs;
emit(JSON.stringify({ local_port: port, ready: true }));
} catch (err) {
const msg = (err && err.message) ? err.message : String(err);
try {
process.stderr.write('anisail-tunnel: ' + msg + '\n');
} catch (_) {}
process.exitCode = 1;
return;
}
const close = () => {
if (hs && typeof hs.close === 'function') {
try {
hs.close();
} catch (_) {}
hs = null;
}
process.exitCode = 0;
process.exit(0);
};
process.on('SIGTERM', close);
process.on('SIGINT', close);
process.stdin.on('close', () => {
close();
});
process.stdin.on('end', () => {
close();
});
process.stdin.resume();
}
run().catch((err) => {
try {
process.stderr.write('anisail-tunnel: ' + (err && err.message ? err.message : String(err)) + '\n');
} catch (_) {}
process.exitCode = 1;
});