.
Some checks failed
Dropshell Test / Build_and_Test (push) Failing after 18s

This commit is contained in:
Your Name 2025-05-10 20:06:05 +12:00
parent 330bdf9941
commit 4d6702b099
4 changed files with 8 additions and 462 deletions

View File

@ -32,7 +32,8 @@ bool execute_local_command_interactive(const sCommand &command, bool silent)
return false;
} else if (pid == 0) {
// Child process
std::vector<const char *> commandvec = {"bash", "-c", full_command.c_str(),NULL};
ASSERT(full_command.find("'") == std::string::npos, "Raw command must not contain single quotes");
std::vector<const char *> commandvec = {"bash", "-c", halfquote(full_command).c_str(),NULL};
if (!silent) {
std::cout << "Executing command: ";
@ -121,28 +122,17 @@ bool execute_ssh_command(const sSSHInfo &ssh_info, const sCommand &command, cMod
ssh_cmd << "ssh -p " << ssh_info.port << " " << (hasFlag(mode, cMode::Interactive) ? "-tt " : "")
<< ssh_info.user << "@" << ssh_info.host;
std::string cmdstr;
if (!is_raw(mode))
cmdstr = quote("bash -c " + command.construct_cmd(cStyle::Safe));
else
{
std::string raw_cmd = command.construct_cmd(cStyle::Raw);
ASSERT(raw_cmd.find("'") == std::string::npos, "Raw command must not contain single quotes");
cmdstr = "bash -c "+ halfquote(raw_cmd);
}
std::string cmdstr = command.construct_cmd(is_raw(mode) ? cStyle::Raw : cStyle::Safe);
ASSERT(cmdstr.find("'") == std::string::npos, "Raw command must not contain single quotes");
cmdstr = "bash -c " + halfquote(cmdstr);
sCommand ssh_command(ssh_cmd.str() + " " + cmdstr);
bool rval = execute_local_command(ssh_command, mode, output);
if (!rval) {
std::cerr <<std::endl<<std::endl;
std::cerr << "Error: Failed to execute ssh command: { [" << ssh_command.get_directory_to_run_in() << "], [";
std::cerr << ssh_command.get_command_to_run() << "], [";
for (const auto& env_var : ssh_command.get_env_vars()) {
std::cerr << env_var.first << "=" << env_var.second << ", ";
}
std::cerr << "] }" << std::endl;
std::cerr << "Error: Failed to execute ssh command:" << std::endl;
std::cerr << "\033[90m" << ssh_command.get_command_to_run() << "\033[0m" << std::endl;
std::cerr <<std::endl<<std::endl;
}
return rval;

View File

@ -1,363 +0,0 @@
#include "runner.hpp"
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <libssh/libssh.h>
#include <libssh/callbacks.h>
#include <termios.h>
#include <sys/select.h>
#include <algorithm>
#include <cctype>
namespace runner {
namespace {
// String trimming functions
void ltrim(std::string& s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
void rtrim(std::string& s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
void trim(std::string& s) {
ltrim(s);
rtrim(s);
}
// Safe version that handles nullptr
void trim(std::string* s) {
if (s) {
trim(*s);
}
}
ssh_session ssh_connect_and_auth(const sSSHInfo* sshinfo, const std::map<std::string, std::string>& env, std::string* error) {
ssh_session session = ssh_new();
if (!session) {
if (error) *error = "Failed to create SSH session.";
return nullptr;
}
ssh_options_set(session, SSH_OPTIONS_HOST, sshinfo->host.c_str());
if (!sshinfo->port.empty()) {
int port = std::stoi(sshinfo->port);
ssh_options_set(session, SSH_OPTIONS_PORT, &port);
}
if (!sshinfo->user.empty()) {
ssh_options_set(session, SSH_OPTIONS_USER, sshinfo->user.c_str());
}
int rc = ssh_connect(session);
if (rc != SSH_OK) {
if (error) *error = std::string("SSH connection failed: ") + ssh_get_error(session);
ssh_free(session);
return nullptr;
}
rc = ssh_userauth_publickey_auto(session, nullptr, nullptr);
if (rc != SSH_AUTH_SUCCESS) {
auto it = env.find("SSHPASS");
if (it != env.end()) {
rc = ssh_userauth_password(session, nullptr, it->second.c_str());
}
}
if (rc != SSH_AUTH_SUCCESS) {
if (error) *error = std::string("SSH authentication failed: ") + ssh_get_error(session);
ssh_disconnect(session);
ssh_free(session);
return nullptr;
}
return session;
}
} // namespace runner
// runner_local: non-interactive local command execution
bool runner_local::execute() {
pid_t pid = fork();
if (pid == -1) {
std::cerr << "Failed to fork" << std::endl;
mReturnCode = -1;
return false;
}
if (pid == 0) {
// Child process
if (!mWorkingDir.empty()) {
if (chdir(mWorkingDir.c_str()) != 0) {
perror("chdir");
exit(127);
}
}
// Set environment variables
for (const auto& [k, v] : mEnv) {
setenv(k.c_str(), v.c_str(), 1);
}
// Build argv
std::vector<char*> argv;
argv.push_back(const_cast<char*>(mCommand.c_str()));
for (auto& arg : mArgs) argv.push_back(const_cast<char*>(arg.c_str()));
argv.push_back(nullptr);
if (mSilent) {
int fd = open("/dev/null", O_WRONLY);
if (fd != -1) {
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
}
}
std::cout << "Executing command: " << mCommand << std::endl;
std::cout << "Args: ";
for (auto& arg : mArgs) std::cout << "[" << arg << "] ";
std::cout << std::endl;
execvp(mCommand.c_str(), argv.data());
perror("execvp");
exit(127);
} else {
int status = 0;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
mReturnCode = WEXITSTATUS(status);
} else {
mReturnCode = -1;
}
return mReturnCode == 0;
}
}
// runner_local_interactive: interactive local command execution
bool runner_local_interactive::execute() {
pid_t pid = fork();
if (pid == -1) {
std::cerr << "Failed to fork" << std::endl;
mReturnCode = -1;
return false;
}
if (pid == 0) {
if (!mWorkingDir.empty()) {
if (chdir(mWorkingDir.c_str()) != 0) {
perror("chdir");
exit(127);
}
}
for (const auto& [k, v] : mEnv) {
setenv(k.c_str(), v.c_str(), 1);
}
std::vector<char*> argv;
argv.push_back(const_cast<char*>(mCommand.c_str()));
for (auto& arg : mArgs) argv.push_back(const_cast<char*>(arg.c_str()));
argv.push_back(nullptr);
// Attach to terminal (no redirection)
execvp(mCommand.c_str(), argv.data());
perror("execvp");
exit(127);
} else {
int status = 0;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
mReturnCode = WEXITSTATUS(status);
} else {
mReturnCode = -1;
}
return mReturnCode == 0;
}
}
// runner_ssh: non-interactive SSH command execution
bool runner_ssh::execute() {
std::string error;
ssh_session session = ssh_connect_and_auth(&mSSHInfo, mEnv, &error);
if (!session) {
std::cerr << error << std::endl;
mReturnCode = -1;
return false;
}
ssh_channel channel = ssh_channel_new(session);
if (!channel) {
std::cerr << "Failed to create SSH channel." << std::endl;
ssh_disconnect(session);
ssh_free(session);
mReturnCode = -1;
return false;
}
if (ssh_channel_open_session(channel) != SSH_OK) {
std::cerr << "Failed to open SSH channel: " << ssh_get_error(session) << std::endl;
ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session);
mReturnCode = -1;
return false;
}
std::stringstream cmd;
cmd << mCommand;
for (const auto& arg : mArgs) {
cmd << " '" << arg << "'";
}
int rc = ssh_channel_request_exec(channel, cmd.str().c_str());
if (rc != SSH_OK) {
std::cerr << "SSH exec failed: " << ssh_get_error(session) << std::endl;
ssh_channel_close(channel);
ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session);
mReturnCode = -1;
return false;
}
char buffer[256];
int nbytes;
while ((nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
if (!mSilent) std::cout.write(buffer, nbytes);
}
mReturnCode = ssh_channel_get_exit_status(channel);
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session);
return mReturnCode == 0;
}
// runner_ssh_interactive: interactive SSH command execution
bool runner_ssh_interactive::execute() {
std::string error;
ssh_session session = ssh_connect_and_auth(&mSSHInfo, mEnv, &error);
if (!session) {
std::cerr << error << std::endl;
mReturnCode = -1;
return false;
}
ssh_channel channel = ssh_channel_new(session);
if (!channel) {
std::cerr << "Failed to create SSH channel." << std::endl;
ssh_disconnect(session);
ssh_free(session);
mReturnCode = -1;
return false;
}
if (ssh_channel_open_session(channel) != SSH_OK) {
std::cerr << "Failed to open SSH channel: " << ssh_get_error(session) << std::endl;
ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session);
mReturnCode = -1;
return false;
}
std::stringstream cmd;
cmd << mCommand;
for (const auto& arg : mArgs) {
cmd << " '" << arg << "'";
}
int rc = ssh_channel_request_pty(channel);
if (rc != SSH_OK) {
std::cerr << "Failed to request PTY: " << ssh_get_error(session) << std::endl;
ssh_channel_close(channel);
ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session);
mReturnCode = -1;
return false;
}
rc = ssh_channel_request_shell(channel);
if (rc != SSH_OK) {
std::cerr << "Failed to request shell: " << ssh_get_error(session) << std::endl;
ssh_channel_close(channel);
ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session);
mReturnCode = -1;
return false;
}
// Forward input/output between user and SSH channel
fd_set fds;
char buffer[256];
while (true) {
FD_ZERO(&fds);
FD_SET(0, &fds); // stdin
int ssh_fd = ssh_get_fd(session);
FD_SET(ssh_fd, &fds);
int maxfd = std::max(0, ssh_fd) + 1;
int ret = select(maxfd, &fds, nullptr, nullptr, nullptr);
if (ret < 0) break;
if (FD_ISSET(0, &fds)) {
int n = read(0, buffer, sizeof(buffer));
if (n > 0) ssh_channel_write(channel, buffer, n);
}
if (FD_ISSET(ssh_fd, &fds)) {
int n = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
if (n > 0) write(1, buffer, n);
else if (n == 0) break;
}
if (ssh_channel_is_closed(channel)) break;
}
mReturnCode = ssh_channel_get_exit_status(channel);
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session);
return mReturnCode == 0;
}
// runner_ssh_capture: SSH command execution with output capture
bool runner_ssh_capture::execute() {
std::string error;
ssh_session session = ssh_connect_and_auth(&mSSHInfo, mEnv, &error);
if (!session) {
std::cerr << error << std::endl;
mReturnCode = -1;
return false;
}
ssh_channel channel = ssh_channel_new(session);
if (!channel) {
std::cerr << "Failed to create SSH channel." << std::endl;
ssh_disconnect(session);
ssh_free(session);
mReturnCode = -1;
return false;
}
if (ssh_channel_open_session(channel) != SSH_OK) {
std::cerr << "Failed to open SSH channel: " << ssh_get_error(session) << std::endl;
ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session);
mReturnCode = -1;
return false;
}
std::stringstream cmd;
cmd << mCommand;
for (const auto& arg : mArgs) {
cmd << " '" << arg << "'";
}
int rc = ssh_channel_request_exec(channel, cmd.str().c_str());
if (rc != SSH_OK) {
std::cerr << "SSH exec failed: " << ssh_get_error(session) << std::endl;
ssh_channel_close(channel);
ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session);
mReturnCode = -1;
return false;
}
char buffer[256];
int nbytes;
mOutput.clear();
while ((nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
mOutput.append(buffer, nbytes);
}
mReturnCode = ssh_channel_get_exit_status(channel);
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session);
return mReturnCode == 0;
}
} // namespace runner

