Skip to content

Comments

Support concurrent Nuclei engines in the same process#6322

Merged
ehsandeep merged 14 commits intoprojectdiscovery:devfrom
hdm:bug/various-race-conditions-2
Jul 18, 2025
Merged

Support concurrent Nuclei engines in the same process#6322
ehsandeep merged 14 commits intoprojectdiscovery:devfrom
hdm:bug/various-race-conditions-2

Conversation

@hdm
Copy link
Contributor

@hdm hdm commented Jul 15, 2025

Proposed changes

This PR includes a handful of improvements that make it possible to run multiple Nuclei engines concurrently without data races. This PR also makes some progress on a reusable template cache, but that work isn't quite usable yet, and each engine needs its own parser stil.

One item open is how to handle the LfaAllowed global. This line in protocolstate/state.go still triggers a race unless commented out:

LfaAllowed = options.AllowLocalFileAccess

This one is tricky to fix since many things check for this variable without having an executionId handy (javascript fs module, etc.).

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

    • Introduced synchronized access to local file access permissions with new functions for getting and setting these permissions.
    • Added utility for capturing log output, useful for testing.
    • Added methods to access compiled cache and count parsed/compiled templates.
  • Bug Fixes

    • Improved thread safety in DNS and WHOIS client pools.
    • Prevented unintended modification of global HTTP client options.
  • Refactor

    • Enhanced template parsing to avoid mutating cached templates.
    • Simplified and centralized permission and synchronization logic across protocols.
    • Removed unused or redundant methods and fields for cleaner codebase.
    • Improved client pool synchronization by adopting centralized concurrency controls.
    • Updated file system functions to utilize context-based path normalization.
  • Tests

    • Improved test reliability by capturing and inspecting logger output, with better handling of GitHub API rate limits.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 15, 2025

Walkthrough

The changes introduce thread-safe handling for local file access permissions using synchronized maps keyed by execution ID, refactor client pool synchronization using concurrency-safe maps and helper functions, and update template parsing logic to avoid in-place mutations of cached templates by working on deep copies. Obsolete methods and direct global state mutations are removed. Minor documentation, test improvements, and logging capture utilities are also added.

Changes

File(s) Change Summary
lib/config.go Updated comment for WithLogger to clarify it sets a shared logger instance.
lib/sdk_private.go Enhanced NucleiEngine parser initialization to assign parser instance consistently across fields.
pkg/installer/template.go Changed table.Header call to pass a string slice instead of variadic string arguments.
pkg/protocols/common/protocolstate/file.go Changed LfaAllowed from bool to synchronized map keyed by execution ID; added IsLfaAllowed, SetLfaAllowed, GetLfaAllowed; updated NormalizePath to use options and local file access checks.
pkg/protocols/common/protocolstate/headless.go Removed IsLfaAllowed function.
pkg/protocols/common/protocolstate/state.go Replaced direct assignment of LfaAllowed with call to SetLfaAllowed in initDialers.
pkg/protocols/dns/dnsclientpool/clientpool.go Replaced manual map and mutex with SyncLockMap for clientPool; added getNormalClient() with mutex; centralized synchronization.
pkg/protocols/http/httpclientpool/clientpool.go Modified GetRawHTTP to use a copy of default options to avoid mutating global defaults.
pkg/protocols/protocols.go Removed mutex and SetExecutionID from ExecutorOptions; refactored ApplyNewEngineOptions to replace options and copy fields; ensured templateCtxStore initialization in GetTemplateCtx.
pkg/protocols/whois/rdapclientpool/clientpool.go Added getNormalClient() helper for mutex-protected access; simplified Get method.
pkg/templates/compile.go Changed template parsing to work on deep copies of cached templates and requests; isolated cache from runtime mutations.
pkg/templates/parser.go Removed CloneForExecutionId and helper function; added CompiledCache(), ParsedCount(), and CompiledCount() accessor methods.
pkg/external/customtemplates/github_test.go Improved test output capture using CaptureWriter; removed macOS skip; added GitHub API rate limit detection.
pkg/utils/capture_writer.go Added CaptureWriter struct to capture log output with a Write method for testing purposes.
pkg/js/libs/fs/fs.go Updated file system functions to accept context.Context; path normalization now uses execution ID from context.

Sequence Diagram(s)

sequenceDiagram
    participant Engine as NucleiEngine
    participant Options as EngineOptions
    participant Parser as Parser

    Engine->>Options: Check for Parser instance
    alt Parser provided and valid
        Engine->>Parser: Assign Parser to internal fields
    else No Parser provided
        Engine->>Parser: Create new Parser
        Engine->>Parser: Assign new Parser to internal fields
    end
Loading
sequenceDiagram
    participant TemplateCache as CachedTemplate
    participant ParseFunc as Parse
    participant NewOptions as ExecutorOptions

    ParseFunc->>TemplateCache: Retrieve cached template
    ParseFunc->>TemplateCache: Deep copy cached template
    ParseFunc->>NewOptions: Create ExecutorOptions with preserved fields
    ParseFunc->>TemplateCache: Assign new options to copied template
    ParseFunc->>TemplateCache: Update requests with copied options
    ParseFunc-->>Caller: Return copied template
Loading
sequenceDiagram
    participant ProtocolState as protocolstate
    participant Options as Options
    participant AtomicFlag as LfaAllowed

    ProtocolState->>Options: IsLfaAllowed(options)
    alt options provided
        ProtocolState->>Dialer: Check LocalFileAccessAllowed under lock
    else
        ProtocolState->>AtomicFlag: Return atomic global flag
    end
Loading

Possibly related PRs

Suggested reviewers

  • dogancanbakir

Poem

In the warren where code bunnies leap,
We guard our caches, no secrets to keep.
With locks and maps, we hop thread-safe,
No global state left in a dangerous place.
Each template now fresh, each client in line—
Our code is as tidy as a rabbit's burrow, divine!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@hdm hdm marked this pull request as ready for review July 16, 2025 18:11
@auto-assign auto-assign bot requested a review from dwisiswant0 July 16, 2025 18:11
@hdm
Copy link
Contributor Author

hdm commented Jul 16, 2025

It looks like the test failure yesterday was due to a temporary quota hit:

panic: [:RUNTIME] failed to install templates at /home/runner/nuclei-templates <- [:RUNTIME] failed to install templates at /home/runner/nuclei-templates <- [:RUNTIME] hit github ratelimit while downloading latest release <- GET https://api.github.com/repos/projectdiscovery/nuclei-templates/releases/latest: 403 API rate limit exceeded for 172.214.45.197. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.) [rate reset in 32m14s]

The current PR should be ready for review

@dwisiswant0 dwisiswant0 requested a review from Mzack9999 July 16, 2025 18:15
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🔭 Outside diff range comments (1)
pkg/protocols/common/protocolstate/state.go (1)

181-181: Ensure consistent use of the per-instance LocalFileAccessAllowed flag

Right now we have two separate settings for local-file access:

  1. A global LfaAllowed in file.go (with its own mutex)
  2. A per-execution LocalFileAccessAllowed on each dialers instance

Because file.go first returns the global flag and only falls back to the per-instance value, you can get different answers depending on which API is called. To fix this, drop the global flag entirely and always consult the instance field:

• pkg/protocols/common/protocolstate/file.go
– Remove the LfaAllowed variable, its mutex, and SetLfaAllowed/GetLfaAllowed logic
– In all exported funcs (e.g. IsLocalFileAccessAllowed), look up the dialers entry by ExecutionId and return its LocalFileAccessAllowed

• pkg/protocols/common/protocolstate/state.go & headless.go
– Continue initializing LocalFileAccessAllowed: options.AllowLocalFileAccess on the per-execution struct
– Delete the call to SetLfaAllowed(options) in state.go

This will guarantee a single source of truth for local-file access.

🧹 Nitpick comments (3)
pkg/protocols/dns/dnsclientpool/clientpool.go (1)

14-18: Consider using consistent mutex declaration style.

For consistency with poolMutex, consider declaring m as a pointer:

-var (
-	poolMutex  *sync.RWMutex
-	clientPool map[string]*retryabledns.Client
-
-	normalClient *retryabledns.Client
-	m            sync.Mutex
-)
+var (
+	poolMutex  *sync.RWMutex
+	clientPool map[string]*retryabledns.Client
+
+	normalClient *retryabledns.Client
+	m            *sync.Mutex
+)

And initialize it in the Init function:

 func Init(options *types.Options) error {
+	if m == nil {
+		m = &sync.Mutex{}
+	}
 	m.Lock()
 	defer m.Unlock()

Also, the reordering of poolMutex and clientPool declarations seems unnecessary. Was there a specific reason for this change?

pkg/protocols/protocols.go (1)

454-462: Remove commented code.

If these template-specific fields are intentionally preserved (not replaced), please add a clear comment explaining why. Otherwise, remove the commented code to improve readability.

-	// Keep the template-specific fields, but replace the rest
-	/*
-		e.TemplateID = n.TemplateID
-		e.TemplatePath = n.TemplatePath
-		e.TemplateInfo = n.TemplateInfo
-		e.TemplateVerifier = n.TemplateVerifier
-		e.RawTemplate = n.RawTemplate
-		e.Variables = n.Variables
-		e.Constants = n.Constants
-	*/
+	// Keep the template-specific fields unchanged while replacing execution-related fields
pkg/templates/compile.go (1)

163-164: Consider enabling debug logging for cache operations

The commented debug log would be valuable for troubleshooting concurrent execution issues. Consider making it configurable rather than commenting it out.

-// options.Logger.Error().Msgf("returning cached template %s after recompiling %d requests", tplCopy.Options.TemplateID, tplCopy.Requests())
+if options.Options.Debug {
+    gologger.Debug().Msgf("returning cached template %s after updating %d requests", tplCopy.Options.TemplateID, tplCopy.Requests())
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1079498 and b94462d.

📒 Files selected for processing (15)
  • lib/config.go (1 hunks)
  • lib/sdk_private.go (1 hunks)
  • pkg/installer/template.go (1 hunks)
  • pkg/protocols/common/protocolstate/file.go (1 hunks)
  • pkg/protocols/common/protocolstate/headless.go (0 hunks)
  • pkg/protocols/common/protocolstate/memguardian.go (2 hunks)
  • pkg/protocols/common/protocolstate/state.go (1 hunks)
  • pkg/protocols/dns/dnsclientpool/clientpool.go (4 hunks)
  • pkg/protocols/http/httpclientpool/clientpool.go (1 hunks)
  • pkg/protocols/http/request.go (1 hunks)
  • pkg/protocols/http/utils.go (1 hunks)
  • pkg/protocols/protocols.go (2 hunks)
  • pkg/protocols/whois/rdapclientpool/clientpool.go (2 hunks)
  • pkg/templates/compile.go (2 hunks)
  • pkg/templates/parser.go (1 hunks)
💤 Files with no reviewable changes (1)
  • pkg/protocols/common/protocolstate/headless.go
🧰 Additional context used
🧠 Learnings (2)
pkg/protocols/http/utils.go (1)
Learnt from: dwisiswant0
PR: projectdiscovery/nuclei#6290
File: pkg/protocols/http/build_request.go:457-464
Timestamp: 2025-06-30T16:34:42.125Z
Learning: In the projectdiscovery/retryablehttp-go package, the Request struct embeds URL fields directly, making req.Scheme, req.Host, and other URL fields accessible directly on the Request object instead of requiring req.URL.Scheme, req.URL.Host, etc.
pkg/protocols/http/request.go (1)
Learnt from: dwisiswant0
PR: projectdiscovery/nuclei#6290
File: pkg/protocols/http/build_request.go:457-464
Timestamp: 2025-06-30T16:34:42.125Z
Learning: In the projectdiscovery/retryablehttp-go package, the Request struct embeds URL fields directly, making req.Scheme, req.Host, and other URL fields accessible directly on the Request object instead of requiring req.URL.Scheme, req.URL.Host, etc.
🧬 Code Graph Analysis (3)
pkg/protocols/common/protocolstate/state.go (1)
pkg/protocols/common/protocolstate/file.go (1)
  • SetLfaAllowed (38-45)
pkg/protocols/http/request.go (1)
pkg/protocols/http/http.go (1)
  • Request (35-240)
pkg/templates/parser.go (2)
pkg/loader/parser/parser.go (1)
  • Parser (7-11)
pkg/templates/cache.go (1)
  • Cache (9-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Tests (windows-latest)
🔇 Additional comments (15)
pkg/protocols/common/protocolstate/memguardian.go (3)

19-19: LGTM: Global mutex properly declared for thread safety.

The global mutex declaration is correctly placed and follows Go conventions. This provides the necessary synchronization primitive for protecting global state changes across concurrent operations.


23-24: LGTM: Proper mutex usage for thread-safe guardian startup.

The mutex lock with defer unlock pattern correctly protects the global state modifications (memTimer and cancelFunc). The use of defer ensures the mutex is always released, even on early returns.


48-50: LGTM: Proper mutex usage for thread-safe guardian shutdown.

The mutex lock with defer unlock pattern correctly protects the global state modifications during shutdown. This ensures that start and stop operations are properly serialized and cannot interfere with each other.

lib/config.go (1)

540-540: Good documentation improvement.

The comment clarification that WithLogger allows setting a "shared" gologger instance is helpful and aligns with the PR's goal of supporting concurrent engines in the same process.

pkg/protocols/http/utils.go (1)

15-16: Excellent race condition fix.

Cloning the request before dumping prevents race conditions with the HTTP transport when multiple goroutines access the same request object. This is a critical improvement for concurrent engine support.

pkg/protocols/whois/rdapclientpool/clientpool.go (2)

33-37: Good thread-safety encapsulation.

The getNormalClient() function properly encapsulates mutex locking around access to the shared normalClient variable, ensuring thread-safe access in concurrent scenarios.


49-49: Proper use of the thread-safe accessor.

Using getNormalClient() instead of direct access ensures consistent thread-safe access to the shared client instance.

pkg/installer/template.go (1)

56-56: Correct API usage fix.

The change from variadic arguments to a slice parameter aligns with the expected table.Header method signature.

pkg/protocols/http/httpclientpool/clientpool.go (1)

157-166: Excellent isolation improvement.

Creating a local copy of rawhttp.DefaultOptions before modification prevents race conditions and side effects when multiple engines run concurrently. This ensures each operation works with its own isolated options instead of mutating shared global state.

pkg/protocols/http/request.go (1)

867-870: Good fix for preventing race conditions!

Cloning the request before modifying its body prevents potential race conditions with the HTTP transport. This is the correct approach for safely generating the curl command.

pkg/templates/parser.go (1)

57-67: LGTM! Thread-safe accessor methods.

The new accessor methods ParsedCount() and CompiledCount() are properly implemented with appropriate locking to ensure thread safety when accessing the cache maps.

pkg/protocols/protocols.go (1)

198-201: Good defensive programming!

Initializing templateCtxStore if nil prevents potential nil pointer dereferences and ensures the method is safe to call even if CreateTemplateCtxStore() wasn't called first.

pkg/protocols/common/protocolstate/state.go (1)

203-203: Good fix for the race condition.

Replacing the direct assignment to the global LfaAllowed variable with the thread-safe SetLfaAllowed(options) function call properly addresses the race condition issue mentioned in the PR objectives.

pkg/protocols/common/protocolstate/file.go (2)

62-66: Good use of the new thread-safe accessor.

The update to use IsLfaAllowed(nil) instead of directly accessing the global LfaAllowed variable is correct and maintains backward compatibility while adding thread safety.


19-36: No action required: Dialers mutex and nil guards are correct

The Dialers struct embeds sync.Mutex, so calling dialers.Lock()/Unlock() is idiomatic and safe. Additionally, IsLfaAllowed already checks dialers != nil (along with ok) before acquiring the lock. The use of the shared dialers state here is intentional. Please disregard the previous concerns about synchronization and nil handling.

Likely an incorrect or invalid review comment.

hdm and others added 2 commits July 16, 2025 16:28
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@Mzack9999
Copy link
Member

@coderabbitai resolve

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 17, 2025

✅ Actions performed

Comments resolved.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
Makefile (2)

78-81: -failfast may mask additional regressions; make it opt-in via env var

Halting the test suite on the first failure speeds up CI feedback, but it also prevents spotting independent failures in the same run. CI logs that surface all failing packages in one shot are often more useful for triage.

Consider keeping the flag configurable instead of hard-coded:

-	$(GOTEST) $(GOFLAGS) -failfast -p 1 ./...
+TEST_EXTRA_FLAGS ?=
+	$(GOTEST) $(GOFLAGS) $(TEST_EXTRA_FLAGS) ./...

Developers can still run make test TEST_EXTRA_FLAGS="-failfast" locally, while CI can execute the full matrix.


78-81: Serialising packages with -p 1 slows CI and hides cross-package races

Setting -p 1 disables the default per-package parallelism that often uncovers race conditions spanning shared resources. Given that this PR’s goal is to make the engine race-free, running tests in parallel packages is actually desirable as a safety net.

If the motivation is to reduce flakiness for now, consider gating this with an environment toggle similar to the previous note, or at least add a TODO to remove once outstanding races are fixed.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3fb1d4 and 6d3c943.

📒 Files selected for processing (1)
  • Makefile (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: hdm
PR: projectdiscovery/nuclei#6322
File: pkg/templates/compile.go:79-81
Timestamp: 2025-07-16T21:27:14.897Z
Learning: To make the template caching mechanism in pkg/templates/compile.go production-ready, DSLs need to be updated to use runtime options instead of cached variables, rather than restoring the Compile() calls on each request.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
pkg/external/customtemplates/github_test.go (1)

24-26: Consider removing commented code if the macOS issue is resolved.

The commented skip logic suggests the macOS-specific failure has been addressed. Consider removing this commented code entirely if the issue is permanently resolved.

-	// if osutils.IsOSX() {
-	// 	t.Skip("skipping on macos due to unknown failure (works locally)")
-	// }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6d3c943 and aa9cc26.

📒 Files selected for processing (1)
  • pkg/external/customtemplates/github_test.go (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: hdm
PR: projectdiscovery/nuclei#6322
File: pkg/templates/compile.go:79-81
Timestamp: 2025-07-16T21:27:14.897Z
Learning: To make the template caching mechanism in pkg/templates/compile.go production-ready, DSLs need to be updated to use runtime options instead of cached variables, rather than restoring the Compile() calls on each request.
pkg/external/customtemplates/github_test.go (2)
Learnt from: hdm
PR: projectdiscovery/nuclei#6322
File: pkg/templates/compile.go:79-81
Timestamp: 2025-07-16T21:27:14.897Z
Learning: In pkg/templates/compile.go, the template caching mechanism intentionally skips calling Compile() on copied requests to achieve performance benefits. This is the intended design, not a bug. The current implementation isn't production-ready but represents the desired direction.
Learnt from: hdm
PR: projectdiscovery/nuclei#6322
File: pkg/templates/compile.go:59-78
Timestamp: 2025-07-16T21:28:08.062Z
Learning: The shallow copy behavior (`tplCopy := *value`) in pkg/templates/compile.go is intentional design for the template caching mechanism. The partial-copy approach is part of the performance optimization strategy, not a bug requiring deep copying.
🔇 Additional comments (4)
pkg/external/customtemplates/github_test.go (4)

5-5: LGTM: Import added for stdout writer implementation.

The os import is correctly added to support the new stdoutWriter type.


10-10: LGTM: Import added for logging level types.

The levels import is correctly added to support the enhanced logging functionality.


16-21: LGTM: Clean adapter implementation for stdout logging.

The stdoutWriter type correctly implements the gologger writer interface, providing a simple way to direct log output to stdout for test debugging.


28-29: LGTM: Enhanced logging setup improves test observability.

The logger configuration with debug level and stdout writer will provide better visibility into test execution, which is valuable for debugging the GitHub template download functionality.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
pkg/utils/capture_writer.go (1)

14-16: Consider thread safety and document the ignored level parameter.

The Write method implementation is straightforward, but there are a few considerations:

  1. Thread safety: bytes.Buffer is not thread-safe. If this will be used in concurrent scenarios, consider adding synchronization.
  2. Ignored level parameter: The level parameter is ignored, which may be intentional for testing but should be documented.
  3. Error handling: While bytes.Buffer.Write never returns an error, the method signature suggests it might be implementing an interface that expects error handling.

Consider documenting the behavior:

-func (w *CaptureWriter) Write(data []byte, level levels.Level) {
+// Write appends data to the buffer, ignoring the log level for testing purposes
+func (w *CaptureWriter) Write(data []byte, level levels.Level) {
 	w.Buffer.Write(data)
 }

If thread safety is needed:

+import "sync"
+
 type CaptureWriter struct {
 	Buffer *bytes.Buffer
+	mu     sync.Mutex
 }

 func (w *CaptureWriter) Write(data []byte, level levels.Level) {
+	w.mu.Lock()
+	defer w.mu.Unlock()
 	w.Buffer.Write(data)
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aa9cc26 and f0dfda6.

📒 Files selected for processing (2)
  • pkg/external/customtemplates/github_test.go (2 hunks)
  • pkg/utils/capture_writer.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/external/customtemplates/github_test.go
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: hdm
PR: projectdiscovery/nuclei#6322
File: pkg/templates/compile.go:79-81
Timestamp: 2025-07-16T21:27:14.897Z
Learning: To make the template caching mechanism in pkg/templates/compile.go production-ready, DSLs need to be updated to use runtime options instead of cached variables, rather than restoring the Compile() calls on each request.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Tests (windows-latest)
  • GitHub Check: Tests (macOS-latest)
  • GitHub Check: Tests (ubuntu-latest)
🔇 Additional comments (2)
pkg/utils/capture_writer.go (2)

1-7: Clean package structure and appropriate imports.

The package declaration and imports are well-organized. The dependency on github.com/projectdiscovery/gologger/levels correctly reflects the method signature requirements.


9-12: Simple and focused struct design.

The CaptureWriter struct is well-designed for its testing purpose with a clear comment explaining its intent. Using a pointer to bytes.Buffer is appropriate for efficiency.

@Mzack9999
Copy link
Member

Follow ups:

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🔭 Outside diff range comments (1)
pkg/js/libs/fs/fs.go (1)

3-8: Add fmt import for error handling.

The fmt package import is needed for the suggested error handling improvements in the context value extraction.

Apply this diff to add the missing import:

 import (
 	"context"
+	"fmt"
 	"os"
 
 	"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
 )
♻️ Duplicate comments (1)
pkg/js/libs/fs/fs.go (1)

62-64: Add safe context value extraction to prevent runtime panics.

Same issue as in ListDir - the direct type assertion could panic if the context doesn't contain the expected key or value type.

Apply the same fix as suggested for ListDir:

-	executionId := ctx.Value("executionId").(string)
+	executionId, ok := ctx.Value("executionId").(string)
+	if !ok || executionId == "" {
+		return nil, fmt.Errorf("missing or invalid executionId in context")
+	}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40f37a9 and b56b477.

📒 Files selected for processing (2)
  • pkg/js/libs/fs/fs.go (5 hunks)
  • pkg/protocols/common/protocolstate/file.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/protocols/common/protocolstate/file.go
🧰 Additional context used
🧠 Learnings (1)
pkg/js/libs/fs/fs.go (2)
Learnt from: dwisiswant0
PR: projectdiscovery/nuclei#6290
File: pkg/fuzz/component/path_test.go:43-44
Timestamp: 2025-06-30T16:33:26.746Z
Learning: The user dwisiswant0 declined adding documentation for internal API changes in pkg/fuzz/component/path when the change was from nested URL field access (rebuilt.URL.Path, rebuilt.URL.String()) to direct field access (rebuilt.Path, rebuilt.String()), indicating they don't consider additional documentation necessary for such internal API modifications.
Learnt from: hdm
PR: projectdiscovery/nuclei#6322
File: pkg/protocols/common/protocolstate/file.go:38-55
Timestamp: 2025-07-16T21:31:43.240Z
Learning: In pkg/protocols/common/protocolstate/file.go, the inconsistent behavior between SetLfaAllowed, GetLfaAllowed, and IsLfaAllowed functions is intentional as an interim step before implementing context-specific LFA logic. The current mixed approach of global and per-instance flags is a temporary transitional state, not a design flaw.
🧬 Code Graph Analysis (1)
pkg/js/libs/fs/fs.go (1)
pkg/protocols/common/protocolstate/file.go (1)
  • NormalizePathWithExecutionId (51-56)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Tests (ubuntu-latest)
  • GitHub Check: Tests (macOS-latest)
  • GitHub Check: Tests (windows-latest)
🔇 Additional comments (3)
pkg/js/libs/fs/fs.go (3)

80-81: Good delegation pattern for context propagation.

The function correctly delegates to ReadFile and passes the context through, avoiding duplication of the executionId extraction logic.


97-104: Consistent context propagation throughout the call chain.

The function correctly propagates the context parameter to both ListDir and ReadFileAsString calls, maintaining consistency with the new context-aware API.


1-112: Overall assessment: Good alignment with concurrent execution objectives.

The changes successfully transition the fs library to be context-aware, supporting the PR's objective of enabling concurrent Nuclei engines. The consistent pattern of extracting executionId from context and using NormalizePathWithExecutionId is well-implemented.

The main concern is the unsafe type assertions that could cause runtime panics in production environments. Once the context value extraction is made safer, these changes will provide a solid foundation for execution ID-based path normalization and local file access control.

@ehsandeep
Copy link
Member

@coderabbitai create github issue for this and link this PR in issue.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 18, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@ehsandeep, I'll create a GitHub issue for the multi-threading client pools follow-up and link this PR.


🏁 Script executed:

#!/bin/bash
# Create GitHub issue for multi-threading client pools follow-up
gh issue create \
  --title "Multi-threading client pools" \
  --body "This is a follow-up item from PR #6322 which introduced concurrent Nuclei engines support.

## Context
PR #6322 implemented support for concurrent Nuclei engines in the same process, but identified multi-threading client pools as an area for further improvement.

## Related
- Original issue: #6329
- Related PR: #6322

## Description
Investigate and implement proper multi-threading support for client pools to further enhance concurrent execution capabilities.

---
*This issue was created as a follow-up to PR #6322.*" \
  --assignee ehsandeep

Length of output: 662


@ehsandeep, I've successfully created GitHub issue #6334 for the multi-threading client pools follow-up. The issue includes:

Issue URL: #6334

🐇✨

  /|   /|   
 ( :v:  )
  |(_)|

@ehsandeep ehsandeep merged commit 5b89811 into projectdiscovery:dev Jul 18, 2025
22 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jul 30, 2025
4 tasks
Ice3man543 pushed a commit that referenced this pull request Aug 2, 2025
* support for concurrent nuclei engines

* clarify LfaAllowed race

* remove unused mutex

* update LfaAllowed logic to prevent races until it can be reworked for per-execution ID

* Update pkg/templates/parser.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* debug tests

* debug gh action

* fixig gh template test

* using atomic

* using synclockmap

* restore tests concurrency

* lint

* wiring executionId in js fs

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Mzack9999 <mzack9999@protonmail.com>
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.

4 participants