mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
Review finding: after an 'always' answer whose command_allowlist entry the operator deletes, the note credited an 'approve for session' answer never given. Both 'session' and 'always' answers session-approve their keys, so the note now says 'an approval the user gave earlier in this session'.
50 lines
2.2 KiB
Python
50 lines
2.2 KiB
Python
"""Why a flagged command ran without a prompt.
|
|
|
|
When a prior user decision (a ``command_allowlist`` entry, an 'always' approval, or an
|
|
earlier approval in this session) covers every finding in a dangerous command, the guard still
|
|
approves silently; these helpers attach that provenance to the guard result and turn it into
|
|
the terminal tool's ``approval`` note, so the run is explained instead of looking like a bypass.
|
|
Provenance never decides anything: callers build it only after the approval check passed.
|
|
"""
|
|
|
|
|
|
def preapproved_result(findings: list[tuple[str, str]], scope_of) -> dict:
|
|
"""Approved guard result for *findings* ``[(pattern_key, description)]`` that are all already
|
|
approved; ``scope_of(key)`` labels each one 'permanent' or 'session'."""
|
|
return {
|
|
"approved": True,
|
|
"message": None,
|
|
"pre_approved": [{"description": text, "scope": scope_of(key)} for key, text in findings],
|
|
}
|
|
|
|
|
|
def allowlisted_result(rule: str, description: str) -> dict:
|
|
"""Approved guard result for a flagged command waved through by a ``command_allowlist`` entry."""
|
|
return {
|
|
"approved": True,
|
|
"message": None,
|
|
"pre_approved": [{"description": description, "scope": "allowlist", "rule": rule}],
|
|
}
|
|
|
|
|
|
_SCOPE_PHRASES = {
|
|
"allowlist": "the command_allowlist entry `{rule}` in config.yaml",
|
|
"permanent": "an 'always' approval the user saved earlier",
|
|
# Both a 'session' and an 'always' answer session-approve their keys, so a session-only grant may
|
|
# be what is left of an 'always' answer whose command_allowlist entry the operator removed.
|
|
"session": "an approval the user gave earlier in this session",
|
|
}
|
|
|
|
|
|
def preapproval_note(entries: list[dict]) -> str:
|
|
"""One-sentence ``approval`` note for a guard result's ``pre_approved`` entries."""
|
|
flagged = "; ".join(entry["description"] for entry in entries)
|
|
reasons = []
|
|
for entry in entries:
|
|
phrase = _SCOPE_PHRASES[entry["scope"]].format(rule=entry.get("rule", ""))
|
|
if len(entries) > 1:
|
|
phrase = f"{entry['description']}: {phrase}"
|
|
if phrase not in reasons:
|
|
reasons.append(phrase)
|
|
return f"Command was flagged ({flagged}) and auto-approved by {'; '.join(reasons)}."
|