View File

@ -1,81 +0,0 @@
#ifndef RUNNER_HPP
#define RUNNER_HPP
#include <string>
#include <vector>
#include <map>
namespace runner {
struct sSSHInfo {
std::string host;
std::string user;
std::string port;
};
class runner {
public:
runner(std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}, bool silent=false) :
mCommand(command),
mArgs(args),
mWorkingDir(working_dir),
mEnv(env),
mSilent(silent),
mReturnCode(0) {}
virtual ~runner() {}
virtual bool execute() = 0;
int return_code() const { return mReturnCode; }
protected:
std::string mCommand;
std::vector<std::string> mArgs;
std::string mWorkingDir;
std::map<std::string, std::string> mEnv;
bool mSilent;
int mReturnCode;
};
class runner_local : public runner {
public:
runner_local(std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}, bool silent=false) :
runner(command, args, working_dir, env, silent) {}
bool execute() override;
};
class runner_local_interactive : public runner {
public:
runner_local_interactive(std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}) :
runner(command, args, working_dir, env, false) {}
bool execute() override;
};
class runner_ssh : public runner {
public:
runner_ssh(const sSSHInfo sshinfo, std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}, bool silent=false) :
runner(command, args, working_dir, env, silent), mSSHInfo(sshinfo) {}
bool execute() override;
protected:
const sSSHInfo mSSHInfo;
};
class runner_ssh_interactive : public runner_ssh {
public:
runner_ssh_interactive(const sSSHInfo sshinfo, std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}, bool silent=true) :
runner_ssh(sshinfo, command, args, working_dir, env, silent) {}
bool execute() override;
};
class runner_ssh_capture : public runner_ssh {
public:
runner_ssh_capture(const sSSHInfo sshinfo, std::string output, std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}) :
runner_ssh(sshinfo, command, args, working_dir, env, true), mOutput(output) {}
bool execute() override;
protected:
std::string & mOutput;
};
} // namespace runner
#endif // RUNNER_HPP

View File

@ -1,6 +1,6 @@
#!/bin/bash
source "${AGENT_PATH}/_common.sh"
_check_required_env_vars
_check_required_env_vars "CONFIG_PATH"
# PORT SCRIPT
# The port script is OPTIONAL.