sync: Multi-project updates - SolverBot, GuruRMM, Dataforth
SolverBot: - Inject active project path into agent system prompts so agents know which directory to scope file operations to GuruRMM: - Bump agent version to 0.6.0 - Add serde aliases for PowerShell/ClaudeTask command types - Add typed CommandType enum on server for proper serialization - Support claude_task command type in send_command API Dataforth: - Fix SCP space-escaping in Sync-FromNAS.ps1 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
88
projects/msp-tools/guru-rmm/deploy_via_textchunks.py
Normal file
88
projects/msp-tools/guru-rmm/deploy_via_textchunks.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""Deploy agent binary to AD2 by writing base64 text chunks to a file, then decoding."""
|
||||
import requests, json, time, sys, base64
|
||||
|
||||
# Read and encode the binary
|
||||
with open("agent/target/release/gururmm-agent.exe", "rb") as f:
|
||||
binary = f.read()
|
||||
b64 = base64.b64encode(binary).decode('ascii')
|
||||
print(f"Binary: {len(binary)} bytes, Base64: {len(b64)} chars")
|
||||
|
||||
# Auth
|
||||
token_r = requests.post('http://172.16.3.30:3001/api/auth/login', json={
|
||||
'email': 'claude-api@azcomputerguru.com',
|
||||
'password': 'ClaudeAPI2026!@#'
|
||||
})
|
||||
token = token_r.json()['token']
|
||||
headers = {'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json'}
|
||||
agent_id = 'd28a1c90-47d7-448f-a287-197bc8892234'
|
||||
|
||||
def send_cmd(cmd, timeout=60, wait=10):
|
||||
r = requests.post(
|
||||
'http://172.16.3.30:3001/api/agents/' + agent_id + '/command',
|
||||
headers=headers,
|
||||
json={'command_type': 'powershell', 'command': cmd, 'timeout_seconds': timeout}
|
||||
)
|
||||
data = r.json()
|
||||
cmd_id = data['command_id']
|
||||
time.sleep(wait)
|
||||
# Poll until complete
|
||||
for attempt in range(10):
|
||||
r2 = requests.get('http://172.16.3.30:3001/api/commands/' + cmd_id, headers=headers)
|
||||
d = r2.json()
|
||||
if d['status'] != 'running':
|
||||
return d
|
||||
time.sleep(5)
|
||||
return d
|
||||
|
||||
# Step 1: Delete old file and create fresh one
|
||||
print("Step 1: Preparing temp file...")
|
||||
d = send_cmd("Remove-Item C:/Temp/agent.b64 -Force -ErrorAction SilentlyContinue; "
|
||||
"New-Item -ItemType Directory -Path C:/Temp -Force | Out-Null; "
|
||||
"'' | Set-Content C:/Temp/agent.b64 -NoNewline; "
|
||||
"Write-Output 'Ready'", wait=8)
|
||||
print(f" {d['status']}: {d.get('stdout','').strip()}")
|
||||
if d['status'] != 'completed':
|
||||
print(f" ERROR: {(d.get('stderr','') or '')[:300]}")
|
||||
sys.exit(1)
|
||||
|
||||
# Step 2: Write base64 text in chunks
|
||||
# Windows command line limit is ~32KB, keep chunks under 20KB to be safe
|
||||
chunk_size = 20000
|
||||
chunks = [b64[i:i+chunk_size] for i in range(0, len(b64), chunk_size)]
|
||||
print(f"Step 2: Writing {len(chunks)} chunks of ~{chunk_size} chars each...")
|
||||
|
||||
for i, chunk in enumerate(chunks):
|
||||
# Use Add-Content to append text (no base64 decode here, just text)
|
||||
# Escape single quotes in base64 (shouldn't have any, but just in case)
|
||||
safe_chunk = chunk.replace("'", "''")
|
||||
cmd = f"Add-Content -Path C:/Temp/agent.b64 -Value '{safe_chunk}' -NoNewline; Write-Output 'chunk{i+1}ok'"
|
||||
d = send_cmd(cmd, wait=5)
|
||||
status = d['status']
|
||||
stdout = d.get('stdout', '').strip()
|
||||
if status != 'completed' or f'chunk{i+1}ok' not in stdout:
|
||||
print(f" Chunk {i+1}/{len(chunks)} FAILED: {status} - {stdout}")
|
||||
print(f" stderr: {(d.get('stderr','') or '')[:300]}")
|
||||
sys.exit(1)
|
||||
if (i+1) % 10 == 0 or i == 0 or i == len(chunks)-1:
|
||||
print(f" Chunk {i+1}/{len(chunks)}: OK")
|
||||
|
||||
# Step 3: Verify base64 file size
|
||||
print("Step 3: Verifying base64 file...")
|
||||
d = send_cmd(f"$f = Get-Item C:/Temp/agent.b64; Write-Output $f.Length", wait=5)
|
||||
remote_size = d.get('stdout', '').strip()
|
||||
print(f" Remote b64 size: {remote_size} (expected: {len(b64)})")
|
||||
|
||||
# Step 4: Decode base64 file to binary
|
||||
print("Step 4: Decoding base64 to binary...")
|
||||
cmd = ("$b64 = Get-Content C:/Temp/agent.b64 -Raw; "
|
||||
"$bytes = [Convert]::FromBase64String($b64); "
|
||||
"[System.IO.File]::WriteAllBytes('C:/Temp/gururmm-agent-new.exe', $bytes); "
|
||||
"$f = Get-Item C:/Temp/gururmm-agent-new.exe; "
|
||||
"Write-Output ('Decoded: ' + $f.Length.ToString() + ' bytes')")
|
||||
d = send_cmd(cmd, timeout=120, wait=15)
|
||||
print(f" {d['status']}: {d.get('stdout','').strip()}")
|
||||
if d.get('stderr'):
|
||||
print(f" stderr: {(d.get('stderr','') or '')[:300]}")
|
||||
|
||||
print(f"\nExpected binary size: {len(binary)} bytes")
|
||||
print("Done!")
|
||||
Reference in New Issue
Block a user