aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_init.py
AgeCommit message (Collapse)AuthorFilesLines
25 hoursfix: ask before keeping a destination the user skippedHEADmasterDanilo M.1-1/+138
Skipping a destination at init left the previous one in the file. Sections a run does not render are preserved verbatim, which is what stops an init setting only the relays from discarding a key set earlier, but a skip is a deliberate "do not use this" and the two rules collided. Declining MISP re-enabled the instance from an earlier run, and MISP is the gate for everything irreversible, so report would have submitted to an instance the user had just said no to. Both vendors behaved the same way. Found by hand-testing the prompts, which is why they are hand-tested: no unit test covers a sequence of runs, and the suite was green throughout. write() gains `drop`, the sections the user was ASKED about and skipped, which join the set _preserved_sections already drops. An unasked section is still preserved, so the non-interactive path and the existing carry-across tests are unchanged. The prompt only fires when a section BOTH exists and was skipped, and Enter keeps it: removal is the destructive answer and has to be typed. DESTINATION_ANSWER_KEYS is derived from _DESTINATION_FIELDS rather than written out again, so a destination added later cannot be forgotten here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0176FYdVfpzUq8S9jecqQqL6
25 hoursfeat: render the destination sections at initDanilo M.1-0/+44
init.build() can now write [misp], [abusedb] and [urlhaus], the three sections report reads, so a user no longer has to hand-edit the config for them. Follows the [reporter] pattern: a section is emitted only when something was answered for it, never with an empty api_key. A half-answered pair (misp_url given, misp_api_key skipped, or vice versa) is rejected rather than silently written: config.load() would classify it "incomplete" and report would refuse, but only after the user believed setup succeeded. Task 8's prompts are the normal route in, but build() is pure and a caller can hand-build a dict, so this is enforced here too. Also fixes FOOTER, which still promised a single [vendors] table; the spec settled three separate sections and [misp] is no longer "a later part" since this plan builds it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0176FYdVfpzUq8S9jecqQqL6
31 hoursfix: keep the trailing comment at the end of the configDanilo M.1-0/+17
The "Later parts add further sections here" block was emitted by build(), so preserved sections were appended below it and it became a comment about nothing, pointing at a table already underneath it. It is now a FOOTER constant that build() still appends, so a lone build() reads as a complete file, and write() strips before adding preserved text and puts back at the end. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LByBnw83xr9YP85nskzkyE
31 hoursfix: restore the footer guard, with the sequence that needs itDanilo M.1-0/+21
The previous commit removed this guard after a mutation check said it was redundant. The check was wrong: it only exercised runs that skipped the identity from the start, where [reporter] is never written and the footer always trails a rendered table. The sequence that breaks is answering the identity and then re-running and skipping it. [reporter] is then PRESERVED rather than rendered, so the footer that trailed it in the old file rides across while this run emits its own, and the file grows a second copy per run. Covered by a test naming that sequence, and both guards now fail when removed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LByBnw83xr9YP85nskzkyE
31 hoursfix: stop init duplicating its own preamble on every rewriteDanilo M.1-0/+27
The carry-across preserved every line before the first [table], but that text is build()'s own header, not the user's. A second init emitted it twice and a third three times, with [general] missing from the tail half, so the file grew a copy per run. It still parsed, which is why the suite stayed green and only a hand test found it. Preserving from the first table onward fixes the trailing "Later parts" block too: it trails whichever table came last, so it is already inside a skipped section. A separate guard for it passed its own mutation check and was removed as redundant. Required prompts now say so. The relay question and the hop picker cannot be skipped, because with no trust boundary parse refuses and init is the route out, but they read like the reporter questions that do offer a skip. The cases prompt says "Enter for <default>" rather than showing the default in brackets, which was the same ambiguity in the other direction. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LByBnw83xr9YP85nskzkyE
32 hoursfeat: ask for the reporter identity during initDanilo M.1-0/+138
Each answer is validated at the prompt that asked for it, and a skipped answer is absent from the file rather than an empty string. Two defects fixed beyond the plan, both in the carry-across rule. Sections build() does not produce are preserved verbatim, and that rule was written when [general] was the only section it produced. Emitting [reporter] as well made preservation emit it TWICE, and tomllib refuses a duplicate table outright, so the rewritten file became unreadable and took the preserved [misp] key with it. Dropping [reporter] unconditionally instead would have been the opposite defect: an init that skips all three questions would silently delete an identity set by hand. What is dropped is now read back off the rendered text, so it is what this run actually wrote rather than what it might have written, and a section added to the builder later cannot be forgotten here. The email check is deliberately not an RFC 5322 validator. What a typo costs is a report whose reply address bounces, and the answers that produce that are a name with no @ at all, a spelled-out "at", and a stray space from a copy-paste. Anything stricter starts rejecting addresses that work. Skipping the address is allowed but warned about at the prompt: it is the one field a report cannot be built without, since it becomes the From. report.build() raises a bare KeyError on that identity today, which the three prompts made reachable from a config file for the first time; logged as backlog item 5 rather than fixed here, because where the check belongs is the report subcommand. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LByBnw83xr9YP85nskzkyE
3 daysfeat: first-run config builderDanilo M.1-0/+185
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KphFXTc2QajxXsHWyvGJ4R