refactor: update SSH agent examples and module structure

- Refactor `gittools` to remove `sshagent` import
- Update `sshagent.loaded()` to use `ssh-add -l` command
- Relocate and expose `remote_copy` and `remote_auth` functions
- Improve SSH agent examples and remove Linux tests
- Optimize `sshagent` module and `play` function imports
This commit is contained in:
Mahmoud-Emad
2025-08-24 23:54:57 +03:00
parent 9945cfb52c
commit a37dbd2438
9 changed files with 263 additions and 245 deletions

View File

@@ -1,29 +1,31 @@
module sshagent
import freeflowuniverse.herolib.ui.console
// Check if SSH agent is properly configured and all is good
fn agent_check(mut agent SSHAgent) ! {
console.print_header('SSH Agent Check')
// Ensure single agent is running
agent.ensure_single_agent()!
// Get diagnostics
diag := agent.diagnostics()
for key, value in diag {
console.print_item('${key}: ${value}')
}
// Verify agent is responsive
if !agent.is_agent_responsive() {
return error('SSH agent is not responsive')
}
// Load all existing keys from ~/.ssh that aren't loaded yet
agent.init()!
console.print_green(' SSH Agent is properly configured and running')
// Show loaded keys
loaded_keys := agent.keys_loaded()!
console.print_item('Loaded keys: ${loaded_keys.len}')
@@ -35,17 +37,17 @@ fn agent_check(mut agent SSHAgent) ! {
// Create a new SSH key
fn sshkey_create(mut agent SSHAgent, name string, passphrase string) ! {
console.print_header('Creating SSH key: ${name}')
// Check if key already exists
if agent.exists(name: name) {
console.print_debug('SSH key "${name}" already exists')
return
}
// Generate new key
mut key := agent.generate(name, passphrase)!
console.print_green(' SSH key "${name}" created successfully')
// Automatically load the key
key.load()!
console.print_green(' SSH key "${name}" loaded into agent')
@@ -54,28 +56,28 @@ fn sshkey_create(mut agent SSHAgent, name string, passphrase string) ! {
// Delete an SSH key
fn sshkey_delete(mut agent SSHAgent, name string) ! {
console.print_header('Deleting SSH key: ${name}')
// Check if key exists
mut key := agent.get(name: name) or {
console.print_debug('SSH key "${name}" does not exist')
return
}
// Get key paths before deletion
key_path := key.keypath() or {
mut key_path := key.keypath() or {
console.print_debug('Private key path not available for "${name}"')
key.keypath_pub() or { return } // Just to trigger the path lookup
}
key_pub_path := key.keypath_pub() or {
mut key_pub_path := key.keypath_pub() or {
console.print_debug('Public key path not available for "${name}"')
return
}
// Remove from agent if loaded (temporarily disabled due to reset_ssh panic)
// if key.loaded {
// key.forget()!
// }
// Delete key files
if key_path.exists() {
key_path.delete()!
@@ -85,26 +87,24 @@ fn sshkey_delete(mut agent SSHAgent, name string) ! {
key_pub_path.delete()!
console.print_debug('Deleted public key: ${key_pub_path.path}')
}
// Reinitialize agent to update key list
agent.init()!
console.print_green(' SSH key "${name}" deleted successfully')
}
// Load SSH key into agent
fn sshkey_load(mut agent SSHAgent, name string) ! {
console.print_header('Loading SSH key: ${name}')
mut key := agent.get(name: name) or {
return error('SSH key "${name}" not found')
}
mut key := agent.get(name: name) or { return error('SSH key "${name}" not found') }
if key.loaded {
console.print_debug('SSH key "${name}" is already loaded')
return
}
key.load()!
console.print_green(' SSH key "${name}" loaded into agent')
}
@@ -112,28 +112,24 @@ fn sshkey_load(mut agent SSHAgent, name string) ! {
// Check if SSH key is valid
fn sshkey_check(mut agent SSHAgent, name string) ! {
console.print_header('Checking SSH key: ${name}')
mut key := agent.get(name: name) or {
return error('SSH key "${name}" not found')
}
mut key := agent.get(name: name) or { return error('SSH key "${name}" not found') }
// Check if key files exist
key_path := key.keypath() or {
return error('Private key file not found for "${name}"')
}
key_pub_path := key.keypath_pub() or {
mut key_path := key.keypath() or { return error('Private key file not found for "${name}"') }
mut key_pub_path := key.keypath_pub() or {
return error('Public key file not found for "${name}"')
}
if !key_path.exists() {
return error('Private key file does not exist: ${key_path.path}')
}
if !key_pub_path.exists() {
return error('Public key file does not exist: ${key_pub_path.path}')
}
// Verify key can be loaded (if not already loaded)
if !key.loaded {
// Test load without actually loading (since forget is disabled)
@@ -142,70 +138,15 @@ fn sshkey_check(mut agent SSHAgent, name string) ! {
return error('Invalid private key format in "${name}"')
}
}
console.print_item('Key type: ${key.cat}')
console.print_item('Loaded: ${key.loaded}')
console.print_item('Email: ${key.email}')
console.print_item('Private key: ${key_path.path}')
console.print_item('Public key: ${key_pub_path.path}')
console.print_green(' SSH key "${name}" is valid')
}
// Copy private key to remote node
fn remote_copy(mut agent SSHAgent, node_addr string, key_name string) ! {
console.print_header('Copying SSH key "${key_name}" to ${node_addr}')
// Get the key
mut key := agent.get(name: key_name) or {
return error('SSH key "${key_name}" not found')
}
// Create builder node
mut b := builder.new()!
mut node := b.node_new(ipaddr: node_addr)!
// Get private key content
key_path := key.keypath()!
if !key_path.exists() {
return error('Private key file not found: ${key_path.path}')
}
private_key_content := key_path.read()!
// Get home directory on remote
home_dir := node.environ_get()!['HOME'] or {
return error('Could not determine HOME directory on remote node')
}
remote_ssh_dir := '${home_dir}/.ssh'
remote_key_path := '${remote_ssh_dir}/${key_name}'
// Ensure .ssh directory exists with correct permissions
node.exec_silent('mkdir -p ${remote_ssh_dir}')!
node.exec_silent('chmod 700 ${remote_ssh_dir}')!
// Copy private key to remote
node.file_write(remote_key_path, private_key_content)!
node.exec_silent('chmod 600 ${remote_key_path}')!
// Generate public key on remote
node.exec_silent('ssh-keygen -y -f ${remote_key_path} > ${remote_key_path}.pub')!
node.exec_silent('chmod 644 ${remote_key_path}.pub')!
console.print_green(' SSH key "${key_name}" copied to ${node_addr}')
}
// Add public key to authorized_keys on remote node
fn remote_auth(mut agent SSHAgent, node_addr string, key_name string) ! {
console.print_header('Adding SSH key "${key_name}" to authorized_keys on ${node_addr}')
// Create builder node
mut b := builder.new()!
mut node := b.node_new(ipaddr: node_addr)!
// Use existing builder integration
agent.push_key_to_node(mut node, key_name)!
console.print_green(' SSH key "${key_name}" added to authorized_keys on ${node_addr}')
}
// Note: remote_copy and remote_auth functions moved to builder_integration.v
// to avoid circular dependencies

View File

@@ -10,27 +10,27 @@ pub fn (mut agent SSHAgent) push_key_to_node(mut node builder.Node, key_name str
if node_info['category'] != 'ssh' {
return error('Can only push keys to SSH nodes, got: ${node_info['category']}')
}
// Find the key
mut key := agent.get(name: key_name) or {
return error('SSH key "${key_name}" not found in agent')
}
// Get public key content
pubkey_content := key.keypub()!
// Check if authorized_keys file exists on remote
home_dir := node.environ_get()!['HOME'] or {
return error('Could not determine HOME directory on remote node')
}
ssh_dir := '${home_dir}/.ssh'
authorized_keys_path := '${ssh_dir}/authorized_keys'
// Ensure .ssh directory exists with correct permissions
node.exec_silent('mkdir -p ${ssh_dir}')!
node.exec_silent('chmod 700 ${ssh_dir}')!
// Check if key already exists
if node.file_exists(authorized_keys_path) {
existing_keys := node.file_read(authorized_keys_path)!
@@ -39,11 +39,11 @@ pub fn (mut agent SSHAgent) push_key_to_node(mut node builder.Node, key_name str
return
}
}
// Add key to authorized_keys
node.exec_silent('echo "${pubkey_content}" >> ${authorized_keys_path}')!
node.exec_silent('chmod 600 ${authorized_keys_path}')!
console.print_debug('SSH key "${key_name}" successfully pushed to node')
}
@@ -54,31 +54,31 @@ pub fn (mut agent SSHAgent) remove_key_from_node(mut node builder.Node, key_name
if node_info['category'] != 'ssh' {
return error('Can only remove keys from SSH nodes, got: ${node_info['category']}')
}
// Find the key
mut key := agent.get(name: key_name) or {
return error('SSH key "${key_name}" not found in agent')
}
// Get public key content
pubkey_content := key.keypub()!
// Get authorized_keys path
home_dir := node.environ_get()!['HOME'] or {
return error('Could not determine HOME directory on remote node')
}
authorized_keys_path := '${home_dir}/.ssh/authorized_keys'
if !node.file_exists(authorized_keys_path) {
console.print_debug('authorized_keys file does not exist on remote node')
return
}
// Remove the key line from authorized_keys
escaped_key := pubkey_content.replace('/', '\\/')
node.exec_silent('sed -i "\\|${escaped_key}|d" ${authorized_keys_path}')!
console.print_debug('SSH key "${key_name}" removed from remote node')
}
@@ -90,11 +90,65 @@ pub fn (mut agent SSHAgent) verify_key_access(mut node builder.Node, key_name st
if node_info['category'] != 'ssh' {
return error('Can only verify access to SSH nodes')
}
// Test basic connectivity
result := node.exec_silent('echo "SSH key verification successful"') or {
return false
}
result := node.exec_silent('echo "SSH key verification successful"') or { return false }
return result.contains('SSH key verification successful')
}
}
// Copy private key to remote node
pub fn remote_copy(mut agent SSHAgent, node_addr string, key_name string) ! {
console.print_header('Copying SSH key "${key_name}" to ${node_addr}')
// Get the key
mut key := agent.get(name: key_name) or { return error('SSH key "${key_name}" not found') }
// Create builder node
mut b := builder.new()!
mut node := b.node_new(ipaddr: node_addr)!
// Get private key content
mut key_path := key.keypath()!
if !key_path.exists() {
return error('Private key file not found: ${key_path.path}')
}
private_key_content := key_path.read()!
// Get home directory on remote
home_dir := node.environ_get()!['HOME'] or {
return error('Could not determine HOME directory on remote node')
}
remote_ssh_dir := '${home_dir}/.ssh'
remote_key_path := '${remote_ssh_dir}/${key_name}'
// Ensure .ssh directory exists with correct permissions
node.exec_silent('mkdir -p ${remote_ssh_dir}')!
node.exec_silent('chmod 700 ${remote_ssh_dir}')!
// Copy private key to remote
node.file_write(remote_key_path, private_key_content)!
node.exec_silent('chmod 600 ${remote_key_path}')!
// Generate public key on remote
node.exec_silent('ssh-keygen -y -f ${remote_key_path} > ${remote_key_path}.pub')!
node.exec_silent('chmod 644 ${remote_key_path}.pub')!
console.print_green(' SSH key "${key_name}" copied to ${node_addr}')
}
// Add public key to authorized_keys on remote node
pub fn remote_auth(mut agent SSHAgent, node_addr string, key_name string) ! {
console.print_header('Adding SSH key "${key_name}" to authorized_keys on ${node_addr}')
// Create builder node
mut b := builder.new()!
mut node := b.node_new(ipaddr: node_addr)!
// Use existing builder integration
agent.push_key_to_node(mut node, key_name)!
console.print_green(' SSH key "${key_name}" added to authorized_keys on ${node_addr}')
}

View File

@@ -27,8 +27,8 @@ pub fn new(args_ SSHAgentNewArgs) !SSHAgent {
}
pub fn loaded() bool {
mut agent := new() or { panic(err) }
return agent.active
res := os.execute('ssh-add -l')
return res.exit_code == 0
}
// create new SSH agent with single instance guarantee

View File

@@ -1,8 +1,6 @@
module sshagent
import freeflowuniverse.herolib.core.playbook { PlayBook }
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.builder
pub fn play(mut plbook PlayBook) ! {
if !plbook.exists(filter: 'sshagent.') {
@@ -25,7 +23,7 @@ pub fn play(mut plbook PlayBook) ! {
mut p := action.params
name := p.get('name')!
passphrase := p.get_default('passphrase', '')!
sshkey_create(mut agent, name, passphrase)!
action.done = true
}
@@ -35,7 +33,7 @@ pub fn play(mut plbook PlayBook) ! {
for mut action in delete_actions {
mut p := action.params
name := p.get('name')!
sshkey_delete(mut agent, name)!
action.done = true
}
@@ -45,7 +43,7 @@ pub fn play(mut plbook PlayBook) ! {
for mut action in load_actions {
mut p := action.params
name := p.get('name')!
sshkey_load(mut agent, name)!
action.done = true
}
@@ -55,7 +53,7 @@ pub fn play(mut plbook PlayBook) ! {
for mut action in check_key_actions {
mut p := action.params
name := p.get('name')!
sshkey_check(mut agent, name)!
action.done = true
}
@@ -66,7 +64,7 @@ pub fn play(mut plbook PlayBook) ! {
mut p := action.params
node_addr := p.get('node')!
key_name := p.get('name')!
remote_copy(mut agent, node_addr, key_name)!
action.done = true
}
@@ -77,7 +75,7 @@ pub fn play(mut plbook PlayBook) ! {
mut p := action.params
node_addr := p.get('node')!
key_name := p.get('name')!
remote_auth(mut agent, node_addr, key_name)!
action.done = true
}