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,65 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.osal.sshagent
import freeflowuniverse.herolib.builder
import freeflowuniverse.herolib.ui.console
console.print_header('SSH Agent Management Example')
// Create SSH agent with single instance guarantee
mut agent := sshagent.new_single()!
println('SSH Agent initialized and ensured single instance')
// Show diagnostics
diag := agent.diagnostics()
console.print_header('SSH Agent Diagnostics:')
for key, value in diag {
console.print_item('${key}: ${value}')
}
// Show current agent status
println(agent)
// Example: Generate a test key if no keys exist
if agent.keys.len == 0 {
console.print_header('No keys found, generating example key...')
mut key := agent.generate('example_key', '')!
console.print_debug('Generated key: ${key}')
// Load the generated key
key.load()!
console.print_debug('Key loaded into agent')
}
// Example: Push key to remote node (uncomment and modify for actual use)
/*
console.print_header('Testing remote node key deployment...')
mut b := builder.new()!
// Create connection to remote node
mut node := b.node_new(
ipaddr: 'root@192.168.1.100:22' // Replace with actual remote host
name: 'test_node'
)!
if agent.keys.len > 0 {
key_name := agent.keys[0].name
console.print_debug('Pushing key "${key_name}" to remote node...')
// Push the key
agent.push_key_to_node(mut node, key_name)!
// Verify access
if agent.verify_key_access(mut node, key_name)! {
console.print_debug('✓ SSH key access verified')
} else {
console.print_debug('✗ SSH key access verification failed')
}
// Optional: Remove key from remote (for testing)
// agent.remove_key_from_node(mut node, key_name)!
// console.print_debug('Key removed from remote node')
}
*/
console.print_header('SSH Agent example completed successfully')

View File

@@ -1,51 +0,0 @@
module main
import freeflowuniverse.herolib.osal.sshagent
import freeflowuniverse.herolib.osal.linux
fn do1() ! {
mut agent := sshagent.new()!
println(agent)
k := agent.get(name: 'kds') or { panic('notgound') }
println(k)
mut k2 := agent.get(name: 'books') or { panic('notgound') }
k2.load()!
println(k2.agent)
println(agent)
k2.forget()!
println(k2.agent)
// println(agent)
}
fn test_user_mgmt() ! {
mut lf := linux.new()!
// Test user creation
lf.user_create(
name: 'testuser'
sshkey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM3/2K7R8A/l0kM0/d'
)!
// Test ssh key creation
lf.sshkey_create(
username: 'testuser'
sshkey_name: 'testkey'
)!
// Test ssh key deletion
lf.sshkey_delete(
username: 'testuser'
sshkey_name: 'testkey'
)!
// Test user deletion
lf.user_delete(name: 'testuser')!
}
fn main() {
do1() or { panic(err) }
test_user_mgmt() or { panic(err) }
}

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.osal.sshagent
import freeflowuniverse.herolib.ui.console
fn do_sshagent_example() ! {
console.print_header('SSH Agent Basic Example')
mut agent := sshagent.new()!
console.print_debug('SSH Agent created')
println(agent)
// Generate a test key if no keys exist
if agent.keys.len == 0 {
console.print_debug('No keys found, generating test key...')
mut test_key := agent.generate('test_example_key', '')!
test_key.load()!
console.print_debug('Test key generated and loaded')
}
// Try to get a specific key (this will fail if key doesn't exist)
console.print_debug('Looking for existing keys...')
if agent.keys.len > 0 {
// Work with the first available key
mut first_key := agent.keys[0]
console.print_debug('Found key: ${first_key.name}')
if !first_key.loaded {
console.print_debug('Loading key...')
first_key.load()!
console.print_debug('Key loaded')
}
console.print_debug('Key details:')
println(first_key)
// Show agent status after loading
console.print_debug('Agent status after loading:')
println(agent)
// Note: We don't call forget() in this example to avoid removing keys
// first_key.forget()!
} else {
console.print_debug('No keys available in agent')
}
}
fn main() {
do_sshagent_example() or {
console.print_debug('Error: ${err}')
panic(err)
}
console.print_header('SSH Agent example completed successfully!')
}

View File

@@ -0,0 +1,85 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.osal.sshagent
import freeflowuniverse.herolib.ui.console
console.print_header('SSH Agent Management Example')
// Create SSH agent with single instance guarantee
mut agent := sshagent.new_single()!
println('SSH Agent initialized and ensured single instance')
// Show diagnostics
diag := agent.diagnostics()
console.print_header('SSH Agent Diagnostics:')
for key, value in diag {
console.print_item('${key}: ${value}')
}
// Show current agent status
println(agent)
// Example: Generate a test key if no keys exist
if agent.keys.len == 0 {
console.print_header('No keys found, generating example key...')
mut key := agent.generate('example_key', '')!
console.print_debug('Generated key: ${key}')
// Load the generated key
key.load()!
console.print_debug('Key loaded into agent')
}
// Example: Working with existing keys
if agent.keys.len > 0 {
console.print_header('Working with existing keys...')
for i, key in agent.keys {
console.print_debug('Key ${i+1}: ${key.name}')
console.print_debug(' Type: ${key.cat}')
console.print_debug(' Loaded: ${key.loaded}')
console.print_debug(' Email: ${key.email}')
if !key.loaded {
console.print_debug(' Loading key...')
mut key_mut := key
key_mut.load() or {
console.print_debug(' Failed to load: ${err}')
continue
}
console.print_debug(' Key loaded successfully')
}
}
}
// Example: Add a key from private key content
console.print_header('Example: Adding a key from content...')
console.print_debug('Note: This would normally use real private key content')
console.print_debug('For security, we skip this in the example')
// Example: Generate and manage a new key
console.print_header('Example: Generate a new test key...')
test_key_name := 'test_key_example'
// Check if test key already exists
existing_key := agent.get(name: test_key_name) or {
console.print_debug('Test key does not exist, generating...')
// Generate new key
mut new_key := agent.generate(test_key_name, '')!
console.print_debug(' Generated new key: ${new_key.name}')
// Load it
new_key.load()!
console.print_debug(' Key loaded into agent')
new_key
}
console.print_debug('Test key exists: ${existing_key.name}')
// Show final agent status
console.print_header('Final SSH Agent Status:')
println(agent)
console.print_header('SSH Agent example completed successfully')

View File

@@ -1,6 +1,5 @@
module gittools
import freeflowuniverse.herolib.osal.sshagent
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.develop.vscode
@@ -106,7 +105,9 @@ fn (self GitRepo) get_repo_url_for_clone() !string {
// return url
// }
if sshagent.loaded() {
// Check if SSH agent is loaded (avoid importing sshagent to prevent circular dependency)
ssh_check := os.execute('ssh-add -l')
if ssh_check.exit_code == 0 {
return self.get_ssh_url()!
} else {
return self.get_http_url()!

View File

@@ -1,5 +1,7 @@
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')
@@ -62,11 +64,11 @@ fn sshkey_delete(mut agent SSHAgent, name string) ! {
}
// 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
}
@@ -96,9 +98,7 @@ fn sshkey_delete(mut agent SSHAgent, name string) ! {
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')
@@ -113,16 +113,12 @@ fn sshkey_load(mut agent SSHAgent, name string) ! {
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}"')
}
mut key_path := key.keypath() or { return error('Private key file not found for "${name}"') }
key_pub_path := key.keypath_pub() or {
mut key_pub_path := key.keypath_pub() or {
return error('Public key file not found for "${name}"')
}
@@ -152,60 +148,5 @@ fn sshkey_check(mut agent SSHAgent, name string) ! {
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

@@ -92,9 +92,63 @@ pub fn (mut agent SSHAgent) verify_key_access(mut node builder.Node, key_name st
}
// 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.') {