Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
H
hermes-node-agent
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lisa
hermes-node-agent
Commits
8892ed3a
Commit
8892ed3a
authored
May 14, 2026
by
Lisa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: repair browser control runtime and republish bundle
parent
2a9456fc
Changes
12
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
193 additions
and
57 deletions
+193
-57
PROTOCOL.md
PROTOCOL.md
+56
-34
README.md
README.md
+14
-4
browser_controller.py
browser_controller.py
+58
-0
install-node.sh
deploy/linux/install-node.sh
+1
-1
hermes-node-agent-linux.tar.gz
dist/hermes-node-agent-linux.tar.gz
+0
-0
hermes_node_agent.py
hermes_node_agent.py
+15
-2
install-windows.ps1
install-windows.ps1
+18
-8
hermes-node-agent-installer.sh
release/bundle/hermes-node-agent-installer.sh
+1
-1
hermes-node-agent-bundle.zip
release/hermes-node-agent-bundle.zip
+0
-0
README_BUILD.md
windows/README_BUILD.md
+12
-3
build-all.sh
windows/build-all.sh
+11
-2
installer.nsi
windows/installer.nsi
+7
-2
No files found.
PROTOCOL.md
View file @
8892ed3a
...
@@ -11,7 +11,7 @@
...
@@ -11,7 +11,7 @@
**Version:**
1.0
**Version:**
1.0
**Date:**
2026-04-29
**Date:**
2026-04-29
**Purpose:**
Reverse-connection node execution with
permission model, compatible with existing OpenClaw
`sexec.sh`
scripts
.
**Purpose:**
Reverse-connection node execution with
an integrated node-local permission model enforced by the agent
.
---
---
...
@@ -48,14 +48,15 @@
...
@@ -48,14 +48,15 @@
│ └───────────────────────────┬──────────────────────┘ │
│ └───────────────────────────┬──────────────────────┘ │
│ │ receives │
│ │ receives │
│ ┌───────────────────────────▼──────────────────────┐ │
│ ┌───────────────────────────▼──────────────────────┐ │
│ │ Command Executor (sexec wrapper) │ │
│ │ Integrated Command Executor │ │
│ │ - Runs: /path/to/sexec.sh run --command ... │ │
│ │ - Evaluates allow/deny/ask rules │ │
│ │ - Executes approved commands directly │ │
│ │ - Streams stdout/stderr back │ │
│ │ - Streams stdout/stderr back │ │
│ │ - Returns exit code │ │
│ │ - Returns exit code │ │
│ └──────────────────────────────────────────────────┘ │
│ └──────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
└──────────────────────────────────────────────────────────┘
Permission System (
sexec.sh + config.json) - reused exactly
Permission System (
config.json permissions block) - enforced by the agent
```
```
---
---
...
@@ -72,8 +73,14 @@ All messages are JSON over WebSocket.
...
@@ -72,8 +73,14 @@ All messages are JSON over WebSocket.
"type"
:
"register"
,
"type"
:
"register"
,
"node_name"
:
"sissy"
,
"node_name"
:
"sissy"
,
"version"
:
"1.0"
,
"version"
:
"1.0"
,
"capabilities"
:
[
"exec"
,
"sysinfo"
],
"capabilities"
:
[
"exec"
],
"sexec_path"
:
"/home/openclaw/.openclaw/skills/sexec/sexec.sh"
"capability_info"
:
{
"enable_browser"
:
false
,
"enable_computer_control"
:
false
,
"enable_desktop_observe"
:
false
,
"enable_audio_control"
:
false
,
"enable_camera_control"
:
false
}
}
}
```
```
...
@@ -121,7 +128,7 @@ All messages are JSON over WebSocket.
...
@@ -121,7 +128,7 @@ All messages are JSON over WebSocket.
-
`id`
: Unique command ID for tracking
-
`id`
: Unique command ID for tracking
-
`command`
: Array of command + args (e.g.,
`["df", "-h"]`
)
-
`command`
: Array of command + args (e.g.,
`["df", "-h"]`
)
-
`timeout`
: Max execution time in seconds
-
`timeout`
: Max execution time in seconds
-
`approved`
: If
`true`
, bypass
"ask" list
(user explicitly approved)
-
`approved`
: If
`true`
, bypass
the node's
`permissions.ask`
rules
(user explicitly approved)
### 4. Node → Gateway: Command Output (streaming)
### 4. Node → Gateway: Command Output (streaming)
...
@@ -158,7 +165,7 @@ All messages are JSON over WebSocket.
...
@@ -158,7 +165,7 @@ All messages are JSON over WebSocket.
### 6. Node → Gateway: Approval Required
### 6. Node → Gateway: Approval Required
**When command matches
"ask" list
:**
**When command matches
the node's `permissions.ask` rules
:**
```
json
```
json
{
{
"type"
:
"exec_approval_required"
,
"type"
:
"exec_approval_required"
,
...
@@ -180,7 +187,7 @@ All messages are JSON over WebSocket.
...
@@ -180,7 +187,7 @@ All messages are JSON over WebSocket.
### 7. Node → Gateway: Command Denied
### 7. Node → Gateway: Command Denied
**When command matches
"deny" list
:**
**When command matches
the node's `permissions.deny` rules
:**
```
json
```
json
{
{
"type"
:
"exec_denied"
,
"type"
:
"exec_denied"
,
...
@@ -257,8 +264,14 @@ Node registers optional tools in its `tools` list during registration and expose
...
@@ -257,8 +264,14 @@ Node registers optional tools in its `tools` list during registration and expose
"type"
:
"register"
,
"type"
:
"register"
,
"node_name"
:
"sissy"
,
"node_name"
:
"sissy"
,
"version"
:
"1.0"
,
"version"
:
"1.0"
,
"capabilities"
:
[
"exec"
,
"sysinfo"
,
"browser_control"
],
"capabilities"
:
[
"exec"
,
"browser_control"
],
"sexec_path"
:
"/home/openclaw/.openclaw/skills/sexec/sexec.sh"
"capability_info"
:
{
"enable_browser"
:
true
,
"enable_computer_control"
:
false
,
"enable_desktop_observe"
:
false
,
"enable_audio_control"
:
false
,
"enable_camera_control"
:
false
}
}
}
```
```
...
@@ -271,13 +284,22 @@ Node registers optional tools in its `tools` list during registration and expose
...
@@ -271,13 +284,22 @@ Node registers optional tools in its `tools` list during registration and expose
**Node config file**
(
`/etc/hermes-node/config.json`
):
**Node config file**
(
`/etc/hermes-node/config.json`
):
```
json
```
json
{
{
"gateway_url"
:
"ws://192.168.42.115:8765"
,
"gateway_url"
:
"ws
s
://192.168.42.115:8765"
,
"node_name"
:
"sissy"
,
"node_name"
:
"sissy"
,
"token"
:
"node-sissy-secret-token-abc123"
,
"token"
:
"node-sissy-secret-token-abc123"
,
"sexec_path"
:
"/home/openclaw/.openclaw/skills/sexec/sexec.sh"
,
"reconnect_interval"
:
5
,
"reconnect_interval"
:
5
,
"heartbeat_interval"
:
30
,
"heartbeat_interval"
:
30
,
"enable_camera_control"
:
false
"capabilities"
:
[
"exec"
],
"enable_browser"
:
false
,
"enable_computer_control"
:
false
,
"enable_desktop_observe"
:
false
,
"enable_audio_control"
:
false
,
"enable_camera_control"
:
false
,
"permissions"
:
{
"deny"
:
[
"rm -rf /"
,
"mkfs"
,
"dd if="
],
"ask"
:
[
"sudo"
,
"su"
,
"passwd"
,
"mount"
,
"umount"
,
"fdisk"
,
"parted"
],
"allow"
:
[
"ls"
,
"pwd"
,
"whoami"
,
"hostname"
,
"uname"
,
"date"
,
"uptime"
,
"df"
,
"free"
,
"ps"
,
"cat"
,
"head"
,
"tail"
,
"grep"
,
"find"
,
"du"
,
"ip"
,
"ifconfig"
,
"ping"
,
"curl"
,
"wget"
,
"git"
,
"python"
,
"python3"
,
"node"
,
"npm"
,
"dmesg"
,
"docker"
,
"kubectl"
]
}
}
}
```
```
...
@@ -351,7 +373,7 @@ For Hermes skill to submit commands.
...
@@ -351,7 +373,7 @@ For Hermes skill to submit commands.
"last_seen"
:
1714392000
,
"last_seen"
:
1714392000
,
"uptime"
:
86400
,
"uptime"
:
86400
,
"version"
:
"1.0"
,
"version"
:
"1.0"
,
"capabilities"
:
[
"exec"
,
"sysinfo"
]
"capabilities"
:
[
"exec"
]
}
}
```
```
...
@@ -369,21 +391,21 @@ For Hermes skill to submit commands.
...
@@ -369,21 +391,21 @@ For Hermes skill to submit commands.
-
Tokens stored in
`/etc/hermes-node/config.json`
on node
-
Tokens stored in
`/etc/hermes-node/config.json`
on node
-
Tokens stored in gateway registry (file or DB)
-
Tokens stored in gateway registry (file or DB)
### 3. Permission System
(Reused from sexec)
### 3. Permission System
-
Each node
keeps existing
`sexec.sh`
+
`config.json`
-
Each node
stores its permission rules in
`config.json`
-
`
allow`
list
: auto-execute
-
`
permissions.allow`
: auto-execute
-
`
ask`
list
: require user approval
-
`
permissions.ask`
: require user approval
-
`
deny`
list
: reject immediately
-
`
permissions.deny`
: reject immediately
### 4. Command Approval Flow
### 4. Command Approval Flow
```
```
User → Hermes → Gateway → Node
User → Hermes → Gateway → Node
↓
↓
sexec checks config.json
agent checks config.json permissions
↓
↓
matches "ask" list
matches `permissions.ask`
↓
↓
sends approval_required
sends approval_required
↓
↓
Gateway → User: "Approve 'sudo gnt-instance stop prod-db'?"
Gateway → User: "Approve 'sudo gnt-instance stop prod-db'?"
↓
↓
...
@@ -391,7 +413,7 @@ User: "yes"
...
@@ -391,7 +413,7 @@ User: "yes"
↓
↓
Gateway → Node: approved=true
Gateway → Node: approved=true
↓
↓
sexec executes
agent executes command
```
```
---
---
...
@@ -427,7 +449,7 @@ Gateway → Node: approved=true
...
@@ -427,7 +449,7 @@ Gateway → Node: approved=true
### Node Side
### Node Side
1.
Install
`hermes-node-agent`
package
1.
Install
`hermes-node-agent`
package
2.
Configure
`/etc/hermes-node/config.json`
with gateway URL + token
2.
Configure
`/etc/hermes-node/config.json`
with gateway URL + token
3.
Ensure
`sexec.sh`
is installed and configured
3.
Review the
`permissions`
block and capability toggles for the node
4.
Start service:
`/etc/init.d/hermes-node-agent start`
4.
Start service:
`/etc/init.d/hermes-node-agent start`
5.
Verify connection:
`tail -f /var/log/hermes-node-agent.log`
5.
Verify connection:
`tail -f /var/log/hermes-node-agent.log`
...
@@ -435,18 +457,18 @@ Gateway → Node: approved=true
...
@@ -435,18 +457,18 @@ Gateway → Node: approved=true
## Compatibility
## Compatibility
### With
OpenClaw sexec
### With
node-local permission policies
-
✅
Reuses exact same
`sexec.sh`
binary
-
✅
Keeps the permission policy in
`config.json`
-
✅
Reuses exact same
`config.json`
format
-
✅
Preserves allow/deny/ask semantics
-
✅
Reuses exact same permission logic
-
✅
Moves execution and approval checks fully into the agent
-
✅
No changes needed to existing sexec installations
-
✅
Removes external wrapper dependencies from deployment
### Migration from
OpenClaw
### Migration from
earlier wrapper-based setups
1.
Keep existing sexec on nodes
1.
Move any legacy allow/deny/ask rules into the node's
`permissions`
block
2.
Install
node agent alongside
2.
Install
or upgrade the node agent
3.
Configure gateway URL + token
3.
Configure gateway URL + token
4.
Start agent
4.
Start agent
5.
Disable OpenClaw gateway (optional)
5.
Remove obsolete wrapper references from local docs/scripts
---
---
...
...
README.md
View file @
8892ed3a
...
@@ -16,7 +16,7 @@ Cross-platform node agent for the Hermes Node Protocol. Connects to a central ga
...
@@ -16,7 +16,7 @@ Cross-platform node agent for the Hermes Node Protocol. Connects to a central ga
-
**Cross-platform**
: Linux and Windows support
-
**Cross-platform**
: Linux and Windows support
-
**Reverse connection**
: Nodes connect to gateway (firewall-friendly)
-
**Reverse connection**
: Nodes connect to gateway (firewall-friendly)
-
**Token authentication**
: Secure per-node tokens
-
**Token authentication**
: Secure per-node tokens
-
**Permission system**
:
sexec-based allow/deny/ask rules
-
**Permission system**
:
integrated allow/deny/ask rules enforced by the agent
-
**Auto-reconnect**
: Exponential backoff on disconnect
-
**Auto-reconnect**
: Exponential backoff on disconnect
-
**Heartbeat**
: Keep-alive mechanism
-
**Heartbeat**
: Keep-alive mechanism
-
**Optional capabilities**
: Browser control, computer control
-
**Optional capabilities**
: Browser control, computer control
...
@@ -72,9 +72,19 @@ sudo /etc/init.d/hermes-node-agent start
...
@@ -72,9 +72,19 @@ sudo /etc/init.d/hermes-node-agent start
"gateway_url": "wss://gateway-host:8765",
"gateway_url": "wss://gateway-host:8765",
"node_name": "my-node",
"node_name": "my-node",
"token": "your-token-here",
"token": "your-token-here",
"sexec_path": "/path/to/sexec.sh",
"reconnect_interval": 5,
"reconnect_interval": 5,
"heartbeat_interval": 30
"heartbeat_interval": 30,
"capabilities":
[
"exec"
]
,
"enable_browser": false,
"enable_computer_control": false,
"enable_desktop_observe": false,
"enable_audio_control": false,
"enable_camera_control": false,
"permissions": {
"deny":
[
"rm -rf /", "mkfs", "dd if="
]
,
"ask":
[
"sudo", "su", "passwd", "mount", "umount", "fdisk", "parted"
]
,
"allow":
[
"ls", "pwd", "whoami", "hostname", "uname", "date", "uptime", "df", "free", "ps", "cat", "head", "tail", "grep", "find", "du", "ip", "ifconfig", "ping", "curl", "wget", "git", "python", "python3", "node", "npm", "dmesg", "docker", "kubectl"
]
}
}
}
```
```
...
@@ -99,7 +109,7 @@ node-agent/
...
@@ -99,7 +109,7 @@ node-agent/
├── install.sh # Linux installer
├── install.sh # Linux installer
├── install-windows.ps1 # Windows PowerShell installer (legacy)
├── install-windows.ps1 # Windows PowerShell installer (legacy)
├── hermes-node-agent.init.d # SysV init script
├── hermes-node-agent.init.d # SysV init script
├── hermes-node-agent.service # s
ystemd unit (alternative
)
├── hermes-node-agent.service # s
ervice file (legacy artifact; SysV init is canonical
)
├── requirements.txt # Python dependencies
├── requirements.txt # Python dependencies
└── windows/ # Windows-specific components
└── windows/ # Windows-specific components
├── agent-manager.py # System tray GUI
├── agent-manager.py # System tray GUI
...
...
browser_controller.py
View file @
8892ed3a
...
@@ -18,6 +18,7 @@ Implements the interface expected by hermes_node_agent.py.
...
@@ -18,6 +18,7 @@ Implements the interface expected by hermes_node_agent.py.
import
asyncio
import
asyncio
import
base64
import
base64
import
inspect
import
logging
import
logging
from
typing
import
Dict
,
Any
,
Optional
from
typing
import
Dict
,
Any
,
Optional
from
pathlib
import
Path
from
pathlib
import
Path
...
@@ -401,6 +402,63 @@ class BrowserController:
...
@@ -401,6 +402,63 @@ class BrowserController:
cdp
=
await
page
.
context
.
new_cdp_session
(
page
)
cdp
=
await
page
.
context
.
new_cdp_session
(
page
)
result
=
await
cdp
.
send
(
method
,
params
or
{})
result
=
await
cdp
.
send
(
method
,
params
or
{})
return
{
"success"
:
True
,
"result"
:
result
}
return
{
"success"
:
True
,
"result"
:
result
}
async
def
execute
(
self
,
command
:
str
,
params
:
Dict
[
str
,
Any
]
=
None
)
->
Dict
[
str
,
Any
]:
"""Dispatch a browser_control command from the node-agent wire protocol."""
params
=
params
or
{}
layer
=
params
.
get
(
"layer"
,
"high_level"
)
page_id
=
params
.
get
(
"page_id"
)
if
layer
==
"playwright"
:
return
await
self
.
playwright_command
(
page_id
=
page_id
,
command
=
command
,
args
=
params
.
get
(
"args"
)
or
[],
kwargs
=
params
.
get
(
"kwargs"
)
or
{},
)
if
layer
==
"cdp"
:
return
await
self
.
cdp_command
(
page_id
=
page_id
,
method
=
command
,
params
=
params
.
get
(
"params"
)
or
{},
)
high_level_map
=
{
"launch"
:
self
.
launch
,
"create_context"
:
self
.
create_context
,
"new_page"
:
self
.
new_page
,
"navigate"
:
self
.
navigate
,
"click"
:
self
.
click
,
"fill"
:
self
.
fill
,
"type_text"
:
self
.
type_text
,
"wait_for_selector"
:
self
.
wait_for_selector
,
"execute_script"
:
self
.
execute_script
,
"evaluate"
:
self
.
evaluate
,
"screenshot"
:
self
.
screenshot
,
"get_content"
:
self
.
get_content
,
"get_title"
:
self
.
get_title
,
"get_url"
:
self
.
get_url
,
"close_page"
:
self
.
close_page
,
"close_context"
:
self
.
close_context
,
"close"
:
self
.
close
,
"list_pages"
:
self
.
list_pages
,
"list_contexts"
:
self
.
list_contexts
,
"load_extension"
:
self
.
load_extension
,
"execute_extension_script"
:
self
.
execute_extension_script
,
"list_extensions"
:
self
.
list_extensions
,
}
handler
=
high_level_map
.
get
(
command
)
if
handler
is
None
:
return
{
"success"
:
False
,
"error"
:
f
"Unknown browser command: {command}"
}
call_params
=
dict
(
params
)
call_params
.
pop
(
"layer"
,
None
)
signature
=
inspect
.
signature
(
handler
)
accepted
=
set
(
signature
.
parameters
.
keys
())
filtered
=
{
k
:
v
for
k
,
v
in
call_params
.
items
()
if
k
in
accepted
}
return
await
handler
(
**
filtered
)
# Helpers
# Helpers
...
...
deploy/linux/install-node.sh
View file @
8892ed3a
This diff is collapsed.
Click to expand it.
dist/hermes-node-agent-linux.tar.gz
View file @
8892ed3a
No preview for this file type
hermes_node_agent.py
View file @
8892ed3a
...
@@ -33,6 +33,7 @@ import ssl
...
@@ -33,6 +33,7 @@ import ssl
import
subprocess
import
subprocess
import
sys
import
sys
import
time
import
time
from
contextlib
import
suppress
from
pathlib
import
Path
from
pathlib
import
Path
from
typing
import
Optional
,
Dict
,
Any
,
List
from
typing
import
Optional
,
Dict
,
Any
,
List
...
@@ -1127,6 +1128,7 @@ class NodeAgent:
...
@@ -1127,6 +1128,7 @@ class NodeAgent:
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
warning
(
f
"BrowserController init failed: {e}"
)
logger
.
warning
(
f
"BrowserController init failed: {e}"
)
self
.
capabilities
=
self
.
_detect_capabilities
()
self
.
capabilities
=
self
.
_detect_capabilities
()
self
.
_pending_tasks
:
set
[
asyncio
.
Task
]
=
set
()
def
_load_config
(
self
,
path
:
Optional
[
str
])
->
Dict
[
str
,
Any
]:
def
_load_config
(
self
,
path
:
Optional
[
str
])
->
Dict
[
str
,
Any
]:
"""Load node configuration from JSON."""
"""Load node configuration from JSON."""
...
@@ -1227,7 +1229,9 @@ class NodeAgent:
...
@@ -1227,7 +1229,9 @@ class NodeAgent:
try
:
try
:
async
for
raw
in
ws
:
async
for
raw
in
ws
:
msg
=
json
.
loads
(
raw
)
msg
=
json
.
loads
(
raw
)
await
self
.
_handle_message
(
ws
,
msg
)
task
=
asyncio
.
create_task
(
self
.
_handle_message
(
ws
,
msg
))
self
.
_pending_tasks
.
add
(
task
)
task
.
add_done_callback
(
self
.
_pending_tasks
.
discard
)
except
Exception
as
e
:
except
Exception
as
e
:
disconnect_reason
=
e
disconnect_reason
=
e
raise
raise
...
@@ -1237,6 +1241,13 @@ class NodeAgent:
...
@@ -1237,6 +1241,13 @@ class NodeAgent:
await
heartbeat_task
await
heartbeat_task
except
asyncio
.
CancelledError
:
except
asyncio
.
CancelledError
:
pass
pass
pending
=
list
(
self
.
_pending_tasks
)
for
task
in
pending
:
task
.
cancel
()
for
task
in
pending
:
with
suppress
(
asyncio
.
CancelledError
):
await
task
self
.
_pending_tasks
.
clear
()
_log_disconnected
(
disconnect_reason
)
_log_disconnected
(
disconnect_reason
)
except
Exception
as
e
:
except
Exception
as
e
:
...
@@ -1433,9 +1444,11 @@ class NodeAgent:
...
@@ -1433,9 +1444,11 @@ class NodeAgent:
_log_browser_received
(
command
)
_log_browser_received
(
command
)
try
:
try
:
if
hasattr
(
self
.
browser
,
'execute'
):
if
hasattr
(
self
.
browser
,
'execute'
):
result
=
self
.
browser
.
execute
(
command
,
params
)
result
=
await
self
.
browser
.
execute
(
command
,
params
)
elif
hasattr
(
self
.
browser
,
'run'
):
elif
hasattr
(
self
.
browser
,
'run'
):
result
=
self
.
browser
.
run
(
command
,
params
)
result
=
self
.
browser
.
run
(
command
,
params
)
if
asyncio
.
iscoroutine
(
result
)
or
isinstance
(
result
,
asyncio
.
Future
):
result
=
await
result
else
:
else
:
result
=
{
'success'
:
False
,
'error'
:
'BrowserController has no execute/run entrypoint'
}
result
=
{
'success'
:
False
,
'error'
:
'BrowserController has no execute/run entrypoint'
}
except
Exception
as
e
:
except
Exception
as
e
:
...
...
install-windows.ps1
View file @
8892ed3a
...
@@ -96,13 +96,23 @@ if (-not (Test-Path $configPath)) {
...
@@ -96,13 +96,23 @@ if (-not (Test-Path $configPath)) {
$token
=
(
$tokenBytes
|
ForEach
-Object
{
$_
.ToString
(
"x2"
)
})
-join
''
$token
=
(
$tokenBytes
|
ForEach
-Object
{
$_
.ToString
(
"x2"
)
})
-join
''
$config
=
@
{
$config
=
@
{
gateway_url
=
"wss://YOUR-GATEWAY-HOST:8765"
gateway_url
=
"wss://YOUR-GATEWAY-HOST:8765"
node_name
=
$env
:COMPUTERNAME
node_name
=
$env
:COMPUTERNAME
token
=
$token
token
=
$token
sexec_path
=
"
$env
:USERPROFILE\.openclaw\skills\sexec\sexec.ps1"
reconnect_interval
=
5
reconnect_interval
=
5
heartbeat_interval
=
30
heartbeat_interval
=
30
capabilities
=
@
(
"exec"
)
}
|
ConvertTo-Json
-Depth 3
enable_browser
=
$false
enable_computer_control
=
$false
enable_desktop_observe
=
$false
enable_audio_control
=
$false
enable_camera_control
=
$false
permissions
=
@
{
deny
=
@
(
"rm -rf /"
,
"mkfs"
,
"dd if="
)
ask
=
@
(
"sudo"
,
"su"
,
"passwd"
,
"mount"
,
"umount"
,
"fdisk"
,
"parted"
)
allow
=
@
(
"ls"
,
"pwd"
,
"whoami"
,
"hostname"
,
"uname"
,
"date"
,
"uptime"
,
"df"
,
"free"
,
"ps"
,
"cat"
,
"head"
,
"tail"
,
"grep"
,
"find"
,
"du"
,
"ip"
,
"ifconfig"
,
"ping"
,
"curl"
,
"wget"
,
"git"
,
"python"
,
"python3"
,
"node"
,
"npm"
,
"systemctl"
,
"journalctl"
,
"dmesg"
,
"docker"
,
"kubectl"
)
}
}
|
ConvertTo-Json
-Depth 5
$config
|
Out-File
-FilePath
$configPath
-Encoding UTF8
$config
|
Out-File
-FilePath
$configPath
-Encoding UTF8
Write-Host
" Config written to:
$configPath
"
-ForegroundColor Yellow
Write-Host
" Config written to:
$configPath
"
-ForegroundColor Yellow
...
@@ -165,5 +175,5 @@ Write-Host " Get-Content $configDir\hermes-node-agent.log -Wait -Tail 50" -For
...
@@ -165,5 +175,5 @@ Write-Host " Get-Content $configDir\hermes-node-agent.log -Wait -Tail 50" -For
Write-Host
""
Write-Host
""
Write-Host
"=== Important ==="
-ForegroundColor Yellow
Write-Host
"=== Important ==="
-ForegroundColor Yellow
Write-Host
"The agent runs as SYSTEM if using Task Scheduler, or as LocalSystem if using NSSM."
-ForegroundColor Gray
Write-Host
"The agent runs as SYSTEM if using Task Scheduler, or as LocalSystem if using NSSM."
-ForegroundColor Gray
Write-Host
"
Ensure the sexec.ps1 script exists at the configured path if using permission
s."
-ForegroundColor Gray
Write-Host
"
Review the permissions block in config.json before enabling broader command acces
s."
-ForegroundColor Gray
Write-Host
""
Write-Host
""
release/bundle/hermes-node-agent-installer.sh
View file @
8892ed3a
This diff is collapsed.
Click to expand it.
release/hermes-node-agent-bundle.zip
View file @
8892ed3a
No preview for this file type
windows/README_BUILD.md
View file @
8892ed3a
...
@@ -70,13 +70,22 @@ This is a fully self-contained offline Windows installer.
...
@@ -70,13 +70,22 @@ This is a fully self-contained offline Windows installer.
The installer writes to `
C:
\P
rogramData
\H
ermesNode
\c
onfig.json
`:
The installer writes to `
C:
\P
rogramData
\H
ermesNode
\c
onfig.json
`:
```json
```json
{
{
"gateway_url": "ws://gateway.example.com:8765",
"gateway_url": "ws
s
://gateway.example.com:8765",
"node_name": "WORKSTATION-01",
"node_name": "WORKSTATION-01",
"token": "YOUR-SECRET-TOKEN",
"token": "YOUR-SECRET-TOKEN",
"sexec_path": ".\sexec-template.ps1",
"reconnect_interval": 5,
"reconnect_interval": 5,
"heartbeat_interval": 30,
"heartbeat_interval": 30,
"capabilities": ["exec", "browser_control", "computer_control"]
"capabilities": ["exec"],
"enable_browser": false,
"enable_computer_control": false,
"enable_desktop_observe": false,
"enable_audio_control": false,
"enable_camera_control": false,
"permissions": {
"deny": ["rm -rf /", "mkfs", "dd if="],
"ask": ["sudo", "su", "passwd", "mount", "umount", "fdisk", "parted"],
"allow": ["ls", "pwd", "whoami", "hostname", "uname", "date", "uptime", "df", "free", "ps", "cat", "head", "tail", "grep", "find", "du", "ip", "ifconfig", "ping", "curl", "wget", "git", "python", "python3", "node", "npm", "systemctl", "journalctl", "dmesg", "docker", "kubectl"]
}
}
}
```
```
...
...
windows/build-all.sh
View file @
8892ed3a
...
@@ -195,10 +195,19 @@ Section "Install"
...
@@ -195,10 +195,19 @@ Section "Install"
''gateway_url'': ''
$0
'',
''gateway_url'': ''
$0
'',
''node_name'': ''
$1
'',
''node_name'': ''
$1
'',
''token'': ''
$2
'',
''token'': ''
$2
'',
''sexec_path'': ''.\sexec-template.ps1'',
''reconnect_interval'': 5,
''reconnect_interval'': 5,
''heartbeat_interval'': 30,
''heartbeat_interval'': 30,
''capabilities'': [''exec'', ''browser_control'', ''computer_control'']
''capabilities'': [''exec''],
''enable_browser'':
$false
,
''enable_computer_control'':
$false
,
''enable_desktop_observe'':
$false
,
''enable_audio_control'':
$false
,
''enable_camera_control'':
$false
,
''permissions'': @{
''deny'': @(''rm -rf /'', ''mkfs'', ''dd if=''),
''ask'': @(''sudo'', ''su'', ''passwd'', ''mount'', ''umount'', ''fdisk'', ''parted''),
''allow'': @(''ls'', ''pwd'', ''whoami'', ''hostname'', ''uname'', ''date'', ''uptime'', ''df'', ''free'', ''ps'', ''cat'', ''head'', ''tail'', ''grep'', ''find'', ''du'', ''ip'', ''ifconfig'', ''ping'', ''curl'', ''wget'', ''git'', ''python'', ''python3'', ''node'', ''npm'', ''systemctl'', ''journalctl'', ''dmesg'', ''docker'', ''kubectl'')
}
}}")"'
}}")"'
; Write uninstaller
; Write uninstaller
...
...
windows/installer.nsi
View file @
8892ed3a
...
@@ -106,10 +106,15 @@ Section \"Install\"
...
@@ -106,10 +106,15 @@ Section \"Install\"
FWrite $0 \" \"gateway_url\": \"\"$GatewayURL\"\",\"
FWrite $0 \" \"gateway_url\": \"\"$GatewayURL\"\",\"
FWrite $0 \" \"node_name\": \"\"$NodeName\"\",\"
FWrite $0 \" \"node_name\": \"\"$NodeName\"\",\"
FWrite $0 \" \"token\": \"\"$Token\"\",\"
FWrite $0 \" \"token\": \"\"$Token\"\",\"
FWrite $0 \" \"sexec_path\": \"./sexec-template.ps1\",\"
FWrite $0 \" \"reconnect_interval\": 5,\"
FWrite $0 \" \"reconnect_interval\": 5,\"
FWrite $0 \" \"heartbeat_interval\": 30,\"
FWrite $0 \" \"heartbeat_interval\": 30,\"
FWrite $0 \" \"capabilities\": [\"exec\", \"browser_control\", \"computer_control\"]\"
FWrite $0 \" \"capabilities\": [\"exec\"],\"
FWrite $0 \" \"enable_browser\": false,\"
FWrite $0 \" \"enable_computer_control\": false,\"
FWrite $0 \" \"enable_desktop_observe\": false,\"
FWrite $0 \" \"enable_audio_control\": false,\"
FWrite $0 \" \"enable_camera_control\": false,\"
FWrite $0 \" \"permissions\": {\"deny\": [\"rm -rf /\", \"mkfs\", \"dd if=\"], \"ask\": [\"sudo\", \"su\", \"passwd\", \"mount\", \"umount\", \"fdisk\", \"parted\"], \"allow\": [\"ls\", \"pwd\", \"whoami\", \"hostname\", \"uname\", \"date\", \"uptime\", \"df\", \"free\", \"ps\", \"cat\", \"head\", \"tail\", \"grep\", \"find\", \"du\", \"ip\", \"ifconfig\", \"ping\", \"curl\", \"wget\", \"git\", \"python\", \"python3\", \"node\", \"npm\", \"systemctl\", \"journalctl\", \"dmesg\", \"docker\", \"kubectl\"]}\"
FWrite $0 \"}\"
FWrite $0 \"}\"
FileClose $0
FileClose $0
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment