diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-10 11:10:08 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-10 11:10:08 +0200 |
| commit | 45a68fbbe8da80a7bdf399b2e042f1982ca6a69d (patch) | |
| tree | d56a1f42cc1507b185cbfcc60f2aee63a8ddf1d5 /tests/fixtures/forged-chain.eml | |
| parent | fb45dbc03650bd9ed7f5629fd01fffdaa951f109 (diff) | |
| download | abusectl-45a68fbbe8da80a7bdf399b2e042f1982ca6a69d.tar.gz abusectl-45a68fbbe8da80a7bdf399b2e042f1982ca6a69d.zip | |
feat: add the report subcommand
Refuses without a configured reporter identity rather than filing a report
with no reply address, and turns a frozen or edited case into an error
message rather than a traceback.
The identity rule is EMAIL REQUIRED, NAME AND ORG OPTIONAL, not the plan's
"all three required". Each [reporter] key is individually skippable at init
and config drops a skipped one rather than storing "", so a partial identity
is a normal shape; text_part() already renders whatever subset is present.
Requiring all three would refuse a config init itself writes without
complaint. The address is different in kind because it becomes the From.
That closes backlog item 5: report.build() read identity["email"] directly
and raised a bare KeyError on a name-without-address identity, which is
exactly what skipping one init prompt while answering another produces. The
check lives in the command rather than the builder, since that is what
decides whether the user sees an exit code and a sentence or a traceback.
Two further defects in the plan's code, both fixed here:
- It called config.load() with no argument, so the global --config option
was silently ignored for this subcommand alone. It now resolves the path
the way _cmd_parse does. Reporting against the wrong identity is the
failure that would have caused.
- Its summary printed counts and no path. Nothing sends these bodies yet, so
reviewing them by hand is the entire point of the command, and the case's
bodies directory is now named in the output.
case.py stays the only writer of the manifest: generate() returns it and
case.save() writes it atomically. Bodies are written before that save, so a
failed save leaves bodies the manifest does not record; the next run finds no
recorded hash, treats them as regenerable rather than hand-edited and
overwrites them, and nothing has been sent, so no machinery is warranted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LByBnw83xr9YP85nskzkyE
Diffstat (limited to 'tests/fixtures/forged-chain.eml')
0 files changed, 0 insertions, 0 deletions
