Skip to content

feat(input): add per-target JSONL filters - #7597

Open
3nesdeniz wants to merge 7 commits into
projectdiscovery:devfrom
3nesdeniz:agent/jsonl-target-filters
Open

feat(input): add per-target JSONL filters#7597
3nesdeniz wants to merge 7 commits into
projectdiscovery:devfrom
3nesdeniz:agent/jsonl-target-filters

Conversation

@3nesdeniz

@3nesdeniz 3nesdeniz commented Jul 25, 2026

Copy link
Copy Markdown

Proposed changes

Closes #4934.

This adds a target-oriented JSONL mode in which each URL can override tags, exclude-tags, severity, and local templates while omitted fields inherit the corresponding global options:

{"url":"https://target-a.example","tags":["apache","shiro"],"severity":["critical","high"]}
{"url":"https://target-b.example","exclude-tags":["tomcat"],"templates":["http/cves/2026/"]}
{"url":"https://target-c.example"}
nuclei -l targets.jsonl -input-mode jsonl

The implementation:

  • extends the existing JSONL parser without changing legacy Proxify request/response behavior;
  • preserves omitted versus explicitly empty fields so inheritance is deterministic;
  • resolves each unique template selector plan once and loads a safe template superset;
  • filters target/template pairs before execution in both template-spray and host-spray strategies;
  • preserves clustered physical requests while selecting only the permitted operators for each target;
  • applies -exclude-hosts before caching target records;
  • keeps legacy MetaInput IDs, hashes, preflight keys, and multiformat behavior unchanged when no target overrides are present.

For combinations whose child execution cannot yet preserve independent target criteria, the runner returns a clear error instead of silently bypassing filters. This currently covers automatic scan, workflows, and global matchers. Per-target template selectors are local-only and cannot be combined with global remote template URLs.

An explicitly empty field clears the inherited CLI selection. For templates, this is equivalent to clearing -t and therefore falls back to the default template catalog.

This is a draft so maintainers can confirm those boundary semantics before it is marked ready.

Proof

  • go test -race ./internal/runner ./pkg/input/provider/http ./pkg/input/formats/json ./pkg/protocols/common/contextargs ./pkg/core ./pkg/templates
  • go test -tags=integration ./internal/tests/integration -run '^TestTargetJSONLTemplateFilters$' -count=1 -v
    • template-spray and host-spray
    • clustered templates
    • target exclusions
    • per-target template selection
  • go vet -tags=integration ./internal/tests/integration
  • make vet
  • make build
  • git diff --check

The complete local make test run reached four packages whose Interactsh tests could not register with the public OAST service. The same focused failures reproduce on an untouched upstream/dev worktree at bcf20899; all target-filter packages and integration scenarios above pass with the race detector where applicable.

Checklist

  • Pull request is created against the dev branch
  • All checks passed (lint, unit/integration/regression tests etc.) with my changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Summary by CodeRabbit

  • New Features
    • Added JSONL target records with per-target template, tag, severity, and exclusion filters.
    • Added exclusions for URLs, hosts, IPs, CIDRs, and ASNs.
    • Applied per-target filters consistently across standard and clustered scans.
    • Skipped nonmatching templates and adjusted progress totals accordingly.
  • Bug Fixes
    • Improved validation and clearer errors for invalid filter combinations.
    • Preserved compatibility with existing JSONL and Proxify formats.
  • Documentation
    • Added usage guidance and examples for per-target JSONL filtering.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c5929977-ba1d-470a-99b0-7c4d67df7595

📥 Commits

Reviewing files that changed from the base of the PR and between eb1b14c and 4023a4d.

📒 Files selected for processing (3)
  • internal/runner/target_filters.go
  • internal/runner/target_filters_test.go
  • pkg/input/README.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/input/README.md
  • internal/runner/target_filters_test.go
  • internal/runner/target_filters.go

Walkthrough

JSONL target records now define per-target tags, exclusions, severities, and templates. The runner prepares these filters, providers retain target metadata, executors skip non-matching templates, progress totals account for skipped work, and preflight keys preserve filtered-input identity.

Changes

Per-target filtering

Layer / File(s) Summary
Input metadata and provider flow
pkg/input/formats/..., pkg/input/provider/...
JSONL parsing validates target records and creates metadata-aware inputs. HTTP providers apply target exclusions, cache target inputs, and report derived provider types.
Target filter identity and matching
pkg/protocols/common/contextargs/...
TargetFilter prepares criteria, matches templates, preserves presence semantics, supports cloning, and contributes to input IDs and scan hashes.
Runner filter preparation
internal/runner/runner.go, internal/runner/target_filters.go
Enumeration prepares per-target filters, resolves template selectors, applies inherited settings, configures the template union, and rejects unsupported combinations.
Target-aware execution and progress
pkg/core/..., pkg/templates/...
Executors and clustered executors skip unmatched templates and adjust progress totals for filtered requests.
Preflight accounting and validation
internal/runner/preflight_portscan.go, internal/tests/integration/target_jsonl_test.go, pkg/input/README.md
Preflight keys preserve legacy inputs and distinguish filtered inputs. Tests cover duplicate occurrences, exclusions, clustering, template selection, and both scan strategies.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant JSONL
  participant InputProvider
  participant Runner
  participant TargetFilter
  participant Executor
  participant Progress
  JSONL->>InputProvider: parse target records
  InputProvider->>Runner: provide MetaInput values
  Runner->>TargetFilter: prepare inherited and per-target criteria
  Runner->>Executor: configure and execute templates
  Executor->>TargetFilter: evaluate template matches
  TargetFilter-->>Executor: return match decision
  Executor->>Progress: adjust totals for skipped requests
Loading

Poem

I’m a rabbit with filters, hopping in line,
Each target gets templates that fit just fine.
Tags bloom, exclusions fall,
Progress counts them all.
JSONL paths sparkle and shine!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.20% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: adding per-target JSONL filters.
Linked Issues check ✅ Passed The implementation meets issue #4934 by supporting target-specific tags and severity, with additional exclusions and template selection controls.
Out of Scope Changes check ✅ Passed The code, tests, documentation, and security restrictions directly support per-target JSONL filtering and legacy behavior.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@3nesdeniz
3nesdeniz marked this pull request as ready for review August 11, 2026 12:31
@3nesdeniz

Copy link
Copy Markdown
Author

Marked ready for review. The branch is synced with current dev, and the affected packages (internal/runner, pkg/input, pkg/protocols/common/contextargs, pkg/templates, pkg/core) pass their tests locally.

@neo-by-projectdiscovery-dev

neo-by-projectdiscovery-dev Bot commented Aug 11, 2026

Copy link
Copy Markdown

Neo - PR Security Review

The delta adds a correct pre-resolution containment guard for JSONL-supplied template selectors with no new exploitable vulnerabilities.

What Neo reviewed

internal/runner/target_filters.go, internal/runner/target_filters_test.go, pkg/catalog/disk/find.go, pkg/catalog/disk/path.go, pkg/utils/filepath/filepath.go, pkg/input/formats/json/json.go

Comment @pdneo help for available commands. · Open in Neo

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (13)
internal/runner/preflight_portscan_test.go (1)

122-135: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The Count() assertion does not test the production path.

allowCnt is set to 2 in the literal on line 125, and line 134 asserts that Count() returns 2. The assertion cannot fail. The behavior worth locking down is that preflightResolveAndPortScan derives allowCnt from countAllowedPreflightInputs rather than from len(allowed.GetAll()). Line 117 already covers the helper. Either drop the Count() assertion or set allowCnt from countAllowedPreflightInputs so the two stay linked.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/runner/preflight_portscan_test.go` around lines 122 - 135, Update
the filteringInputProvider test setup so allowCnt is derived via
countAllowedPreflightInputs rather than hard-coded as 2, allowing the Count()
assertion to exercise the production-derived value. Keep the existing Iterate
behavior and assertions unchanged.
pkg/core/executors_test.go (2)

247-269: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Two test files hardcode the "TargetInputProvider" string. The shared root cause is that neither file uses the provider.TargetInputProvider constant from pkg/input/provider/interface.go. A rename of the constant would leave both tests compiling while silently skipping the target-filter branch they intend to cover.

  • pkg/core/executors_test.go#L247-L269: import pkg/input/provider and replace the three inputType: "TargetInputProvider" literals with the constant.
  • internal/runner/target_filters_test.go#L40-L40: replace the returned literal in InputType with provider.TargetInputProvider; the package is already imported.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/core/executors_test.go` around lines 247 - 269, The tests hardcode the
target provider type instead of using the shared constant. In
pkg/core/executors_test.go lines 247-269, import pkg/input/provider and replace
all three "TargetInputProvider" literals with provider.TargetInputProvider; in
internal/runner/target_filters_test.go line 40, return
provider.TargetInputProvider from InputType, using the existing import.

247-249: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the provider.TargetInputProvider constant instead of the literal.

The literal "TargetInputProvider" must stay in sync with pkg/input/provider/interface.go. Import provider and use the constant so a rename breaks the build instead of silently disabling the tested branch.

Also applies to: 253-255, 268-269

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/core/executors_test.go` around lines 247 - 249, Replace the literal
"TargetInputProvider" with provider.TargetInputProvider in the
fakeTargetProvider initializations for deniedOnly and the additional referenced
cases. Import the provider package and use the constant consistently so these
tests track the canonical provider name.
internal/runner/preflight_portscan.go (1)

55-66: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider caching the preflight key to avoid repeated marshaling.

filteringInputProvider.Iterate computes preflightInputKey for every input on every iteration pass. In the template-spray strategy Iterate runs once per template, so the total cost is templates × inputs. For inputs with a TargetFilter, the new code adds a second MetaInput allocation, a second JSON marshal, and an identity concatenation compared to the previous single MarshalString.

A small map[*contextargs.MetaInput]string cache, or a key computed once during preflight collection and reused, would remove the repeated work.

Also applies to: 68-89

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/runner/preflight_portscan.go` around lines 55 - 66, The
filteringInputProvider.Iterate path repeatedly computes preflightInputKey for
the same MetaInput across template passes, causing redundant allocation and
marshaling. Add caching keyed by *contextargs.MetaInput, or compute and retain
each key during preflight collection, then reuse it in Iterate while preserving
the existing allowed-key filtering and callback behavior.
internal/tests/integration/target_jsonl_test.go (2)

100-137: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The fixed request count of 2 couples the test to clustering.

The assertion requires exactly one physical request per target, which holds only while the alpha and beta templates cluster. Any change to the clustering heuristics, or an added third template, produces a failure message about "physical request count" that does not explain the cause. Consider deriving the expected count from the scenario, or extending the failure message to state that clustering is the assumed precondition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tests/integration/target_jsonl_test.go` around lines 100 - 137, The
request-count assertion in the strategy/scenario integration test is coupled to
the current clustering behavior. Update the assertion around requestCount.Load
to derive the expected count from each scenario when possible; otherwise
explicitly state in the failure message that exactly two requests is the
clustering precondition, so changes to clustering or template count are clearly
diagnosed.

26-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a scenario for explicitly empty arrays.

Templates is declared as *[]string precisely so an explicit "templates": [] can be distinguished from an omitted field, and the PR documents that an empty array clears the inherited global selection. No scenario exercises that path end to end, and no scenario exercises a per-target severity override. Both are headline behaviors of this feature.

Add one record with Templates pointing at an empty slice, and one scenario with a severity field, then assert the resulting template selection.

Also applies to: 81-97

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tests/integration/target_jsonl_test.go` around lines 26 - 31, Add
integration coverage in the target JSONL test scenarios using targetJSONLRecord:
include a record whose Templates points to an explicitly empty slice and verify
it clears the inherited global templates, then add a scenario with a per-target
severity field and assert the resulting template selection. Preserve omitted
Templates behavior separately so explicit empty arrays remain distinguishable.
pkg/templates/cluster.go (1)

294-297: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Compute the matching operator set once per execution.

operatorMatchesTargetFilter runs for every operator on every event. Each call performs filepath.Clean, a binary search over the effective template paths, and two tag loops. A large cluster combined with many events repeats this work. Compute the allowed operators once before e.requests.ExecuteWithResults and iterate that slice inside the callback.

♻️ Proposed change for `Execute`
 	filter := ctx.Input.MetaInput.TargetFilter
 	if !e.MatchesTargetFilter(filter) {
 		return false, nil
 	}
+	activeOperators := e.operators
+	if filter != nil {
+		activeOperators = make([]*clusteredOperator, 0, len(e.operators))
+		for _, operator := range e.operators {
+			if operatorMatchesTargetFilter(operator, filter) {
+				activeOperators = append(activeOperators, operator)
+			}
+		}
+	}

Then replace for _, operator := range e.operators with for _, operator := range activeOperators in the event callback and in the matcher-status fallback loop.

Also applies to: 382-384

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/templates/cluster.go` around lines 294 - 297, Compute the filtered
operator set once in Execute before e.requests.ExecuteWithResults by applying
operatorMatchesTargetFilter to e.operators, then reuse that slice in the event
callback and matcher-status fallback loop. Replace both per-event iterations
over e.operators with activeOperators while preserving existing filtering
behavior.
internal/runner/target_filters_test.go (1)

156-186: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for removeIncludedTags and per-target severity overrides.

The suite covers tags, templates, and forced includes. Two behaviors from prepareTargetFilters remain untested:

  • -include-tags removing an inherited or per-target exclude tag.
  • filter.HasSeverities replacing the global -severity selection, including the explicitly empty case that clears it.

Both paths change which templates run, so a regression there is user visible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/runner/target_filters_test.go` around lines 156 - 186, Extend
TestPrepareTargetFiltersPreservesInheritanceAndForcedIncludes to cover
removeIncludedTags by asserting an inherited or per-target exclude tag is
removed when included, and add per-target severity cases verifying
filter.HasSeverities replaces the global severity selection, including an
explicitly empty severity list that clears the global selection. Use
MatchesTemplate assertions that demonstrate the resulting template execution
behavior.
pkg/templates/cluster_test.go (1)

57-96: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extend the cluster filter test to severity and template restriction.

The test covers tag matching only. operatorMatchesTargetFilter forwards severity and the restrictTemplates template-path check to MatchesTemplate. Add one case that prepares a filter with a severity list and one that prepares restrictTemplates=true with a single template path. Both are cheap to add and cover the paths that decide whether the shared clustered request runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/templates/cluster_test.go` around lines 57 - 96, Extend
TestClusterExecuterMatchesPerTargetFilters with cases for severity filtering and
restricted template paths. Prepare a severity filter and assert
operatorMatchesTargetFilter accepts the matching apache operator and rejects
nginx; prepare a restrictTemplates filter containing the apache template path
and assert only the corresponding operator matches, covering the forwarded
MatchesTemplate checks.
internal/runner/target_filters.go (1)

22-194: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Consider splitting prepareTargetFilters into smaller units.

The function performs validation, loader widening, global path resolution, per-target resolution, and loader assignment in one 170-line body. Extracting three helpers, for example validateTargetOverrides, resolveGlobalTemplateSets, and prepareInputFilter, would reduce the branch depth and make the template-selection switch easier to test in isolation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/runner/target_filters.go` around lines 22 - 194, Split
prepareTargetFilters into focused helpers for override validation,
global/default template path resolution, and per-input filter
preparation/assignment. Keep loader widening and final template assignment in
prepareTargetFilters, while moving the validation and template-selection switch
into named helpers such as validateTargetOverrides, resolveGlobalTemplateSets,
and prepareInputFilter without changing behavior.
pkg/input/provider/http/multiformat.go (1)

43-43: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate provider-type literal across packages.

targetInputProviderType here is "TargetInputProvider", and pkg/input/provider/interface.go declares TargetInputProvider = "TargetInputProvider". pkg/core compares target.InputType() against the provider constant. If either literal changes, the comparison fails silently and per-target filtering stops working.

The provider package imports this package, so this package cannot import it back. Add a compile-time assertion in pkg/input/provider/interface.go to bind the two values.

♻️ Proposed guard in pkg/input/provider/interface.go
// keep the provider-type constant in sync with the http provider implementation
var _ = map[bool]struct{}{true: {}}[TargetInputProvider == (&http.HttpInputProvider{}).InputType() || true]

A simpler option is a unit test in pkg/input/provider that asserts a JSONL target provider returns TargetInputProvider.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/input/provider/http/multiformat.go` at line 43, Bind the provider-type
values by adding a compile-time assertion in the existing TargetInputProvider
declaration area of provider/interface.go, comparing it with the HTTP provider
implementation’s InputType() result. Preserve the package dependency direction
by having the provider package reference the HTTP implementation without making
the HTTP package import provider, and ensure mismatched values fail compilation.
pkg/protocols/common/contextargs/target_filter_test.go (1)

12-19: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a multi-path case with unsorted input.

Every path slice passed to Prepare here has one element. A one-element slice is always sorted, so these cases cannot detect the binary-search hazard in containsSortedPath. Add a case that passes several template paths in unsorted order and asserts each one matches.

💚 Proposed additional test
func TestTargetFilterMatchesEveryConfiguredTemplatePath(t *testing.T) {
	filter := &TargetFilter{}
	filter.Prepare(
		nil, nil, nil,
		[]string{"/templates/zeta.yaml", "/templates/apache.yaml", "/templates/mid.yaml"},
		nil,
		true,
	)

	for _, path := range []string{"/templates/zeta.yaml", "/templates/apache.yaml", "/templates/mid.yaml"} {
		require.True(t, filter.MatchesTemplate(path, nil, severity.High, false), path)
	}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/protocols/common/contextargs/target_filter_test.go` around lines 12 - 19,
Add a test near the existing TargetFilter tests that calls TargetFilter.Prepare
with multiple unsorted template paths, then verifies MatchesTemplate returns
true for every configured path. Keep the case focused on exercising
containsSortedPath with unsorted input and use the existing assertion style.
pkg/input/formats/json/json_test.go (1)

100-107: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use t.Chdir instead of manual working-directory cleanup.

The module requires Go 1.26, so t.Chdir is available. Replace the later err = assignment with err := after removing the initial declaration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/input/formats/json/json_test.go` around lines 100 - 107, Update
TestJSONFormatterTreatsSeverityAsLiteralValue to use t.Chdir(t.TempDir())
instead of manually capturing and restoring the working directory, removing the
previousWorkingDirectory cleanup. After removing the initial err declaration,
change the later assignment to use err :=.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/runner/runner.go`:
- Line 686: Update the condition in the runner flow around
r.inputProvider.InputType() so TargetInputProvider also enables implicit DAST,
preserving the existing MultiFormatInputProvider and r.options.DAST behavior.
Ensure target JSONL input loads DAST templates by default.

In `@pkg/input/README.md`:
- Around line 46-54: Update the per-target override documentation to state that
built-in ignore-file tags remain enforced despite target-level exclude-tags, and
global -exclude-severity remains enforced despite target-level severity values.
Clarify that explicitly empty arrays do not override these exclusions.

In `@pkg/protocols/common/contextargs/target_filter.go`:
- Around line 45-63: The sorted-path invariant is not guaranteed for template
matching. In pkg/protocols/common/contextargs/target_filter.go lines 45-63,
update TargetFilter.Prepare to defensively copy, filepath.Clean, and sort both
templatePaths and includeTemplatePaths before storing them in
preparedTargetFilter; in pkg/protocols/common/contextargs/target_filter_test.go
lines 12-19, add coverage using multiple unsorted template paths and assert each
path matches.

---

Nitpick comments:
In `@internal/runner/preflight_portscan_test.go`:
- Around line 122-135: Update the filteringInputProvider test setup so allowCnt
is derived via countAllowedPreflightInputs rather than hard-coded as 2, allowing
the Count() assertion to exercise the production-derived value. Keep the
existing Iterate behavior and assertions unchanged.

In `@internal/runner/preflight_portscan.go`:
- Around line 55-66: The filteringInputProvider.Iterate path repeatedly computes
preflightInputKey for the same MetaInput across template passes, causing
redundant allocation and marshaling. Add caching keyed by
*contextargs.MetaInput, or compute and retain each key during preflight
collection, then reuse it in Iterate while preserving the existing allowed-key
filtering and callback behavior.

In `@internal/runner/target_filters_test.go`:
- Around line 156-186: Extend
TestPrepareTargetFiltersPreservesInheritanceAndForcedIncludes to cover
removeIncludedTags by asserting an inherited or per-target exclude tag is
removed when included, and add per-target severity cases verifying
filter.HasSeverities replaces the global severity selection, including an
explicitly empty severity list that clears the global selection. Use
MatchesTemplate assertions that demonstrate the resulting template execution
behavior.

In `@internal/runner/target_filters.go`:
- Around line 22-194: Split prepareTargetFilters into focused helpers for
override validation, global/default template path resolution, and per-input
filter preparation/assignment. Keep loader widening and final template
assignment in prepareTargetFilters, while moving the validation and
template-selection switch into named helpers such as validateTargetOverrides,
resolveGlobalTemplateSets, and prepareInputFilter without changing behavior.

In `@internal/tests/integration/target_jsonl_test.go`:
- Around line 100-137: The request-count assertion in the strategy/scenario
integration test is coupled to the current clustering behavior. Update the
assertion around requestCount.Load to derive the expected count from each
scenario when possible; otherwise explicitly state in the failure message that
exactly two requests is the clustering precondition, so changes to clustering or
template count are clearly diagnosed.
- Around line 26-31: Add integration coverage in the target JSONL test scenarios
using targetJSONLRecord: include a record whose Templates points to an
explicitly empty slice and verify it clears the inherited global templates, then
add a scenario with a per-target severity field and assert the resulting
template selection. Preserve omitted Templates behavior separately so explicit
empty arrays remain distinguishable.

In `@pkg/core/executors_test.go`:
- Around line 247-269: The tests hardcode the target provider type instead of
using the shared constant. In pkg/core/executors_test.go lines 247-269, import
pkg/input/provider and replace all three "TargetInputProvider" literals with
provider.TargetInputProvider; in internal/runner/target_filters_test.go line 40,
return provider.TargetInputProvider from InputType, using the existing import.
- Around line 247-249: Replace the literal "TargetInputProvider" with
provider.TargetInputProvider in the fakeTargetProvider initializations for
deniedOnly and the additional referenced cases. Import the provider package and
use the constant consistently so these tests track the canonical provider name.

In `@pkg/input/formats/json/json_test.go`:
- Around line 100-107: Update TestJSONFormatterTreatsSeverityAsLiteralValue to
use t.Chdir(t.TempDir()) instead of manually capturing and restoring the working
directory, removing the previousWorkingDirectory cleanup. After removing the
initial err declaration, change the later assignment to use err :=.

In `@pkg/input/provider/http/multiformat.go`:
- Line 43: Bind the provider-type values by adding a compile-time assertion in
the existing TargetInputProvider declaration area of provider/interface.go,
comparing it with the HTTP provider implementation’s InputType() result.
Preserve the package dependency direction by having the provider package
reference the HTTP implementation without making the HTTP package import
provider, and ensure mismatched values fail compilation.

In `@pkg/protocols/common/contextargs/target_filter_test.go`:
- Around line 12-19: Add a test near the existing TargetFilter tests that calls
TargetFilter.Prepare with multiple unsorted template paths, then verifies
MatchesTemplate returns true for every configured path. Keep the case focused on
exercising containsSortedPath with unsorted input and use the existing assertion
style.

In `@pkg/templates/cluster_test.go`:
- Around line 57-96: Extend TestClusterExecuterMatchesPerTargetFilters with
cases for severity filtering and restricted template paths. Prepare a severity
filter and assert operatorMatchesTargetFilter accepts the matching apache
operator and rejects nginx; prepare a restrictTemplates filter containing the
apache template path and assert only the corresponding operator matches,
covering the forwarded MatchesTemplate checks.

In `@pkg/templates/cluster.go`:
- Around line 294-297: Compute the filtered operator set once in Execute before
e.requests.ExecuteWithResults by applying operatorMatchesTargetFilter to
e.operators, then reuse that slice in the event callback and matcher-status
fallback loop. Replace both per-event iterations over e.operators with
activeOperators while preserving existing filtering behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 12916cf8-928e-43fc-a2be-655895ba064d

📥 Commits

Reviewing files that changed from the base of the PR and between 1027207 and 356c56a.

📒 Files selected for processing (22)
  • internal/runner/preflight_portscan.go
  • internal/runner/preflight_portscan_test.go
  • internal/runner/runner.go
  • internal/runner/target_filters.go
  • internal/runner/target_filters_test.go
  • internal/tests/integration/target_jsonl_test.go
  • pkg/core/execute_options.go
  • pkg/core/executors.go
  • pkg/core/executors_test.go
  • pkg/input/README.md
  • pkg/input/formats/formats.go
  • pkg/input/formats/json/json.go
  • pkg/input/formats/json/json_test.go
  • pkg/input/provider/http/multiformat.go
  • pkg/input/provider/http/multiformat_target_test.go
  • pkg/input/provider/interface.go
  • pkg/protocols/common/contextargs/metainput.go
  • pkg/protocols/common/contextargs/metainput_test.go
  • pkg/protocols/common/contextargs/target_filter.go
  • pkg/protocols/common/contextargs/target_filter_test.go
  • pkg/templates/cluster.go
  • pkg/templates/cluster_test.go

Comment thread internal/runner/runner.go
Comment thread pkg/input/README.md
Comment thread pkg/protocols/common/contextargs/target_filter.go
Comment thread internal/runner/target_filters.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
pkg/protocols/common/contextargs/target_filter_test.go (1)

95-113: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Strengthen the preparation test assertions.

This test verifies matching outcomes, but it does not directly verify the normalized and sorted effectiveTemplates or effectiveIncludes collections. It also tests forced inclusions without restrictive tags, exclusions, or severities, so it does not prove that inclusions override those filters. Assert the prepared collections directly and add restrictive criteria to the forced-path cases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/protocols/common/contextargs/target_filter_test.go` around lines 95 -
113, Strengthen TestTargetFilterPrepareNormalizesTemplatePaths by directly
asserting the sorted, normalized effectiveTemplates and effectiveIncludes
collections after Prepare. Update the forced-path MatchesTemplate cases to use
restrictive tags, exclusions, and severities, verifying forced inclusions still
match despite those filters, while retaining the non-matching template
assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/protocols/common/contextargs/target_filter_test.go`:
- Around line 95-113: Strengthen TestTargetFilterPrepareNormalizesTemplatePaths
by directly asserting the sorted, normalized effectiveTemplates and
effectiveIncludes collections after Prepare. Update the forced-path
MatchesTemplate cases to use restrictive tags, exclusions, and severities,
verifying forced inclusions still match despite those filters, while retaining
the non-matching template assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2cf1fd5d-4dc8-49b6-af59-fc1e3ab0ae99

📥 Commits

Reviewing files that changed from the base of the PR and between 356c56a and 084d83b.

📒 Files selected for processing (3)
  • pkg/input/README.md
  • pkg/protocols/common/contextargs/target_filter.go
  • pkg/protocols/common/contextargs/target_filter_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/input/README.md
  • pkg/protocols/common/contextargs/target_filter.go

@3nesdeniz

Copy link
Copy Markdown
Author

Addressed the remaining CodeRabbit nitpick in eb1b14c: TestTargetFilterPrepareNormalizesTemplatePaths now asserts the sorted, filepath.Cleaned effectiveTemplates/effectiveIncludes directly, and the forced-include cases carry a restrictive tag, exclude-tag, and severity to prove inclusions override those filters. Out-of-set rejection under restrictTemplates is retained.

Reject absolute paths and parent-directory traversal in per-target JSONL
`templates` selectors so a targets file cannot direct the loader at arbitrary
local files (CWE-22). Global -t/-it selectors remain unrestricted trusted CLI
input.
@coderabbitai coderabbitai Bot mentioned this pull request Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adds support for input adapted to different goals

1 participant