charness 3.7.0 → 3.9.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/CHANGELOG.md +36 -0
- package/DEVELOPMENT.md +8 -2
- package/README.md +5 -5
- package/SETUP.md +17 -5
- package/agent-plugin/skills/charness-manager/SKILL.md +3 -3
- package/dist/adapters/openCodeAdapter.d.ts.map +1 -1
- package/dist/adapters/openCodeAdapter.js +2 -1
- package/dist/adapters/openCodeAdapter.js.map +1 -1
- package/dist/bot.d.ts.map +1 -1
- package/dist/bot.js +50 -9
- package/dist/bot.js.map +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +56 -6
- package/dist/cli.js.map +1 -1
- package/dist/configDirFile.d.ts +7 -3
- package/dist/configDirFile.d.ts.map +1 -1
- package/dist/configDirFile.js +12 -5
- package/dist/configDirFile.js.map +1 -1
- package/dist/connectors/telegram/commands/botCore.d.ts +5 -1
- package/dist/connectors/telegram/commands/botCore.d.ts.map +1 -1
- package/dist/connectors/telegram/commands/runners.d.ts +52 -0
- package/dist/connectors/telegram/commands/runners.d.ts.map +1 -0
- package/dist/connectors/telegram/commands/runners.js +524 -0
- package/dist/connectors/telegram/commands/runners.js.map +1 -0
- package/dist/connectors/telegram/runnerPairingMessages.d.ts +29 -0
- package/dist/connectors/telegram/runnerPairingMessages.d.ts.map +1 -0
- package/dist/connectors/telegram/runnerPairingMessages.js +112 -0
- package/dist/connectors/telegram/runnerPairingMessages.js.map +1 -0
- package/dist/i18n/de.d.ts.map +1 -1
- package/dist/i18n/de.js +60 -0
- package/dist/i18n/de.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +60 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +60 -0
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/fr.d.ts.map +1 -1
- package/dist/i18n/fr.js +60 -0
- package/dist/i18n/fr.js.map +1 -1
- package/dist/i18n/hi.d.ts.map +1 -1
- package/dist/i18n/hi.js +60 -0
- package/dist/i18n/hi.js.map +1 -1
- package/dist/i18n/ja.d.ts.map +1 -1
- package/dist/i18n/ja.js +60 -0
- package/dist/i18n/ja.js.map +1 -1
- package/dist/i18n/ka.d.ts.map +1 -1
- package/dist/i18n/ka.js +60 -0
- package/dist/i18n/ka.js.map +1 -1
- package/dist/i18n/pt.d.ts.map +1 -1
- package/dist/i18n/pt.js +60 -0
- package/dist/i18n/pt.js.map +1 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +60 -0
- package/dist/i18n/ru.js.map +1 -1
- package/dist/i18n/uk.d.ts.map +1 -1
- package/dist/i18n/uk.js +60 -0
- package/dist/i18n/uk.js.map +1 -1
- package/dist/i18n/uz.d.ts.map +1 -1
- package/dist/i18n/uz.js +60 -0
- package/dist/i18n/uz.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +60 -0
- package/dist/i18n/zh.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/installManager.d.ts +57 -1
- package/dist/installManager.d.ts.map +1 -1
- package/dist/installManager.js +88 -10
- package/dist/installManager.js.map +1 -1
- package/dist/instanceSettings.d.ts +12 -2
- package/dist/instanceSettings.d.ts.map +1 -1
- package/dist/instanceSettings.js +17 -3
- package/dist/instanceSettings.js.map +1 -1
- package/dist/outputTrace.d.ts +6 -0
- package/dist/outputTrace.d.ts.map +1 -1
- package/dist/outputTrace.js +24 -1
- package/dist/outputTrace.js.map +1 -1
- package/dist/remoteRun/cliArgs.d.ts +2 -0
- package/dist/remoteRun/cliArgs.d.ts.map +1 -1
- package/dist/remoteRun/cliArgs.js +11 -2
- package/dist/remoteRun/cliArgs.js.map +1 -1
- package/dist/remoteRun/commands.d.ts +21 -0
- package/dist/remoteRun/commands.d.ts.map +1 -1
- package/dist/remoteRun/commands.js +38 -17
- package/dist/remoteRun/commands.js.map +1 -1
- package/dist/remoteRun/interrupts.d.ts +10 -0
- package/dist/remoteRun/interrupts.d.ts.map +1 -1
- package/dist/remoteRun/interrupts.js +43 -6
- package/dist/remoteRun/interrupts.js.map +1 -1
- package/dist/remoteRun/output.d.ts +2 -0
- package/dist/remoteRun/output.d.ts.map +1 -1
- package/dist/remoteRun/output.js +45 -0
- package/dist/remoteRun/output.js.map +1 -1
- package/dist/remoteRun/pairedRunners.d.ts +51 -0
- package/dist/remoteRun/pairedRunners.d.ts.map +1 -0
- package/dist/remoteRun/pairedRunners.js +165 -0
- package/dist/remoteRun/pairedRunners.js.map +1 -0
- package/dist/remoteRun/probe.d.ts +23 -1
- package/dist/remoteRun/probe.d.ts.map +1 -1
- package/dist/remoteRun/probe.js +45 -11
- package/dist/remoteRun/probe.js.map +1 -1
- package/dist/remoteRun/remoteRunCli.d.ts +13 -6
- package/dist/remoteRun/remoteRunCli.d.ts.map +1 -1
- package/dist/remoteRun/remoteRunCli.js +34 -59
- package/dist/remoteRun/remoteRunCli.js.map +1 -1
- package/dist/remoteRun/runnerClient.d.ts +2 -0
- package/dist/remoteRun/runnerClient.d.ts.map +1 -1
- package/dist/remoteRun/runnerClient.js +5 -1
- package/dist/remoteRun/runnerClient.js.map +1 -1
- package/dist/remoteRun/runnerSummary.d.ts +24 -0
- package/dist/remoteRun/runnerSummary.d.ts.map +1 -0
- package/dist/remoteRun/runnerSummary.js +86 -0
- package/dist/remoteRun/runnerSummary.js.map +1 -0
- package/dist/remoteRun/runnerWait.d.ts +68 -0
- package/dist/remoteRun/runnerWait.d.ts.map +1 -0
- package/dist/remoteRun/runnerWait.js +137 -0
- package/dist/remoteRun/runnerWait.js.map +1 -0
- package/dist/remoteRun/runnerWaitTiming.d.ts +16 -0
- package/dist/remoteRun/runnerWaitTiming.d.ts.map +1 -0
- package/dist/remoteRun/runnerWaitTiming.js +37 -0
- package/dist/remoteRun/runnerWaitTiming.js.map +1 -0
- package/dist/remoteRun/runners.d.ts +15 -8
- package/dist/remoteRun/runners.d.ts.map +1 -1
- package/dist/remoteRun/runners.js +59 -19
- package/dist/remoteRun/runners.js.map +1 -1
- package/dist/remoteRun/runnersCatalog.d.ts +14 -0
- package/dist/remoteRun/runnersCatalog.d.ts.map +1 -0
- package/dist/remoteRun/runnersCatalog.js +68 -0
- package/dist/remoteRun/runnersCatalog.js.map +1 -0
- package/dist/remoteRun/runnersConfig.d.ts +31 -20
- package/dist/remoteRun/runnersConfig.d.ts.map +1 -1
- package/dist/remoteRun/runnersConfig.js +14 -12
- package/dist/remoteRun/runnersConfig.js.map +1 -1
- package/dist/remoteRun/ssh.d.ts +22 -2
- package/dist/remoteRun/ssh.d.ts.map +1 -1
- package/dist/remoteRun/ssh.js +41 -7
- package/dist/remoteRun/ssh.js.map +1 -1
- package/dist/runnerUtility/adminCheck.d.ts +18 -0
- package/dist/runnerUtility/adminCheck.d.ts.map +1 -0
- package/dist/runnerUtility/adminCheck.js +69 -0
- package/dist/runnerUtility/adminCheck.js.map +1 -0
- package/dist/runnerUtility/adminService.d.ts +22 -0
- package/dist/runnerUtility/adminService.d.ts.map +1 -0
- package/dist/runnerUtility/adminService.js +145 -0
- package/dist/runnerUtility/adminService.js.map +1 -0
- package/dist/runnerUtility/appInstall.d.ts +25 -0
- package/dist/runnerUtility/appInstall.d.ts.map +1 -0
- package/dist/runnerUtility/appInstall.js +147 -0
- package/dist/runnerUtility/appInstall.js.map +1 -0
- package/dist/runnerUtility/appUpdate.d.ts +39 -0
- package/dist/runnerUtility/appUpdate.d.ts.map +1 -0
- package/dist/runnerUtility/appUpdate.js +90 -0
- package/dist/runnerUtility/appUpdate.js.map +1 -0
- package/dist/runnerUtility/execEnv.d.ts +21 -0
- package/dist/runnerUtility/execEnv.d.ts.map +1 -0
- package/dist/runnerUtility/execEnv.js +109 -0
- package/dist/runnerUtility/execEnv.js.map +1 -0
- package/dist/runnerUtility/execSession.d.ts +13 -0
- package/dist/runnerUtility/execSession.d.ts.map +1 -0
- package/dist/runnerUtility/execSession.js +58 -0
- package/dist/runnerUtility/execSession.js.map +1 -0
- package/dist/runnerUtility/hubClient.d.ts +30 -0
- package/dist/runnerUtility/hubClient.d.ts.map +1 -0
- package/dist/runnerUtility/hubClient.js +127 -0
- package/dist/runnerUtility/hubClient.js.map +1 -0
- package/dist/runnerUtility/injectStream.d.ts +9 -0
- package/dist/runnerUtility/injectStream.d.ts.map +1 -0
- package/dist/runnerUtility/injectStream.js +12 -0
- package/dist/runnerUtility/injectStream.js.map +1 -0
- package/dist/runnerUtility/iosCheck.d.ts +62 -0
- package/dist/runnerUtility/iosCheck.d.ts.map +1 -0
- package/dist/runnerUtility/iosCheck.js +200 -0
- package/dist/runnerUtility/iosCheck.js.map +1 -0
- package/dist/runnerUtility/launcher.d.ts +5 -0
- package/dist/runnerUtility/launcher.d.ts.map +1 -0
- package/dist/runnerUtility/launcher.js +85 -0
- package/dist/runnerUtility/launcher.js.map +1 -0
- package/dist/runnerUtility/linkLoop.d.ts +39 -0
- package/dist/runnerUtility/linkLoop.d.ts.map +1 -0
- package/dist/runnerUtility/linkLoop.js +274 -0
- package/dist/runnerUtility/linkLoop.js.map +1 -0
- package/dist/runnerUtility/localLinkStop.d.ts +23 -0
- package/dist/runnerUtility/localLinkStop.d.ts.map +1 -0
- package/dist/runnerUtility/localLinkStop.js +79 -0
- package/dist/runnerUtility/localLinkStop.js.map +1 -0
- package/dist/runnerUtility/machineReport.d.ts +39 -0
- package/dist/runnerUtility/machineReport.d.ts.map +1 -0
- package/dist/runnerUtility/machineReport.js +161 -0
- package/dist/runnerUtility/machineReport.js.map +1 -0
- package/dist/runnerUtility/packageId.d.ts +5 -0
- package/dist/runnerUtility/packageId.d.ts.map +1 -0
- package/dist/runnerUtility/packageId.js +64 -0
- package/dist/runnerUtility/packageId.js.map +1 -0
- package/dist/runnerUtility/pairArgs.d.ts +16 -0
- package/dist/runnerUtility/pairArgs.d.ts.map +1 -0
- package/dist/runnerUtility/pairArgs.js +17 -0
- package/dist/runnerUtility/pairArgs.js.map +1 -0
- package/dist/runnerUtility/pairingRecovery.d.ts +31 -0
- package/dist/runnerUtility/pairingRecovery.d.ts.map +1 -0
- package/dist/runnerUtility/pairingRecovery.js +24 -0
- package/dist/runnerUtility/pairingRecovery.js.map +1 -0
- package/dist/runnerUtility/pueueDaemon.d.ts +36 -0
- package/dist/runnerUtility/pueueDaemon.d.ts.map +1 -0
- package/dist/runnerUtility/pueueDaemon.js +165 -0
- package/dist/runnerUtility/pueueDaemon.js.map +1 -0
- package/dist/runnerUtility/rootServiceCli.d.ts +8 -0
- package/dist/runnerUtility/rootServiceCli.d.ts.map +1 -0
- package/dist/runnerUtility/rootServiceCli.js +31 -0
- package/dist/runnerUtility/rootServiceCli.js.map +1 -0
- package/dist/runnerUtility/runnerCli.d.ts +18 -0
- package/dist/runnerUtility/runnerCli.d.ts.map +1 -0
- package/dist/runnerUtility/runnerCli.js +190 -0
- package/dist/runnerUtility/runnerCli.js.map +1 -0
- package/dist/runnerUtility/runnerCommands.d.ts +76 -0
- package/dist/runnerUtility/runnerCommands.d.ts.map +1 -0
- package/dist/runnerUtility/runnerCommands.js +464 -0
- package/dist/runnerUtility/runnerCommands.js.map +1 -0
- package/dist/runnerUtility/runnerConfig.d.ts +63 -0
- package/dist/runnerUtility/runnerConfig.d.ts.map +1 -0
- package/dist/runnerUtility/runnerConfig.js +153 -0
- package/dist/runnerUtility/runnerConfig.js.map +1 -0
- package/dist/runnerUtility/runnerFlags.d.ts +9 -0
- package/dist/runnerUtility/runnerFlags.d.ts.map +1 -0
- package/dist/runnerUtility/runnerFlags.js +53 -0
- package/dist/runnerUtility/runnerFlags.js.map +1 -0
- package/dist/runnerUtility/runnerHome.d.ts +30 -0
- package/dist/runnerUtility/runnerHome.d.ts.map +1 -0
- package/dist/runnerUtility/runnerHome.js +82 -0
- package/dist/runnerUtility/runnerHome.js.map +1 -0
- package/dist/runnerUtility/runnerKeys.d.ts +11 -0
- package/dist/runnerUtility/runnerKeys.d.ts.map +1 -0
- package/dist/runnerUtility/runnerKeys.js +80 -0
- package/dist/runnerUtility/runnerKeys.js.map +1 -0
- package/dist/runnerUtility/runnerServers.d.ts +40 -0
- package/dist/runnerUtility/runnerServers.d.ts.map +1 -0
- package/dist/runnerUtility/runnerServers.js +79 -0
- package/dist/runnerUtility/runnerServers.js.map +1 -0
- package/dist/runnerUtility/serviceCommon.d.ts +97 -0
- package/dist/runnerUtility/serviceCommon.d.ts.map +1 -0
- package/dist/runnerUtility/serviceCommon.js +209 -0
- package/dist/runnerUtility/serviceCommon.js.map +1 -0
- package/dist/runnerUtility/serviceManager.d.ts +51 -0
- package/dist/runnerUtility/serviceManager.d.ts.map +1 -0
- package/dist/runnerUtility/serviceManager.js +344 -0
- package/dist/runnerUtility/serviceManager.js.map +1 -0
- package/dist/runnerUtility/serviceUnits.d.ts +38 -0
- package/dist/runnerUtility/serviceUnits.d.ts.map +1 -0
- package/dist/runnerUtility/serviceUnits.js +189 -0
- package/dist/runnerUtility/serviceUnits.js.map +1 -0
- package/dist/runnerUtility/toolInstall.d.ts +95 -0
- package/dist/runnerUtility/toolInstall.d.ts.map +1 -0
- package/dist/runnerUtility/toolInstall.js +232 -0
- package/dist/runnerUtility/toolInstall.js.map +1 -0
- package/dist/runnerUtility/versionPollTiming.d.ts +16 -0
- package/dist/runnerUtility/versionPollTiming.d.ts.map +1 -0
- package/dist/runnerUtility/versionPollTiming.js +36 -0
- package/dist/runnerUtility/versionPollTiming.js.map +1 -0
- package/dist/runners/authorizedKeys.d.ts +52 -0
- package/dist/runners/authorizedKeys.d.ts.map +1 -0
- package/dist/runners/authorizedKeys.js +153 -0
- package/dist/runners/authorizedKeys.js.map +1 -0
- package/dist/runners/bootstrapLine.d.ts +13 -0
- package/dist/runners/bootstrapLine.d.ts.map +1 -0
- package/dist/runners/bootstrapLine.js +154 -0
- package/dist/runners/bootstrapLine.js.map +1 -0
- package/dist/runners/gate.d.ts +41 -0
- package/dist/runners/gate.d.ts.map +1 -0
- package/dist/runners/gate.js +225 -0
- package/dist/runners/gate.js.map +1 -0
- package/dist/runners/gateLink.d.ts +26 -0
- package/dist/runners/gateLink.d.ts.map +1 -0
- package/dist/runners/gateLink.js +240 -0
- package/dist/runners/gateLink.js.map +1 -0
- package/dist/runners/gateProtocol.d.ts +104 -0
- package/dist/runners/gateProtocol.d.ts.map +1 -0
- package/dist/runners/gateProtocol.js +151 -0
- package/dist/runners/gateProtocol.js.map +1 -0
- package/dist/runners/gateWrapper.d.ts +6 -0
- package/dist/runners/gateWrapper.d.ts.map +1 -0
- package/dist/runners/gateWrapper.js +70 -0
- package/dist/runners/gateWrapper.js.map +1 -0
- package/dist/runners/hubAddress.d.ts +33 -0
- package/dist/runners/hubAddress.d.ts.map +1 -0
- package/dist/runners/hubAddress.js +88 -0
- package/dist/runners/hubAddress.js.map +1 -0
- package/dist/runners/hubAddressCandidates.d.ts +16 -0
- package/dist/runners/hubAddressCandidates.d.ts.map +1 -0
- package/dist/runners/hubAddressCandidates.js +96 -0
- package/dist/runners/hubAddressCandidates.js.map +1 -0
- package/dist/runners/hubIds.d.ts +16 -0
- package/dist/runners/hubIds.d.ts.map +1 -0
- package/dist/runners/hubIds.js +25 -0
- package/dist/runners/hubIds.js.map +1 -0
- package/dist/runners/hubKey.d.ts +6 -0
- package/dist/runners/hubKey.d.ts.map +1 -0
- package/dist/runners/hubKey.js +78 -0
- package/dist/runners/hubKey.js.map +1 -0
- package/dist/runners/hubLock.d.ts +7 -0
- package/dist/runners/hubLock.d.ts.map +1 -0
- package/dist/runners/hubLock.js +230 -0
- package/dist/runners/hubLock.js.map +1 -0
- package/dist/runners/hubPackage.d.ts +23 -0
- package/dist/runners/hubPackage.d.ts.map +1 -0
- package/dist/runners/hubPackage.js +184 -0
- package/dist/runners/hubPackage.js.map +1 -0
- package/dist/runners/hubPairing.d.ts +70 -0
- package/dist/runners/hubPairing.d.ts.map +1 -0
- package/dist/runners/hubPairing.js +277 -0
- package/dist/runners/hubPairing.js.map +1 -0
- package/dist/runners/hubPaths.d.ts +42 -0
- package/dist/runners/hubPaths.d.ts.map +1 -0
- package/dist/runners/hubPaths.js +96 -0
- package/dist/runners/hubPaths.js.map +1 -0
- package/dist/runners/hubRegistry.d.ts +134 -0
- package/dist/runners/hubRegistry.d.ts.map +1 -0
- package/dist/runners/hubRegistry.js +256 -0
- package/dist/runners/hubRegistry.js.map +1 -0
- package/dist/runners/linkControl.d.ts +38 -0
- package/dist/runners/linkControl.d.ts.map +1 -0
- package/dist/runners/linkControl.js +171 -0
- package/dist/runners/linkControl.js.map +1 -0
- package/dist/runners/pairCode.d.ts +30 -0
- package/dist/runners/pairCode.d.ts.map +1 -0
- package/dist/runners/pairCode.js +46 -0
- package/dist/runners/pairCode.js.map +1 -0
- package/dist/runners/pairingTiming.d.ts +18 -0
- package/dist/runners/pairingTiming.d.ts.map +1 -0
- package/dist/runners/pairingTiming.js +42 -0
- package/dist/runners/pairingTiming.js.map +1 -0
- package/dist/runners/removalTiming.d.ts +13 -0
- package/dist/runners/removalTiming.d.ts.map +1 -0
- package/dist/runners/removalTiming.js +17 -0
- package/dist/runners/removalTiming.js.map +1 -0
- package/dist/runners/runnerProxy.d.ts +9 -0
- package/dist/runners/runnerProxy.d.ts.map +1 -0
- package/dist/runners/runnerProxy.js +67 -0
- package/dist/runners/runnerProxy.js.map +1 -0
- package/dist/runners/runnerRemoval.d.ts +21 -0
- package/dist/runners/runnerRemoval.d.ts.map +1 -0
- package/dist/runners/runnerRemoval.js +94 -0
- package/dist/runners/runnerRemoval.js.map +1 -0
- package/dist/runners/runnerServiceKind.d.ts +10 -0
- package/dist/runners/runnerServiceKind.d.ts.map +1 -0
- package/dist/runners/runnerServiceKind.js +13 -0
- package/dist/runners/runnerServiceKind.js.map +1 -0
- package/dist/runners/runnersCli.d.ts +25 -0
- package/dist/runners/runnersCli.d.ts.map +1 -0
- package/dist/runners/runnersCli.js +239 -0
- package/dist/runners/runnersCli.js.map +1 -0
- package/dist/runners/runnersList.d.ts +14 -0
- package/dist/runners/runnersList.d.ts.map +1 -0
- package/dist/runners/runnersList.js +51 -0
- package/dist/runners/runnersList.js.map +1 -0
- package/dist/runners/runnersOverview.d.ts +20 -0
- package/dist/runners/runnersOverview.d.ts.map +1 -0
- package/dist/runners/runnersOverview.js +56 -0
- package/dist/runners/runnersOverview.js.map +1 -0
- package/dist/runners/sshKeys.d.ts +26 -0
- package/dist/runners/sshKeys.d.ts.map +1 -0
- package/dist/runners/sshKeys.js +60 -0
- package/dist/runners/sshKeys.js.map +1 -0
- package/dist/runners/tarArchive.d.ts +20 -0
- package/dist/runners/tarArchive.d.ts.map +1 -0
- package/dist/runners/tarArchive.js +70 -0
- package/dist/runners/tarArchive.js.map +1 -0
- package/dist/scheduler/mcpSurface.d.ts +11 -5
- package/dist/scheduler/mcpSurface.d.ts.map +1 -1
- package/dist/scheduler/mcpSurface.js +59 -26
- package/dist/scheduler/mcpSurface.js.map +1 -1
- package/dist/selfUpdate/selfCheck.d.ts +13 -0
- package/dist/selfUpdate/selfCheck.d.ts.map +1 -1
- package/dist/selfUpdate/selfCheck.js +9 -3
- package/dist/selfUpdate/selfCheck.js.map +1 -1
- package/dist/stt/sttInstallEntry.js +7 -4
- package/dist/stt/sttInstallEntry.js.map +1 -1
- package/dist/testTimings.d.ts +5 -2
- package/dist/testTimings.d.ts.map +1 -1
- package/dist/testTimings.js +10 -1
- package/dist/testTimings.js.map +1 -1
- package/dist/utils/agentEnvironment.d.ts +6 -2
- package/dist/utils/agentEnvironment.d.ts.map +1 -1
- package/dist/utils/agentEnvironment.js +13 -2
- package/dist/utils/agentEnvironment.js.map +1 -1
- package/dist/utils/runnersScreenPlan.d.ts +141 -0
- package/dist/utils/runnersScreenPlan.d.ts.map +1 -0
- package/dist/utils/runnersScreenPlan.js +272 -0
- package/dist/utils/runnersScreenPlan.js.map +1 -0
- package/package.json +5 -2
- package/remoteRun/runner.sh +81 -6
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.defaultGateLinkTimings = void 0;
|
|
37
|
+
exports.runGateLink = runGateLink;
|
|
38
|
+
const crypto_1 = require("crypto");
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const net = __importStar(require("net"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const stream_1 = require("stream");
|
|
43
|
+
const ssh2_1 = require("ssh2");
|
|
44
|
+
const configDirFile_1 = require("../configDirFile");
|
|
45
|
+
const gateProtocol_1 = require("./gateProtocol");
|
|
46
|
+
const hubPaths_1 = require("./hubPaths");
|
|
47
|
+
const hubKey_1 = require("./hubKey");
|
|
48
|
+
const hubRegistry_1 = require("./hubRegistry");
|
|
49
|
+
const linkControl_1 = require("./linkControl");
|
|
50
|
+
const sshKeys_1 = require("./sshKeys");
|
|
51
|
+
/**
|
|
52
|
+
* @description The `link` request: the hub end of a runner's permanent connection.
|
|
53
|
+
*
|
|
54
|
+
* The runner dials the hub with an ordinary ssh client and runs `link`; sshd starts this gate, whose stdin and stdout ARE that
|
|
55
|
+
* channel. Over it the roles turn around: the gate is an ssh CLIENT (`ssh2`) and the runner's built-in server is the SERVER — the gate
|
|
56
|
+
* checks the server's host key against the one pinned at pairing and logs in with the hub key. The gate then listens on
|
|
57
|
+
* `link/<id>.sock`; for every connection to it, it opens a `direct-tcpip` channel to the runner, whose server treats the channel as
|
|
58
|
+
* a socket of its own and speaks ssh over it to whoever is on the other end — stock `ssh` through `runner-proxy`, with everything
|
|
59
|
+
* remote-run needs from ssh (one master, rsync, exec). The runner has no listening port, and the hub's only exposure is the forced
|
|
60
|
+
* command of a key that cannot forward anything.
|
|
61
|
+
*
|
|
62
|
+
* A request from the runner side to open a channel or a forwarding is refused by the client library itself (nothing is registered
|
|
63
|
+
* for it); the gate accepts none.
|
|
64
|
+
*
|
|
65
|
+
* NEWEST LINK WINS: a gate that starts takes the socket path over (it renames its freshly bound socket onto it). The gate that was
|
|
66
|
+
* replaced notices within one check interval — the file at the path is not the one it bound — and leaves, which also ends the runner's
|
|
67
|
+
* half-open old connection. The same check ends a gate whose runner was removed from the registry. A stock sshd with
|
|
68
|
+
* `ClientAliveInterval 0` would never notice a dead peer; the ssh keepalive of this client does.
|
|
69
|
+
*/
|
|
70
|
+
const loopbackAddress = '127.0.0.1';
|
|
71
|
+
/** The port of the `direct-tcpip` request. The runner's server ignores it: every channel goes to its one ssh server. */
|
|
72
|
+
const runnerServerPort = 22;
|
|
73
|
+
const socketMode = 0o600;
|
|
74
|
+
const linkDirMode = 0o700;
|
|
75
|
+
const socketSuffixBytes = 3;
|
|
76
|
+
const keepaliveCountMax = 3;
|
|
77
|
+
const sshHostKeyAlgorithm = 'ssh-ed25519';
|
|
78
|
+
exports.defaultGateLinkTimings = { checkIntervalMs: 10 * 1000, keepaliveIntervalMs: 15 * 1000, readyTimeoutMs: 20 * 1000 };
|
|
79
|
+
/**
|
|
80
|
+
* A writable that hands everything to `target` and never ends it: the gate's stdout is `process.stdout`, which is not to be closed
|
|
81
|
+
* (the gate ends by leaving), and the ssh client ends its transport when it is done.
|
|
82
|
+
*/
|
|
83
|
+
function createNonClosingWritable(target) {
|
|
84
|
+
return new stream_1.Writable({
|
|
85
|
+
write(chunk, _encoding, callback) {
|
|
86
|
+
target.write(chunk, callback);
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/** @description Run the link until it ends; resolves with the exit code of the gate (0: it held the link and it ended; 1: it never came up). */
|
|
91
|
+
function runGateLink(params) {
|
|
92
|
+
const { ctx, runnerId, log } = params;
|
|
93
|
+
const timings = { ...exports.defaultGateLinkTimings, ...params.timings };
|
|
94
|
+
const now = params.now ?? Date.now;
|
|
95
|
+
const paths = (0, hubPaths_1.getRunnerLinkPaths)(ctx.dir, runnerId);
|
|
96
|
+
const runner = (0, hubRegistry_1.readPairedFile)(ctx.dir).runners.find((candidate) => candidate.id === runnerId);
|
|
97
|
+
const hubKey = (0, hubKey_1.readHubKey)(ctx.dir);
|
|
98
|
+
const pinnedHostKey = runner === undefined ? null : (0, sshKeys_1.parsePublicKey)(runner.hostKey);
|
|
99
|
+
if (runner === undefined || hubKey === null || pinnedHostKey === null) {
|
|
100
|
+
log('this runner is not paired here');
|
|
101
|
+
return Promise.resolve(1);
|
|
102
|
+
}
|
|
103
|
+
const pinnedBlob = pinnedHostKey.blob;
|
|
104
|
+
return new Promise((resolve) => {
|
|
105
|
+
const client = new ssh2_1.Client();
|
|
106
|
+
const openConnections = new Set();
|
|
107
|
+
const sinceMs = now();
|
|
108
|
+
let server = null;
|
|
109
|
+
let boundInode = null;
|
|
110
|
+
let checkTimer = null;
|
|
111
|
+
let isReady = false;
|
|
112
|
+
let isFinished = false;
|
|
113
|
+
const duplex = stream_1.Duplex.from({ readable: params.input, writable: createNonClosingWritable(params.output) });
|
|
114
|
+
const readSocketInode = () => {
|
|
115
|
+
try {
|
|
116
|
+
return fs.statSync(paths.socket).ino;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const writeState = (state) => {
|
|
123
|
+
try {
|
|
124
|
+
(0, linkControl_1.writeLinkState)(ctx.dir, runnerId, state);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
// The link works without its status file; the hub only loses "last seen".
|
|
128
|
+
log(`cannot write the link status (${(0, configDirFile_1.getCaughtErrnoCode)(error)})`);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const finish = (reason) => {
|
|
132
|
+
if (isFinished)
|
|
133
|
+
return;
|
|
134
|
+
isFinished = true;
|
|
135
|
+
if (checkTimer !== null)
|
|
136
|
+
clearInterval(checkTimer);
|
|
137
|
+
for (const connection of openConnections)
|
|
138
|
+
connection.destroy();
|
|
139
|
+
// The socket file is NOT deleted here: checking that the file is still this gate's and then deleting it is two steps, and a
|
|
140
|
+
// successor may rename its own socket onto the path between them. A leftover file only refuses connections (the runner reads as
|
|
141
|
+
// offline); the next gate renames over it and `cutRunnerLink` deletes it.
|
|
142
|
+
server?.close();
|
|
143
|
+
const state = (0, linkControl_1.readLinkState)(ctx.dir, runnerId);
|
|
144
|
+
if (isReady && state?.pid === process.pid)
|
|
145
|
+
writeState({ ...state, endedAtMs: now() });
|
|
146
|
+
log(`link ended: ${reason}`);
|
|
147
|
+
client.end();
|
|
148
|
+
duplex.destroy();
|
|
149
|
+
resolve(isReady ? 0 : 1);
|
|
150
|
+
};
|
|
151
|
+
const beat = () => {
|
|
152
|
+
writeState({ pid: process.pid, sinceMs, lastBeatMs: now(), endedAtMs: null });
|
|
153
|
+
};
|
|
154
|
+
const check = () => {
|
|
155
|
+
if (readSocketInode() !== boundInode) {
|
|
156
|
+
finish('another link took over');
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
if (!(0, hubRegistry_1.readPairedFile)(ctx.dir).runners.some((candidate) => candidate.id === runnerId)) {
|
|
161
|
+
finish('the runner was removed');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// An unreadable registry says nothing about this runner: keep the link and look again at the next check.
|
|
167
|
+
}
|
|
168
|
+
beat();
|
|
169
|
+
};
|
|
170
|
+
const acceptConnection = (connection) => {
|
|
171
|
+
openConnections.add(connection);
|
|
172
|
+
connection.on('close', () => openConnections.delete(connection));
|
|
173
|
+
connection.on('error', () => connection.destroy());
|
|
174
|
+
try {
|
|
175
|
+
client.forwardOut(loopbackAddress, 0, loopbackAddress, runnerServerPort, (error, channel) => {
|
|
176
|
+
if (error !== undefined) {
|
|
177
|
+
connection.destroy();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (connection.destroyed) {
|
|
181
|
+
channel.destroy();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
connection.pipe(channel);
|
|
185
|
+
channel.pipe(connection);
|
|
186
|
+
channel.on('close', () => connection.destroy());
|
|
187
|
+
channel.on('error', () => connection.destroy());
|
|
188
|
+
connection.on('close', () => channel.destroy());
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
connection.destroy();
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
// The socket is bound under a name of its own and RENAMED onto the link's path: renaming is the atomic takeover, and a gate that is
|
|
196
|
+
// replaced closes its server without touching the new gate's file (`net.Server.close()` deletes whatever file is at the path it was
|
|
197
|
+
// bound to — at the link's path that would be the successor's socket).
|
|
198
|
+
const bindSocket = () => {
|
|
199
|
+
fs.mkdirSync(path.dirname(paths.socket), { recursive: true, mode: linkDirMode });
|
|
200
|
+
const ownPath = `${paths.socket}.${(0, crypto_1.randomBytes)(socketSuffixBytes).toString('hex')}`;
|
|
201
|
+
const listener = net.createServer(acceptConnection);
|
|
202
|
+
server = listener;
|
|
203
|
+
listener.once('error', (error) => finish(`cannot listen on the link socket (${(0, configDirFile_1.getCaughtErrnoCode)(error)})`));
|
|
204
|
+
listener.listen(ownPath, () => {
|
|
205
|
+
try {
|
|
206
|
+
fs.chmodSync(ownPath, socketMode);
|
|
207
|
+
boundInode = fs.statSync(ownPath).ino;
|
|
208
|
+
fs.renameSync(ownPath, paths.socket);
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
finish(`cannot publish the link socket (${(0, configDirFile_1.getCaughtErrnoCode)(error)})`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
isReady = true;
|
|
215
|
+
beat();
|
|
216
|
+
checkTimer = setInterval(check, timings.checkIntervalMs);
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
params.output.write((0, gateProtocol_1.formatGateAnswerHead)('link', { package: params.packageId ?? gateProtocol_1.noPackageMarker }));
|
|
220
|
+
duplex.on('error', () => finish('the connection to the runner failed'));
|
|
221
|
+
// The channel from the runner ended cleanly (EOF: the ssh session that carried it is gone). A duplex whose readable side ended stays half
|
|
222
|
+
// open, so the ssh client never sees a close — only a failed write or the keepalive's silence would tell, and until then the hub shows a
|
|
223
|
+
// runner that has left as online.
|
|
224
|
+
params.input.once('end', () => finish('the channel from the runner ended'));
|
|
225
|
+
client.on('error', (error) => finish(`ssh: ${error.message}`));
|
|
226
|
+
client.on('close', () => finish('the runner disconnected'));
|
|
227
|
+
client.on('ready', bindSocket);
|
|
228
|
+
client.connect({
|
|
229
|
+
sock: duplex,
|
|
230
|
+
username: gateProtocol_1.linkUserName,
|
|
231
|
+
privateKey: hubKey.privateKey,
|
|
232
|
+
algorithms: { serverHostKey: [sshHostKeyAlgorithm] },
|
|
233
|
+
hostVerifier: (key) => Buffer.isBuffer(key) && key.equals(pinnedBlob),
|
|
234
|
+
keepaliveInterval: timings.keepaliveIntervalMs,
|
|
235
|
+
keepaliveCountMax,
|
|
236
|
+
readyTimeout: timings.readyTimeoutMs,
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=gateLink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateLink.js","sourceRoot":"","sources":["../../src/runners/gateLink.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { Readable } from 'stream';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* @description What a runner and the hub's gate say to each other over the forced command of the runner's ssh key. The runner runs
|
|
5
|
+
* `ssh … <request>`; sshd starts the gate with the request word in `SSH_ORIGINAL_COMMAND`.
|
|
6
|
+
*
|
|
7
|
+
* temporary key (a pairing code): `bootstrap` marker line, then the packed charness package (raw gzip)
|
|
8
|
+
* `redeem` stdin: a {@link RedeemRequest} as JSON; stdout: marker line, then a {@link RedeemReply}
|
|
9
|
+
* permanent key (a paired runner): `link` marker line, then an ssh session in which the GATE is the client (see gateLink.ts)
|
|
10
|
+
* `package` marker line, then the packed package (raw gzip)
|
|
11
|
+
* `version` marker line with the hub's current `package=<id>`, nothing else — asked every few minutes over
|
|
12
|
+
* the connection that is already open, so a linked runner learns of an update
|
|
13
|
+
* `identity` marker line, then a {@link RedeemReply} — what `redeem` answered for this key's runner. The
|
|
14
|
+
* way back for a runner whose redeem answer was lost: the hub committed the pairing and
|
|
15
|
+
* removed the temporary key, so only the permanent key can still ask
|
|
16
|
+
* `unpair` marker line, then {@link UnpairReply}
|
|
17
|
+
*
|
|
18
|
+
* Every answer starts with a MARKER line (after a line break, see {@link formatGateAnswerHead}): a shell that prints something before the
|
|
19
|
+
* forced command (a chatty `.bashrc`) would otherwise corrupt the stream; the reader discards everything up to the marker — the runner
|
|
20
|
+
* utility with {@link readUntilGateMarker}, the pasted `sh` line with `grep -b` over the first {@link maxGateNoiseBytes} bytes.
|
|
21
|
+
*/
|
|
22
|
+
/** The text every marker line starts with; the `1` is the protocol version. */
|
|
23
|
+
export declare const gateMarker = "--charness-gate-1--";
|
|
24
|
+
export declare const gateRequests: readonly ["bootstrap", "redeem", "cancel", "link", "package", "version", "identity", "unpair"];
|
|
25
|
+
/** @name GateRequest @description One of the words a runner may send. */
|
|
26
|
+
export type GateRequest = (typeof gateRequests)[number];
|
|
27
|
+
export declare const temporaryKeyRequests: readonly GateRequest[];
|
|
28
|
+
export declare const runnerKeyRequests: readonly GateRequest[];
|
|
29
|
+
/** What a `link` / `version` answer names as the package when the hub cannot pack one. */
|
|
30
|
+
export declare const noPackageMarker = "none";
|
|
31
|
+
/** The username the gate's ssh client logs in with inside the link (the runner's server ignores it). */
|
|
32
|
+
export declare const linkUserName = "charness";
|
|
33
|
+
/** The most bytes of a request body the gate reads from stdin. */
|
|
34
|
+
export declare const maxGateRequestBytes: number;
|
|
35
|
+
/**
|
|
36
|
+
* @description What every answer of the gate starts with: a line break, then the marker line. The break ends whatever unfinished line a
|
|
37
|
+
* shell rc printed before the gate ran (a banner without its newline), so the marker always opens a line of its own.
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatGateAnswerHead(request: GateRequest, fields?: Readonly<Record<string, string>>): string;
|
|
40
|
+
/** @description `--charness-gate-1-- link package=abc…`, newline included. Field values are limited to a safe alphabet. */
|
|
41
|
+
export declare function formatGateMarkerLine(request: GateRequest, fields?: Readonly<Record<string, string>>): string;
|
|
42
|
+
export interface GateMarker {
|
|
43
|
+
request: GateRequest;
|
|
44
|
+
fields: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
/** @description The marker `line` (without its newline) says, or `null` when it is not a marker line. */
|
|
47
|
+
export declare function parseGateMarkerLine(line: string): GateMarker | null;
|
|
48
|
+
/** How much text before the marker (a chatty shell rc) a reader puts up with. */
|
|
49
|
+
export declare const maxGateNoiseBytes: number;
|
|
50
|
+
/**
|
|
51
|
+
* @description Read `stream` up to and including the marker line: lines before it (noise from the hub's shell) are dropped. Resolves with
|
|
52
|
+
* the marker and the bytes that followed it in what was read — the caller puts them back (`stream.unshift(rest)`) before handing the
|
|
53
|
+
* stream on, since they already belong to the answer. `null`: the stream ended or the noise was too long without a marker. The stream
|
|
54
|
+
* is paused when this resolves.
|
|
55
|
+
*/
|
|
56
|
+
export declare function readUntilGateMarker(stream: Readable, maxNoiseBytes?: number): Promise<{
|
|
57
|
+
marker: GateMarker;
|
|
58
|
+
rest: Buffer;
|
|
59
|
+
} | null>;
|
|
60
|
+
/** @description What the runner tells the hub when it redeems a pairing code. */
|
|
61
|
+
export declare const redeemRequestSchema: z.ZodObject<{
|
|
62
|
+
suggestedName: z.ZodString;
|
|
63
|
+
publicKey: z.ZodString;
|
|
64
|
+
hostKey: z.ZodString;
|
|
65
|
+
workDir: z.ZodString;
|
|
66
|
+
os: z.ZodString;
|
|
67
|
+
arch: z.ZodString;
|
|
68
|
+
version: z.ZodString;
|
|
69
|
+
serviceKind: z.ZodEnum<{
|
|
70
|
+
unknown: "unknown";
|
|
71
|
+
foreground: "foreground";
|
|
72
|
+
"user-service": "user-service";
|
|
73
|
+
"system-service": "system-service";
|
|
74
|
+
}>;
|
|
75
|
+
}, z.core.$strict>;
|
|
76
|
+
/** @name RedeemRequest @description The body of a `redeem`. */
|
|
77
|
+
export type RedeemRequest = z.infer<typeof redeemRequestSchema>;
|
|
78
|
+
export declare const redeemReplySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
79
|
+
ok: z.ZodLiteral<true>;
|
|
80
|
+
runnerId: z.ZodString;
|
|
81
|
+
name: z.ZodString;
|
|
82
|
+
hubPublicKey: z.ZodString;
|
|
83
|
+
label: z.ZodString;
|
|
84
|
+
host: z.ZodString;
|
|
85
|
+
port: z.ZodNumber;
|
|
86
|
+
packageId: z.ZodNullable<z.ZodString>;
|
|
87
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
88
|
+
ok: z.ZodLiteral<false>;
|
|
89
|
+
reason: z.ZodString;
|
|
90
|
+
}, z.core.$strict>], "ok">;
|
|
91
|
+
/** @name RedeemReply @description What `redeem` answers. */
|
|
92
|
+
export type RedeemReply = z.infer<typeof redeemReplySchema>;
|
|
93
|
+
export declare const unpairReplySchema: z.ZodObject<{
|
|
94
|
+
ok: z.ZodBoolean;
|
|
95
|
+
}, z.core.$strict>;
|
|
96
|
+
/** `ok`: the code was open and is closed now; `false`: there was nothing to close (spent, expired, or cancelled already). */
|
|
97
|
+
export declare const cancelReplySchema: z.ZodObject<{
|
|
98
|
+
ok: z.ZodBoolean;
|
|
99
|
+
}, z.core.$strict>;
|
|
100
|
+
/** @name CancelReply @description What `cancel` answers. */
|
|
101
|
+
export type CancelReply = z.infer<typeof cancelReplySchema>;
|
|
102
|
+
/** @name UnpairReply @description What `unpair` answers. */
|
|
103
|
+
export type UnpairReply = z.infer<typeof unpairReplySchema>;
|
|
104
|
+
//# sourceMappingURL=gateProtocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateProtocol.d.ts","sourceRoot":"","sources":["../../src/runners/gateProtocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;;;;;;;;;;;;;;;;GAkBG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,UAAU,wBAAwB,CAAC;AAChD,eAAO,MAAM,YAAY,gGAAiG,CAAC;AAC3H,yEAAyE;AACzE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,eAAO,MAAM,oBAAoB,EAAE,SAAS,WAAW,EAAsC,CAAC;AAC9F,eAAO,MAAM,iBAAiB,EAAE,SAAS,WAAW,EAAyD,CAAC;AAE9G,0FAA0F;AAC1F,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,wGAAwG;AACxG,eAAO,MAAM,YAAY,aAAa,CAAC;AACvC,kEAAkE;AAClE,eAAO,MAAM,mBAAmB,QAAY,CAAC;AAK7C;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,GAAG,MAAM,CAEhH;AAMD,2HAA2H;AAC3H,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,GAAG,MAAM,CAGhH;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,yGAAyG;AACzG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CASnE;AAGD,iFAAiF;AACjF,eAAO,MAAM,iBAAiB,QAAY,CAAC;AAE3C;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAE,MAA0B,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAsCrJ;AAID,iFAAiF;AACjF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;kBAU9B,CAAC;AACH,+DAA+D;AAC/D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;0BAa5B,CAAC;AACH,4DAA4D;AAC5D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,iBAAiB;;kBAAsC,CAAC;AAErE,6HAA6H;AAC7H,eAAO,MAAM,iBAAiB;;kBAAsC,CAAC;AACrE,4DAA4D;AAC5D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,4DAA4D;AAC5D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cancelReplySchema = exports.unpairReplySchema = exports.redeemReplySchema = exports.redeemRequestSchema = exports.maxGateNoiseBytes = exports.maxGateRequestBytes = exports.linkUserName = exports.noPackageMarker = exports.runnerKeyRequests = exports.temporaryKeyRequests = exports.gateRequests = exports.gateMarker = void 0;
|
|
4
|
+
exports.formatGateAnswerHead = formatGateAnswerHead;
|
|
5
|
+
exports.formatGateMarkerLine = formatGateMarkerLine;
|
|
6
|
+
exports.parseGateMarkerLine = parseGateMarkerLine;
|
|
7
|
+
exports.readUntilGateMarker = readUntilGateMarker;
|
|
8
|
+
const zod_1 = require("zod");
|
|
9
|
+
const runnersConfig_1 = require("../remoteRun/runnersConfig");
|
|
10
|
+
const hubIds_1 = require("./hubIds");
|
|
11
|
+
const sshKeys_1 = require("./sshKeys");
|
|
12
|
+
const hubRegistry_1 = require("./hubRegistry");
|
|
13
|
+
/**
|
|
14
|
+
* @description What a runner and the hub's gate say to each other over the forced command of the runner's ssh key. The runner runs
|
|
15
|
+
* `ssh … <request>`; sshd starts the gate with the request word in `SSH_ORIGINAL_COMMAND`.
|
|
16
|
+
*
|
|
17
|
+
* temporary key (a pairing code): `bootstrap` marker line, then the packed charness package (raw gzip)
|
|
18
|
+
* `redeem` stdin: a {@link RedeemRequest} as JSON; stdout: marker line, then a {@link RedeemReply}
|
|
19
|
+
* permanent key (a paired runner): `link` marker line, then an ssh session in which the GATE is the client (see gateLink.ts)
|
|
20
|
+
* `package` marker line, then the packed package (raw gzip)
|
|
21
|
+
* `version` marker line with the hub's current `package=<id>`, nothing else — asked every few minutes over
|
|
22
|
+
* the connection that is already open, so a linked runner learns of an update
|
|
23
|
+
* `identity` marker line, then a {@link RedeemReply} — what `redeem` answered for this key's runner. The
|
|
24
|
+
* way back for a runner whose redeem answer was lost: the hub committed the pairing and
|
|
25
|
+
* removed the temporary key, so only the permanent key can still ask
|
|
26
|
+
* `unpair` marker line, then {@link UnpairReply}
|
|
27
|
+
*
|
|
28
|
+
* Every answer starts with a MARKER line (after a line break, see {@link formatGateAnswerHead}): a shell that prints something before the
|
|
29
|
+
* forced command (a chatty `.bashrc`) would otherwise corrupt the stream; the reader discards everything up to the marker — the runner
|
|
30
|
+
* utility with {@link readUntilGateMarker}, the pasted `sh` line with `grep -b` over the first {@link maxGateNoiseBytes} bytes.
|
|
31
|
+
*/
|
|
32
|
+
/** The text every marker line starts with; the `1` is the protocol version. */
|
|
33
|
+
exports.gateMarker = '--charness-gate-1--';
|
|
34
|
+
exports.gateRequests = ['bootstrap', 'redeem', 'cancel', 'link', 'package', 'version', 'identity', 'unpair'];
|
|
35
|
+
exports.temporaryKeyRequests = ['bootstrap', 'redeem', 'cancel'];
|
|
36
|
+
exports.runnerKeyRequests = ['link', 'package', 'version', 'identity', 'unpair'];
|
|
37
|
+
/** What a `link` / `version` answer names as the package when the hub cannot pack one. */
|
|
38
|
+
exports.noPackageMarker = 'none';
|
|
39
|
+
/** The username the gate's ssh client logs in with inside the link (the runner's server ignores it). */
|
|
40
|
+
exports.linkUserName = 'charness';
|
|
41
|
+
/** The most bytes of a request body the gate reads from stdin. */
|
|
42
|
+
exports.maxGateRequestBytes = 64 * 1024;
|
|
43
|
+
const maxTextLength = 200;
|
|
44
|
+
const markerLinePattern = new RegExp(`^${exports.gateMarker} (${exports.gateRequests.join('|')})((?: [a-z]+=[A-Za-z0-9._:@/-]*)*)$`);
|
|
45
|
+
/**
|
|
46
|
+
* @description What every answer of the gate starts with: a line break, then the marker line. The break ends whatever unfinished line a
|
|
47
|
+
* shell rc printed before the gate ran (a banner without its newline), so the marker always opens a line of its own.
|
|
48
|
+
*/
|
|
49
|
+
function formatGateAnswerHead(request, fields = {}) {
|
|
50
|
+
return `\n${formatGateMarkerLine(request, fields)}`;
|
|
51
|
+
}
|
|
52
|
+
function checkIsGateRequest(value) {
|
|
53
|
+
return exports.gateRequests.some((request) => request === value);
|
|
54
|
+
}
|
|
55
|
+
/** @description `--charness-gate-1-- link package=abc…`, newline included. Field values are limited to a safe alphabet. */
|
|
56
|
+
function formatGateMarkerLine(request, fields = {}) {
|
|
57
|
+
const rendered = Object.entries(fields).map(([key, value]) => ` ${key}=${value}`).join('');
|
|
58
|
+
return `${exports.gateMarker} ${request}${rendered}\n`;
|
|
59
|
+
}
|
|
60
|
+
/** @description The marker `line` (without its newline) says, or `null` when it is not a marker line. */
|
|
61
|
+
function parseGateMarkerLine(line) {
|
|
62
|
+
const match = markerLinePattern.exec(line);
|
|
63
|
+
if (match === null || !checkIsGateRequest(match[1]))
|
|
64
|
+
return null;
|
|
65
|
+
const fields = {};
|
|
66
|
+
for (const field of match[2].split(' ').filter((part) => part !== '')) {
|
|
67
|
+
const separator = field.indexOf('=');
|
|
68
|
+
fields[field.slice(0, separator)] = field.slice(separator + 1);
|
|
69
|
+
}
|
|
70
|
+
return { request: match[1], fields };
|
|
71
|
+
}
|
|
72
|
+
const newlineByte = 0x0a;
|
|
73
|
+
/** How much text before the marker (a chatty shell rc) a reader puts up with. */
|
|
74
|
+
exports.maxGateNoiseBytes = 64 * 1024;
|
|
75
|
+
/**
|
|
76
|
+
* @description Read `stream` up to and including the marker line: lines before it (noise from the hub's shell) are dropped. Resolves with
|
|
77
|
+
* the marker and the bytes that followed it in what was read — the caller puts them back (`stream.unshift(rest)`) before handing the
|
|
78
|
+
* stream on, since they already belong to the answer. `null`: the stream ended or the noise was too long without a marker. The stream
|
|
79
|
+
* is paused when this resolves.
|
|
80
|
+
*/
|
|
81
|
+
function readUntilGateMarker(stream, maxNoiseBytes = exports.maxGateNoiseBytes) {
|
|
82
|
+
return new Promise((resolve) => {
|
|
83
|
+
let buffered = Buffer.alloc(0);
|
|
84
|
+
let droppedBytes = 0;
|
|
85
|
+
const settle = (result) => {
|
|
86
|
+
stream.off('data', onData);
|
|
87
|
+
stream.off('end', onEnd);
|
|
88
|
+
stream.off('close', onEnd);
|
|
89
|
+
stream.pause();
|
|
90
|
+
resolve(result);
|
|
91
|
+
};
|
|
92
|
+
const onData = (chunk) => {
|
|
93
|
+
buffered = Buffer.concat([buffered, chunk]);
|
|
94
|
+
for (;;) {
|
|
95
|
+
const newline = buffered.indexOf(newlineByte);
|
|
96
|
+
if (newline === -1) {
|
|
97
|
+
if (droppedBytes + buffered.length > maxNoiseBytes)
|
|
98
|
+
settle(null);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const marker = parseGateMarkerLine(buffered.subarray(0, newline).toString('utf8').replace(/\r$/, ''));
|
|
102
|
+
const rest = buffered.subarray(newline + 1);
|
|
103
|
+
if (marker !== null) {
|
|
104
|
+
settle({ marker, rest });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
droppedBytes += newline + 1;
|
|
108
|
+
buffered = rest;
|
|
109
|
+
if (droppedBytes > maxNoiseBytes) {
|
|
110
|
+
settle(null);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const onEnd = () => settle(null);
|
|
116
|
+
stream.on('data', onData);
|
|
117
|
+
stream.once('end', onEnd);
|
|
118
|
+
stream.once('close', onEnd);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
const publicKeySchema = zod_1.z.string().refine(sshKeys_1.checkIsEd25519PublicKey, 'must be an ed25519 public key (type and key, no comment)');
|
|
122
|
+
/** @description What the runner tells the hub when it redeems a pairing code. */
|
|
123
|
+
exports.redeemRequestSchema = zod_1.z.strictObject({
|
|
124
|
+
/** A name the runner would like (its host name); the hub makes it valid and unique. */
|
|
125
|
+
suggestedName: zod_1.z.string().max(maxTextLength),
|
|
126
|
+
publicKey: publicKeySchema,
|
|
127
|
+
hostKey: publicKeySchema,
|
|
128
|
+
workDir: runnersConfig_1.runnerWorkDirSchema,
|
|
129
|
+
os: zod_1.z.string().max(maxTextLength),
|
|
130
|
+
arch: zod_1.z.string().max(maxTextLength),
|
|
131
|
+
version: zod_1.z.string().max(maxTextLength),
|
|
132
|
+
serviceKind: zod_1.z.enum(hubRegistry_1.runnerServiceKinds),
|
|
133
|
+
});
|
|
134
|
+
exports.redeemReplySchema = zod_1.z.discriminatedUnion('ok', [
|
|
135
|
+
zod_1.z.strictObject({
|
|
136
|
+
ok: zod_1.z.literal(true),
|
|
137
|
+
runnerId: hubIds_1.hubIdSchema,
|
|
138
|
+
name: zod_1.z.string(),
|
|
139
|
+
hubPublicKey: publicKeySchema,
|
|
140
|
+
label: zod_1.z.string(),
|
|
141
|
+
host: zod_1.z.string(),
|
|
142
|
+
port: zod_1.z.number().int(),
|
|
143
|
+
/** The hub's current package (what the runner just downloaded, or something newer); `null` when it cannot be packed. */
|
|
144
|
+
packageId: zod_1.z.string().nullable(),
|
|
145
|
+
}),
|
|
146
|
+
zod_1.z.strictObject({ ok: zod_1.z.literal(false), reason: zod_1.z.string() }),
|
|
147
|
+
]);
|
|
148
|
+
exports.unpairReplySchema = zod_1.z.strictObject({ ok: zod_1.z.boolean() });
|
|
149
|
+
/** `ok`: the code was open and is closed now; `false`: there was nothing to close (spent, expired, or cancelled already). */
|
|
150
|
+
exports.cancelReplySchema = zod_1.z.strictObject({ ok: zod_1.z.boolean() });
|
|
151
|
+
//# sourceMappingURL=gateProtocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateProtocol.js","sourceRoot":"","sources":["../../src/runners/gateProtocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type HubContext } from './hubPaths';
|
|
2
|
+
/** @description The text of the wrapper for `ctx`. */
|
|
3
|
+
export declare function renderGateWrapper(ctx: Pick<HubContext, 'nodePath' | 'cliPath'>): string;
|
|
4
|
+
/** @description Write the wrapper (only when it differs from what is there) and return its path. */
|
|
5
|
+
export declare function ensureGateWrapper(ctx: HubContext): string;
|
|
6
|
+
//# sourceMappingURL=gateWrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateWrapper.d.ts","sourceRoot":"","sources":["../../src/runners/gateWrapper.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAW9D,sDAAsD;AACtD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC,GAAG,MAAM,CAEvF;AAED,oGAAoG;AACpG,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAYzD"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.renderGateWrapper = renderGateWrapper;
|
|
37
|
+
exports.ensureGateWrapper = ensureGateWrapper;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const configDirFile_1 = require("../configDirFile");
|
|
40
|
+
const tmuxExec_1 = require("../utils/tmuxExec");
|
|
41
|
+
const hubLock_1 = require("./hubLock");
|
|
42
|
+
const hubPaths_1 = require("./hubPaths");
|
|
43
|
+
/**
|
|
44
|
+
* @description The `gate` file every runner key's `authorized_keys` line points at: a two-line `sh` wrapper that runs THIS install's
|
|
45
|
+
* `node` on THIS install's `cli.js`. The lines carry its path (not node's or the checkout's), and the file is rewritten at every
|
|
46
|
+
* start, so a Node upgrade, a moved checkout or a switch from npm to a git checkout never leaves a key line pointing at nothing.
|
|
47
|
+
*/
|
|
48
|
+
const wrapperMode = 0o700;
|
|
49
|
+
const permissionBitsMask = 0o777;
|
|
50
|
+
/** @description The text of the wrapper for `ctx`. */
|
|
51
|
+
function renderGateWrapper(ctx) {
|
|
52
|
+
return `#!/bin/sh\nexec ${(0, tmuxExec_1.shellSingleQuote)(ctx.nodePath)} ${(0, tmuxExec_1.shellSingleQuote)(ctx.cliPath)} runner-gate "$@"\n`;
|
|
53
|
+
}
|
|
54
|
+
/** @description Write the wrapper (only when it differs from what is there) and return its path. */
|
|
55
|
+
function ensureGateWrapper(ctx) {
|
|
56
|
+
(0, hubLock_1.ensureHubDir)(ctx.dir);
|
|
57
|
+
const gatePath = (0, hubPaths_1.getHubFilePaths)(ctx.dir).gate;
|
|
58
|
+
const text = renderGateWrapper(ctx);
|
|
59
|
+
let current = null;
|
|
60
|
+
try {
|
|
61
|
+
current = fs.readFileSync(gatePath, 'utf8');
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
current = null;
|
|
65
|
+
}
|
|
66
|
+
if (current !== text || (fs.statSync(gatePath).mode & permissionBitsMask) !== wrapperMode)
|
|
67
|
+
(0, configDirFile_1.writeTextFileAtomically)(gatePath, text, wrapperMode);
|
|
68
|
+
return gatePath;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=gateWrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateWrapper.js","sourceRoot":"","sources":["../../src/runners/gateWrapper.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,8CAEC;AAGD,8CAYC;AAjCD,uCAAyB;AACzB,oDAA2D;AAC3D,gDAAqD;AACrD,uCAAyC;AACzC,yCAA8D;AAE9D;;;;GAIG;AAEH,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAEjC,sDAAsD;AACtD,SAAgB,iBAAiB,CAAC,GAA6C;IAC7E,OAAO,mBAAmB,IAAA,2BAAgB,EAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAA,2BAAgB,EAAC,GAAG,CAAC,OAAO,CAAC,qBAAqB,CAAC;AACjH,CAAC;AAED,oGAAoG;AACpG,SAAgB,iBAAiB,CAAC,GAAe;IAC/C,IAAA,sBAAY,EAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACtB,MAAM,QAAQ,GAAG,IAAA,0BAAe,EAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IAC/C,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IACD,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,GAAG,kBAAkB,CAAC,KAAK,WAAW;QAAE,IAAA,uCAAuB,EAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IAChJ,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface HubAddress {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
}
|
|
5
|
+
export type HubAddressParsing = {
|
|
6
|
+
ok: true;
|
|
7
|
+
address: HubAddress;
|
|
8
|
+
} | {
|
|
9
|
+
ok: false;
|
|
10
|
+
error: string;
|
|
11
|
+
};
|
|
12
|
+
/** @description `host`, `host:port`, `[v6]:port` or a bare IPv6 address, as an address (port 22 when none is given). */
|
|
13
|
+
export declare function parseHubAddress(text: string): HubAddressParsing;
|
|
14
|
+
/** @description The host key to pin out of `ssh-keyscan` output: the most preferred type that is a well-formed key, as `<type> <base64>`. */
|
|
15
|
+
export declare function parseKeyscanOutput(output: string): string | null;
|
|
16
|
+
/** @description Reads the ssh host key an address answers with (`null`: nothing answered). */
|
|
17
|
+
export type HostKeyScanner = (host: string, port: number) => Promise<string | null>;
|
|
18
|
+
/** @description The real scanner: `ssh-keyscan`, bounded. */
|
|
19
|
+
export declare const scanHostKey: HostKeyScanner;
|
|
20
|
+
export type HubAddressCheck = {
|
|
21
|
+
ok: true;
|
|
22
|
+
hostKey: string;
|
|
23
|
+
note: string | null;
|
|
24
|
+
} | {
|
|
25
|
+
ok: false;
|
|
26
|
+
error: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* @description Does `address` answer with an ssh server, and is it this machine's own? Returns the host key to pin. The machine's own
|
|
30
|
+
* sshd is read on its loopback; when that cannot be read the address is accepted with a note that it was not compared.
|
|
31
|
+
*/
|
|
32
|
+
export declare function checkHubAddress(address: HubAddress, scan: HostKeyScanner): Promise<HubAddressCheck>;
|
|
33
|
+
//# sourceMappingURL=hubAddress.d.ts.map
|