srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/internal/store/store_test.go
AgeCommit message (Collapse)AuthorFilesLines
2026-08-04Plugin protocol foundation: tag_entry, tag search/sort, TUI tag viewsrdusr1-0/+16
The prerequisite for the plugin ecosystem: any external process - any language - that can reach the control socket can now tag a history entry with a short string marker and an opaque JSON data blob, stored in a new entry_tags table rather than requiring the plugin stay connected for a later live round-trip. A plugin does its analysis once; the data it attaches is what a human reviewing the entry later actually sees. internal/ipc: new "tag_entry" request (id, tag_plugin, tag, tag_data) and EntryDetail.Tags (the full record for one entry, populated by "get"). internal/store: entry_tags table, EntryTag struct, AddEntryTag/ ListEntryTags, a comma-joined Tags aggregate added to List/Search via a correlated subquery (cheap enough per row that showing a tag badge in the history list needs no N+1 query), and a new tag: search filter alongside the existing status:/source:/flagged:. TUI: a Tags column in the history table (sortable via o/O, the eighth sort column), T from detail view opens a tag list (mirroring the WebSocket-messages view's table-then-detail-viewport pattern), enter on one shows its data - JSON-colorized via the existing jsoncolor.go if it parses as JSON, sanitized plain text otherwise. Also fixed a pre-existing gap while touching this: the WebSocket-messages view never got mouse wheel support when it shipped; wired both it and the new tags view up together. PLUGINS.md documents the wire protocol for non-Go plugin authors - connection model (subscribe vs request/response), the handful of request types a plugin actually needs, and the trust boundary (the socket has no auth beyond OS file permissions, same as the TUI's own access). PLAN.md records the architecture decision (external process over an embedded scripting language - mirrors the daemon/TUI split already in place, no interpreter to sandbox, any language) and groups ~20 researched Burp extensions/Pro features into what Phase 1 already covers (Autorize, Param Miner, Backslash Powered Scanner, Retire.js - all just subscribe+repeat+tag, no new capability needed), what needs a second protocol addition (JWT Editor, SAML Raider - live RPC to a specific connected plugin for interactive actions like re-signing), and what deserves its own separate project rather than a plugin (active vulnerability scanning, Collaborator/OAST, a crawler). Verified live end to end against a real daemon: a throwaway program simulating a real plugin tagged a captured entry with structured JWT data over the actual wire protocol; confirmed the tag badge, tag: search filter, and full tag record all round-tripped correctly through List/Search/Get. Confirmed in the TUI itself (tmux, real keystrokes): the Tags column renders, T opens the tag list, entering it shows the JSON data with real ANSI-verified syntax highlighting (not just eyeballed), and tag: search filtering works from the history list.
2026-02-17Flagged marker for history entriessrdusr1-0/+27
Last of the "should build soon" items from the Burp/ZAP/Caido gap research - Burp's row highlighting and Caido's Findings both serve the same real workflow: mark something interesting mid-engagement, revisit later. Scoped to a boolean flag (★) rather than full free-text notes/comments, which would need their own text-input overlay for comparatively modest extra value over a simple marker - tracked as a real follow-up in PLAN.md, not dropped silently. internal/store: history gains a flagged column (migrated in for existing databases the same way source was) plus Store.SetFlagged and Summary/Entry.Flagged. Search's structured-filter layer (added last commit for status:/source:) gains flagged:true/false alongside them - extractStructured already existed for exactly this kind of "pull it out before it reaches FTS5" filter. internal/ipc gains a "set_flagged" request. cmd/mitmux: 'f' toggles the flag on the selected history row (applied optimistically to local state, persisted async - a drift between local and server state on failure is an acceptable trade-off for a marker this low-stakes), shown as a ★ column in the list and in the detail view's title. store_test.go covers the flagged: parsing (true/false spellings, and a "looks like it but isn't" case - flagged:maybe - falling through as literal search text, matching the existing pattern for status:). Verified live: toggling 'f' shows the star immediately, flagged:true correctly filtered to just that entry, and a direct SQLite check confirmed the flag actually persisted to the database (flagged=1), not just reflected in local UI state.
2026-02-16Structured search filters: status:, source:srdusr1-0/+95
Closes another top item from the Burp/ZAP/Caido gap research: status- code and MIME/type filtering alongside free text is used constantly in practice (Caido's HTTPQL, Burp's proxy history filter). Scoped to status and source for now - method: already works today via FTS5's own method column (a plain text match on "POST" is effectively exact for a short alphanumeric token), so it didn't need special handling. status_code isn't a text column FTS5 can index, and doesn't benefit from full-text matching anyway (it's a numeric comparison, not a word search), so extractStructured pulls status:/source: tokens out of the query before it reaches FTS5 and turns them into real parameterized SQL predicates against history's typed columns: status:404 (exact), status:>=400 / status:!=200 (comparison operators), status:4xx (also 2xx/3xx/5xx - the shorthand people actually reach for: "show me the errors"), source:repeater/intruder/proxy. Whatever text remains after extraction still goes through the existing FTS5 path, so "admin status:200" correctly ANDs a real full-text match with a real status predicate in one query. When nothing remains (pure "status:4xx"), Search skips the FTS5 join entirely and queries history directly. store_test.go covers the parsing (exact/operator/range/source, combined with free text, and two "looks like it but isn't" cases - status:banana and the malformed 4-digit status:4004 - to confirm they fall through as literal search text instead of being misparsed). Verified live against real varied traffic (status 200/404/500 requests plus a POST with an "admin" body) - status:4xx matched only the 404; status:>=400 matched both 404 and 500; "admin status:200" correctly matched only the POST and excluded the other unrelated 200; source:proxy matched everything captured so far. All against the actual SQL execution path, not just the pure parsing function.