Commit a3a00221 authored by Lisa's avatar Lisa

fix: sync approval flow in gateway and rebuild node-agent bundle

parent dc1a4f86
......@@ -25,11 +25,11 @@ mkdir -p "$PACKAGE_DIR"
echo "Copying files to $PACKAGE_DIR..."
# Copy core files from the package source of truth
cp package-hermes-node-agent/hermes_node_agent.py "$PACKAGE_DIR/hermes_node_agent.py"
# Copy core files from repo-root source of truth
cp hermes_node_agent.py "$PACKAGE_DIR/hermes_node_agent.py"
cp browser_controller.py "$PACKAGE_DIR/"
cp requirements.txt "$PACKAGE_DIR/"
cp package-hermes-node-agent/install.sh "$PACKAGE_DIR/install.sh"
cp install.sh "$PACKAGE_DIR/install.sh"
cp hermes-node-agent.init.d "$PACKAGE_DIR/"
cp hermes-node-agent.service "$PACKAGE_DIR/"
......@@ -51,7 +51,7 @@ python3 <<'PY'
import base64, pathlib, re
src = pathlib.Path('dist/hermes-node-agent-linux.tar.gz').read_bytes()
b64 = base64.b64encode(src).decode('ascii')
installer_path = pathlib.Path('package-hermes-node-agent/deploy/install-node.sh')
installer_path = pathlib.Path('deploy/linux/install-node.sh')
text = installer_path.read_text()
pattern = r"(cat <<'TARBALL_DATA' \| base64 -d \| tar xzf -\n)(.*?)(\nTARBALL_DATA)"
new_text, count = re.subn(pattern, lambda m: m.group(1) + b64 + m.group(3), text, flags=re.S)
......@@ -61,9 +61,6 @@ pathlib.Path('deploy/linux/install-node.sh').write_text(new_text)
print('✅ Re-embedded packaged payload into deploy/linux/install-node.sh')
PY
# Keep the root installer copy in sync with the packaged source of truth
cp package-hermes-node-agent/install.sh install.sh
# Cleanup
rm -rf "$BUILD_DIR"
......
This diff is collapsed.
......@@ -269,9 +269,19 @@ class PosixCommandExecutor(CommandExecutor):
def execute(self, command: Any, approved: bool = False) -> Dict[str, Any]:
allowed, reason = self._check_permission(command, approved)
if not allowed and reason != 'ask':
return {'success': False, 'error': f'Permission denied: {reason}', 'exit_code': 127}
return {
'success': False,
'status': 'denied',
'error': f'Permission denied: {reason}',
'exit_code': 127,
}
if not approved and reason == 'ask':
return {'success': False, 'error': 'Command requires approval', 'exit_code': 2}
return {
'success': False,
'status': 'approval_required',
'error': 'Command requires approval',
'exit_code': 2,
}
if isinstance(command, (list, tuple)):
cmd = ' '.join(shlex.quote(str(part)) for part in command)
else:
......@@ -328,9 +338,19 @@ class WindowsCommandExecutor(CommandExecutor):
def execute(self, command: str, approved: bool = False) -> Dict[str, Any]:
allowed, reason = self._check_permission(command, approved)
if not allowed and reason != 'ask':
return {'success': False, 'error': f'Permission denied: {reason}', 'exit_code': 127}
return {
'success': False,
'status': 'denied',
'error': f'Permission denied: {reason}',
'exit_code': 127,
}
if not approved and reason == 'ask':
return {'success': False, 'error': 'Command requires approval', 'exit_code': 2}
return {
'success': False,
'status': 'approval_required',
'error': 'Command requires approval',
'exit_code': 2,
}
try:
import base64
encoded = base64.b64encode(command.encode('utf-16le')).decode('ascii')
......@@ -1321,16 +1341,20 @@ class NodeAgent:
})
exit_code = result.get('exit_code', -1)
error = result.get('error')
status = result.get('status')
if error:
_log_exec_failed(command, error, exit_code)
else:
_log_exec_completed(command, exit_code)
await self._send_json(ws, {
payload = {
'type': 'exec_complete',
'id': cmd_id,
'exit_code': exit_code,
'error': error,
})
}
if status:
payload['status'] = status
await self._send_json(ws, payload)
except Exception as e:
_log_exec_failed(command, str(e), -1)
await self._send_json(ws, {
......@@ -1488,8 +1512,7 @@ def main():
parser.add_argument('--debug', action='store_true', help='Debug logging')
args = parser.parse_args()
if args.debug:
logging.getLogger().setLevel(logging.DEBUG)
_setup_logging(args.debug)
# Load config to check token
config = NodeAgent(args.config)._load_config(args.config)
......@@ -1502,7 +1525,43 @@ def main():
try:
asyncio.run(agent.connect_and_run())
except KeyboardInterrupt:
logger.info("Shutting down")
_log_shutdown()
except Exception as e:
_log_connection_error(e)
raise
finally:
logging.shutdown()
for stream_name in ('stdout', 'stderr'):
stream = getattr(sys, stream_name, None)
if stream is not None:
try:
stream.flush()
except Exception:
pass
if sys.stdout:
try:
sys.stdout.flush()
except Exception:
pass
if sys.stderr:
try:
sys.stderr.flush()
except Exception:
pass
time.sleep(0.05)
try:
os.fsync(1)
except Exception:
pass
try:
os.fsync(2)
except Exception:
pass
sys.exit(0)
if __name__ == '__main__':
main()
......@@ -322,7 +322,8 @@ echo ""
echo "Next steps:"
echo " 1. Edit config: $CONFIG_DIR/config.json"
echo " 2. Start agent: $AGENT_DIR/hermes-node-agent --config $CONFIG_DIR/config.json"
echo " 3. Verify logs: tail -f /tmp/hermes-node-agent.log"
echo " 3. Verify logs live: $AGENT_DIR/hermes-node-agent --config $CONFIG_DIR/config.json"
echo " (or with debug: $AGENT_DIR/hermes-node-agent --debug --config $CONFIG_DIR/config.json)"
echo ""
echo "For Windows nodes, see WINDOWS_INSTALL.md"
echo "For full deployment guide, see DEPLOYMENT.md"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment