mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
refactor(console): remove hosted-context command blocking from Hermes Console (#66144)
The dashboard console previously ran under a 'hosted' context that blocked most commands (auth add, config set model.*, mcp add --command, cron --script, ...) behind an allowlist + line-policy layer. With the full Hermes CLI now built into the dashboard, that policy layer is redundant gatekeeping: the console gets the same command surface everywhere. Removed: - ConsoleContext/contexts plumbing on ConsoleCommand + engine - EXPECTED_HOSTED_PATHS allowlist + _mark_hosted - _enforce_hosted_line_policy + HOSTED_CONFIG_* allow/block tables - _dashboard_console_context() and the context field on the ready frame - hosted-context tests; context badge in HermesConsoleModal Kept (mechanical, not policy): shell-syntax rejection, the interactive/server command blocks (gateway, dashboard, mcp serve, ...), mutating-command confirmations, output caps, and command timeouts.
This commit is contained in:
parent
60419dfb4b
commit
6dcbcd0277
5 changed files with 26 additions and 467 deletions
|
|
@ -339,168 +339,6 @@ def test_console_registry_covers_non_admin_cli_surface():
|
|||
assert missing == set()
|
||||
|
||||
|
||||
EXPECTED_HOSTED_CONSOLE_COMMANDS = {
|
||||
("status",),
|
||||
("doctor",),
|
||||
("logs",),
|
||||
("version",),
|
||||
("prompt-size",),
|
||||
("insights",),
|
||||
("security", "audit"),
|
||||
("portal", "info"),
|
||||
("portal", "tools"),
|
||||
("send",),
|
||||
("config", "show"),
|
||||
("config", "path"),
|
||||
("config", "env-path"),
|
||||
("config", "check"),
|
||||
("config", "migrate"),
|
||||
("config", "set"),
|
||||
("sessions", "list"),
|
||||
("sessions", "stats"),
|
||||
("sessions", "export"),
|
||||
("sessions", "rename"),
|
||||
("sessions", "optimize"),
|
||||
("sessions", "repair"),
|
||||
("cron", "list"),
|
||||
("cron", "status"),
|
||||
("cron", "create"),
|
||||
("cron", "edit"),
|
||||
("cron", "pause"),
|
||||
("cron", "resume"),
|
||||
("cron", "run"),
|
||||
("cron", "remove"),
|
||||
("cron", "tick"),
|
||||
("profile",),
|
||||
("profile", "list"),
|
||||
("profile", "show"),
|
||||
("profile", "info"),
|
||||
("tools", "list"),
|
||||
("tools", "enable"),
|
||||
("tools", "disable"),
|
||||
("tools", "post-setup"),
|
||||
("skills", "browse"),
|
||||
("skills", "search"),
|
||||
("skills", "inspect"),
|
||||
("skills", "list"),
|
||||
("skills", "check"),
|
||||
("skills", "list-modified"),
|
||||
("skills", "diff"),
|
||||
("skills", "install"),
|
||||
("skills", "update"),
|
||||
("skills", "audit"),
|
||||
("skills", "uninstall"),
|
||||
("skills", "reset"),
|
||||
("skills", "opt-in"),
|
||||
("skills", "opt-out"),
|
||||
("skills", "repair-official"),
|
||||
("skills", "snapshot", "export"),
|
||||
("skills", "tap", "list"),
|
||||
("mcp", "list"),
|
||||
("mcp", "catalog"),
|
||||
("mcp", "test"),
|
||||
("mcp", "add"),
|
||||
("mcp", "remove"),
|
||||
("mcp", "install"),
|
||||
("mcp", "login"),
|
||||
("mcp", "reauth"),
|
||||
("mcp", "configure"),
|
||||
("mcp", "picker"),
|
||||
("memory", "status"),
|
||||
("auth", "list"),
|
||||
("auth", "status"),
|
||||
("auth", "reset"),
|
||||
("auth", "spotify", "status"),
|
||||
("pairing", "list"),
|
||||
("pairing", "approve"),
|
||||
("pairing", "revoke"),
|
||||
("pairing", "clear-pending"),
|
||||
("webhook", "list"),
|
||||
("webhook", "subscribe"),
|
||||
("webhook", "remove"),
|
||||
("webhook", "test"),
|
||||
}
|
||||
|
||||
|
||||
def test_hosted_console_registry_exposes_only_hosted_safe_surface():
|
||||
engine = HermesConsoleEngine(context="hosted")
|
||||
hosted = {
|
||||
path for path, command in engine.commands.items() if "hosted" in command.contexts
|
||||
}
|
||||
|
||||
assert hosted == EXPECTED_HOSTED_CONSOLE_COMMANDS
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"line",
|
||||
[
|
||||
"portal login",
|
||||
"auth add nous --type oauth",
|
||||
"auth logout nous",
|
||||
"profile create tester",
|
||||
"profile use default",
|
||||
"plugins list",
|
||||
"plugins install owner/repo",
|
||||
"kanban list",
|
||||
"hooks list",
|
||||
"checkpoints clear",
|
||||
"curator pause",
|
||||
"pets install cat",
|
||||
"backup --quick",
|
||||
"import /tmp/hermes-console-test.zip",
|
||||
"mcp serve",
|
||||
"model",
|
||||
"setup",
|
||||
"dashboard",
|
||||
"gateway restart",
|
||||
"update",
|
||||
"uninstall",
|
||||
],
|
||||
)
|
||||
def test_hosted_console_rejects_local_only_or_dangerous_commands(line):
|
||||
result = HermesConsoleEngine(context="hosted").execute(line)
|
||||
|
||||
assert result.status == "error"
|
||||
assert result.output
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"line",
|
||||
[
|
||||
"mcp add demo --url https://example.com/sse",
|
||||
"mcp install n8n",
|
||||
"mcp configure github",
|
||||
"mcp picker",
|
||||
"config set display.interface cli",
|
||||
"cron create 'every 1h' 'say hello'",
|
||||
],
|
||||
)
|
||||
def test_hosted_console_allows_guarded_useful_commands_before_confirmation(line):
|
||||
result = HermesConsoleEngine(context="hosted").execute(line)
|
||||
|
||||
assert result.status == "confirm_required"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"line",
|
||||
[
|
||||
"mcp add local --command npx --args foo",
|
||||
"mcp add local --preset unsafe",
|
||||
"mcp add local --url file:///tmp/server",
|
||||
"config set model.provider openrouter",
|
||||
"config set portal.url https://evil.example",
|
||||
"cron create 'every 1h' 'say hello' --script scripts/ping.py",
|
||||
"cron create 'every 1h' 'say hello' --no-agent",
|
||||
"cron edit abc123 --workdir /tmp/project",
|
||||
],
|
||||
)
|
||||
def test_hosted_console_blocks_known_footgun_arguments_before_confirmation(line):
|
||||
result = HermesConsoleEngine(context="hosted").execute(line)
|
||||
|
||||
assert result.status == "error"
|
||||
assert result.output
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"line",
|
||||
[
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue