filter: make drops visible in the gateway log
Every drop so far has been silent. The script printed its reason to stderr
and exited 0 with "[SILENT]", but Hermes only logs stderr on the nonzero
path, as
script ignored webhook path=... code=... stderr=...
so from outside, a deliberate drop, a crash, a timeout and a missing file all
looked identical: {"status":"ignored","reason":"script"} and nothing else.
Finding out which one it was meant re-running the payload through the script
by hand.
Drops now exit 3 with an empty stdout. Both still mean "ignored" to Hermes,
but the reason lands in the log. Exit 3 rather than 1 keeps a deliberate drop
distinguishable from an unhandled exception, which exits 1, so the code alone
says which happened.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S94o42aQ8VkBmEWvDem5xa
This commit is contained in:
@@ -89,12 +89,21 @@ for path in [("comment","id"), ("comment","body"), ("comment","user","login"),
|
||||
print(f"{'PASS' if ok else 'FAIL'} {'prompt path survives: {' + label + '}':<52} {cur if ok else 'MISSING'}")
|
||||
if not ok: fails.append(f"path-{label}")
|
||||
|
||||
# --- stdout discipline: an ignore must emit EXACTLY [SILENT] ---
|
||||
# --- drop contract: nonzero exit + empty stdout + reason on stderr ---
|
||||
# Nonzero is what gets the reason into the gateway log (Hermes logs
|
||||
# "script ignored webhook path=... code=... stderr=..." only on that path).
|
||||
rc, out, err = run(payload(author="luna"))
|
||||
print(f"{'PASS' if out == chr(91)+'SILENT'+chr(93)+chr(10) else 'FAIL'} {'ignore emits exactly [SILENT] on stdout':<52} {out!r}")
|
||||
if out != "[SILENT]\n": fails.append("silent-exact")
|
||||
print(f"{'PASS' if err.strip() else 'FAIL'} {'ignore explains itself on stderr':<52} {err.strip()[:40]!r}")
|
||||
if not err.strip(): fails.append("stderr-reason")
|
||||
print(f"{'PASS' if rc == 3 else 'FAIL'} {'drop exits 3 (not 0, so Hermes logs it)':<52} rc={rc}")
|
||||
if rc != 3: fails.append("drop-exit-code")
|
||||
print(f"{'PASS' if out == '' else 'FAIL'} {'drop writes nothing to stdout':<52} {out!r}")
|
||||
if out != "": fails.append("drop-stdout-empty")
|
||||
print(f"{'PASS' if 'luna' in err else 'FAIL'} {'drop names the rule on stderr':<52} {err.strip()[-44:]!r}")
|
||||
if "luna" not in err: fails.append("stderr-reason")
|
||||
|
||||
# a crash must stay distinguishable from a deliberate drop
|
||||
rc, out, err = run("not-a-dict")
|
||||
print(f"{'PASS' if rc == 3 else 'FAIL'} {'malformed payload is a drop (3), not a crash':<52} rc={rc}")
|
||||
if rc != 3: fails.append("malformed-exit-code")
|
||||
|
||||
print()
|
||||
print("ALL PASSED" if not fails else "FAILURES: " + ", ".join(fails))
|
||||
|
||||
@@ -12,7 +12,19 @@ STDOUT IS A PROTOCOL CHANNEL, not a log:
|
||||
That last case is why every diagnostic here goes to stderr. A stray print()
|
||||
would not drop an event, it would let one through.
|
||||
|
||||
Empty stdout, a nonzero exit, a missing script, or a timeout also count as
|
||||
Drops exit with DROP_EXIT_CODE and an empty stdout rather than printing
|
||||
"[SILENT]" and exiting 0. Both mean "ignored" to Hermes, but only the nonzero
|
||||
path is logged, as
|
||||
|
||||
script ignored webhook path=... code=3 stderr=...
|
||||
|
||||
which puts the reason in the gateway log. On the exit-0 path the reason goes
|
||||
to stderr and is never surfaced anywhere, so a drop is indistinguishable from
|
||||
a crash from a missing file -- which cost a long debugging detour once
|
||||
already. code=3 is what separates a deliberate drop from a real crash: a
|
||||
traceback exits 1.
|
||||
|
||||
Empty stdout, a nonzero exit, a missing script, or a timeout all count as
|
||||
"ignored", so this script fails CLOSED: if it breaks, nothing reaches the
|
||||
agent rather than everything. That is the right direction for a loop guard,
|
||||
but it does mean a syntax error silently disables the whole integration --
|
||||
@@ -35,6 +47,11 @@ import sys
|
||||
# and you do not want her reacting to build output.
|
||||
IGNORED_AUTHORS = {"luna"}
|
||||
|
||||
# Exit code for a deliberate drop. Anything nonzero makes Hermes ignore the
|
||||
# delivery AND log the reason; 3 distinguishes "a rule fired" from an
|
||||
# unhandled exception, which exits 1.
|
||||
DROP_EXIT_CODE = 3
|
||||
|
||||
# Gitea's HookIssueCommentAction values are created / edited / deleted.
|
||||
# "deleted" is dropped: the payload still carries the comment body, so letting
|
||||
# it through would have her act on a request that was explicitly withdrawn.
|
||||
@@ -42,9 +59,9 @@ ALLOWED_ACTIONS = {"created", "edited"}
|
||||
|
||||
|
||||
def ignore(reason: str) -> None:
|
||||
"""Drop the delivery, loudly enough to find in the gateway log."""
|
||||
print(f"gitea-pr-comment-filter: ignoring delivery: {reason}", file=sys.stderr)
|
||||
print("[SILENT]")
|
||||
raise SystemExit(0)
|
||||
raise SystemExit(DROP_EXIT_CODE)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
Reference in New Issue
Block a user