feat(find): talonctl find — resolve any identifier to a template#12
Merged
Conversation
Pure module with no I/O — dataclasses, RULE_ID_RE, NON_IAC_PREFIXES, and an empty ResourceFinder.find() that always returns strategy_used=none. Subsequent tasks will layer on each resolution strategy behind TDD. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Matches 32-char hex query against provider_metadata.rule_id across all resource types. Case-insensitive, --type-filterable, tolerates missing/ malformed provider_metadata. Returns strategy_used=rule_id. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bare-key match across type buckets plus explicit "type.name" form. --type filter narrows which buckets are probed. Same key across multiple types returns all matches, sorted (resource_type, resource_id). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ngsiem:<rule_id> delegates to the rule_id strategy with a distinct strategy_used="composite_id_ngsiem". fcs:/thirdparty:/cwpp: return a populated non_iac_info block and an empty match set, marking the alert as non-IaC-tunable. Unknown prefixes fall through so keys that happen to contain a colon still hit later strategies. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Case-insensitive substring match on display_name across state, skipping queries that contain * or ? (those go to glob). Deterministic (resource_type, resource_id) sort. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fnmatch.fnmatchcase against state keys; activated only when query contains * or ?. Honors --type filter. Deterministic sort. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
resource_id, name_substring, and glob strategies now also scan the templates list passed to ResourceFinder. Dedup suppresses templates whose (resource_type, name) is already in state (state wins). Template-only hits have deployed=False, rule_id=None, deployed_at=None. rule_id strategy is intentionally a no-op for undeployed templates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Thin Click wrapper around ResourceFinder. Loads state directly via JSON (no orchestrator, no creds). Renders matches to a rich Table with a one-line header; non-IaC composite matches render as a Panel. Exit code 0 for matches or recognized non-IaC, 1 otherwise. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Emit a stable JSON shape (query, strategy_used, matches, non_iac_info) regardless of match count. Suppress the shared talonctl banner when find is invoked with --format json/path so stdout pipes cleanly. Uses ctx.args in the group callback (works under CliRunner). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
One template_path per stdout line, no header, no color, no banner. Entries missing template_path produce a single-line stderr warning and are skipped (does not affect exit code). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Exit 1 with a stderr note when state file is absent (unless --include-undeployed is set with an empty templates list, which is still exit 1 but silent). Exit 2 on corrupt JSON. Locks in the exit-code contract documented in the spec. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Registration itself landed in the Task 9 commit as part of the _TalonGroup wiring; this test is the contract that keeps it there. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the spec's acceptance list verbatim so regressions across any strategy, format, or exit-code path fail loudly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes #10. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
talonctl find QUERY— an offline, read-only subcommand that resolves an arbitrary identifier to one or more talonctl-managed resources. Closes #10.rule_idUUID →resource_id→ composite ID (ngsiem:/fcs:/thirdparty:/cwpp:) → display-name substring → glob onresource_id.detection,saved_search,workflow,lookup_file,rtr_script,rtr_put_file,dashboard).table(default, rich Table / Panel for non-IaC composite alerts),json(stable shape),path(bare template paths forxargs).--include-undeployedscans on-disk templates alongside state (state wins on dedup).0on match or recognized non-IaC prefix,1on zero-match,2on malformed args or corrupt state file.Architecture
src/talonctl/core/resource_finder.py(dataclasses, constants,ResourceFinderwith ordered method chain).src/talonctl/commands/find.py.cli.pygets a_TalonGroupsubclass that suppresses the shared banner whenfindis invoked with--format json/--format path, so stdout pipes cleanly.Spec + plan were brainstormed first (see
docs/superpowers/specs/2026-04-21-talonctl-find-design.mdanddocs/superpowers/plans/2026-04-21-talonctl-find.md— both gitignored, local only).Tests
test_resource_finder.py, 24 intest_find_command.py).talonctl find— resolve any identifier (UUID, resource_id, name, composite alert ID, glob) to a template path #10 are locked in asTestAcceptanceCriteria::test_ac{1..10}_*.ruff format/ruff checkclean.Test plan
deployed_state.json, run `talonctl find <rule_id>` and confirm the matching template path appears.Follow-up items (not blocking)
_TalonGroup.invoke()insrc/talonctl/cli.py:26-27readsctx.protected_args, which emits aDeprecationWarningunder Click 8 and is removed in Click 9. Tests pass today (12 warnings in the suite), but we'll need to port the banner-suppression mechanism before bumping to Click 9.console.print_json(...); the implementation usesclick.echo(json.dumps(..., indent=2))instead so stdout is guaranteed Rich-free and pipe-clean. Intentional departure from the spec wording.🤖 Generated with Claude Code