Skip to content

Conversation

Mzack9999
Copy link
Member

@Mzack9999 Mzack9999 commented Aug 21, 2025

Proposed changes

Close #6409

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

    • Browse RSYNC servers: list available modules and files within a module; supports host/port and optional credentials.
    • Responses include captured RSYNC driver output for easier inspection.
  • Tests

    • Added RSYNC-based JavaScript integration test (disabled on Windows/macOS) that runs a temporary RSYNC server and verifies results.
  • Chores

    • Updated dependencies to support RSYNC functionality.

Copy link
Contributor

coderabbitai bot commented Aug 21, 2025

Walkthrough

Adds two go.mod dependencies and implements an RsyncClient with ListModules and ListFilesInModule, centralized fast-dial connection helper, captured rsync driver output, and modified isRsync error handling to suppress plugin errors.

Changes

Cohort / File(s) Summary
Dependencies (go.mod)
go.mod
Added dependencies: github.com/Mzack9999/go-rsync v0.0.0-20250821180103-81ffa574ef4d (direct) and github.com/kaiakz/ubuffer ... (indirect). No other module or path changes.
RSYNC client feature & flow updates
pkg/js/libs/rsync/rsync.go
Added RsyncClient and RsyncListResponse; implemented ListModules and ListFilesInModule with optional username/password; added connectWithFastDialer and replaced direct dials in isRsync; capture driver output into response; changed isRsync to suppress plugin errors.
Integration tests: JS rsync testcase & docker resource
cmd/integration-test/javascript.go
Added an rsync integration test case (javascriptRsyncTest), rsyncResource Docker setup (Alpine rsync daemon), test registration in jsTestcases, and test execution logic with retries and resource purge.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor JS as JS Caller
  participant RC as RsyncClient
  participant Dial as Fast Dialer
  participant RS as rsynclib

  rect rgb(240,248,255)
  note over JS,RC: List modules
  JS->>RC: ListModules(ctx, host, port, user, pass)
  RC->>Dial: connectWithFastDialer(host:port)
  Dial-->>RC: net.Conn / error
  RC->>RS: ListModules(conn, creds?)
  RS-->>RC: modules[], logs
  RC-->>JS: RsyncListResponse{Modules, Output}
  end

  rect rgb(245,255,240)
  note over JS,RC: List files in module
  JS->>RC: ListFilesInModule(ctx, host, port, user, pass, module)
  RC->>Dial: connectWithFastDialer(host:port)
  Dial-->>RC: net.Conn / error
  RC->>RS: SocketClient(conn, module, creds?)
  RS-->>RC: files[], logs
  RC-->>JS: RsyncListResponse{Files, Output}
  end

  opt Plugin check path
    JS->>RC: isRsync(...)
    RC->>Dial: connectWithFastDialer(...)
    Dial-->>RC: conn / error
    RC->>RS: plugin.Run(...)
    note right of RC: On plugin error, function now returns nil error (suppressed)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Assessment against linked issues

Objective Addressed Explanation
Authentication with username and password (#6409) Methods accept username/password but it's unclear if credentials are actually used by rsynclib calls (no explicit credential negotiation visible).
List Modules (#6409)
List Shares (#6409) No implementation that explicitly lists "shares"; only modules and files within modules are provided.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Suppress plugin error return in isRsync (pkg/js/libs/rsync/rsync.go) Changing isRsync to return nil on plugin.Run failures alters detection semantics and is not part of the authentication/modules/files objectives.

I thump my paws on code today,
New modules hop in tidy array,
With secret crumbs and log-lit cheer,
I list the paths both far and near,
Hoppity-hop—rsync, lend your ear! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-6409-rsync-auth

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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

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

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@Mzack9999 Mzack9999 marked this pull request as ready for review August 25, 2025 17:56
@auto-assign auto-assign bot requested a review from dwisiswant0 August 25, 2025 17:56
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: 6

🧹 Nitpick comments (8)
pkg/js/libs/rsync/rsync.go (8)

20-28: Docstring references gokrazy driver but the code imports a different fork

Comment says “Internally client uses https://github.com/gokrazy/rsync driver,” but imports point to github.com/Mzack9999/go-rsync/rsync. Please align the docs to avoid confusion (e.g., clarify it's a fork of gokrazy, if applicable).

- // Internally client uses https://github.com/gokrazy/rsync driver.
+ // Internally the client uses a forked rsync driver (github.com/Mzack9999/go-rsync),
+ // originally based on gokrazy/rsync.

42-54: Inconsistent naming in docs (“ListSharesResponse”, “ListShares”) vs actual API

The type is RsyncListResponse and the methods are ListModules / ListFilesInModule, but comments and examples mention “ListSharesResponse” and ListShares. Please fix wording to reflect the exported API.

- // ListSharesResponse is the response from the ListShares function.
- // this is returned by ListShares function.
+ // RsyncListResponse is returned by ListModules and ListFilesInModule.

57-63: Propagate context to the fast dialer instead of using context.Background()

Using context.Background() ignores caller cancellations/timeouts. Thread the ctx down for better control, especially inside scans.

-func connectWithFastDialer(executionId string, host string, port int) (net.Conn, error) {
+func connectWithFastDialer(ctx context.Context, executionId string, host string, port int) (net.Conn, error) {
   dialer := protocolstate.GetDialersWithId(executionId)
   if dialer == nil {
     return nil, fmt.Errorf("dialers not initialized for %s", executionId)
   }
-  return dialer.Fastdialer.Dial(context.Background(), "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
+  return dialer.Fastdialer.Dial(ctx, "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
}

And in the only call site:

-conn, err := connectWithFastDialer(executionId, host, port)
+conn, err := connectWithFastDialer(context.Background(), executionId, host, port)

If feasible, also thread the original ctx from IsRsync into isRsync to respect upstream cancellations/timeouts.


93-94: Swallowing plugin errors alters semantics and hinders troubleshooting

Returning nil on rsyncPlugin.Run error makes it indistinguishable from “not rsync.” If intentional, add a debug log or metric so users can differentiate transport/plugin failures from clean negatives. Otherwise, consider returning a wrapped error.

-  if err != nil {
-    return resp, nil
-  }
+  if err != nil {
+    // Treat as negative but record reason for diagnostics.
+    // TODO: emit debug log/metric here if available.
+    return resp, nil
+  }

Would you like me to wire a debug logger here behind a global/debug flag?


148-152: Don’t send empty credentials; build options conditionally

Passing WithClientAuth("", "") may change server behavior (e.g., provoke auth or lockouts). Build options slice and only add auth when provided.

- sr, err := rsynclib.ListModules(address,
-   rsynclib.WithClientAuth(username, password),
-   rsynclib.WithLogger(logger),
-   rsynclib.WithFastDialer(fastDialer.Fastdialer),
- )
+ opts := []rsynclib.Option{rsynclib.WithFastDialer(fastDialer.Fastdialer)}
+ opts = append(opts, rsynclib.WithLogger(logger))
+ if username != "" || password != "" {
+   opts = append(opts, rsynclib.WithClientAuth(username, password))
+ }
+ sr, err := rsynclib.ListModules(address, opts...)

169-187: DRY: repeated logger construction

The bytes.Buffer + slog.TextHandler boilerplate is duplicated in both list functions. Consider a small helper that returns (logger *slog.Logger, getOutput func() string) to centralize redaction/capping as well.

I can provide a small newBufferedLogger() helper if you want me to push a patch.


188-193: Same as above: conditional auth, plus ensure client cleanup

Build options conditionally and ensure the client is closed if the driver exposes a Close/Disconnect method to avoid leaks.

- sr, err := rsynclib.SocketClient(nil, address, module, ".",
-   rsynclib.WithClientAuth(username, password),
-   rsynclib.WithLogger(logger),
-   rsynclib.WithFastDialer(fastDialer.Fastdialer),
- )
+ opts := []rsynclib.Option{rsynclib.WithFastDialer(fastDialer.Fastdialer), rsynclib.WithLogger(logger)}
+ if username != "" || password != "" {
+   opts = append(opts, rsynclib.WithClientAuth(username, password))
+ }
+ sr, err := rsynclib.SocketClient(nil, address, module, ".", opts...)
+ // If the client exposes Close(), ensure we don't leak the connection:
+ // defer sr.Close()

Please verify whether the returned client type has a Close() method and add a defer accordingly.


197-201: Error message may over-attribute failures to auth

sr.List() can fail for reasons beyond authentication (permissions, module path, network hiccups). Consider a more neutral message.

- return RsyncListResponse{}, fmt.Errorf("authentication failed: %v", err)
+ return RsyncListResponse{}, fmt.Errorf("list failed (auth/permissions/network): %v", err)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0f7b33c and 36e7701.

⛔ Files ignored due to path filters (4)
  • cmd/nuclei/rsync.yaml is excluded by !**/*.yaml
  • go.sum is excluded by !**/*.sum
  • pkg/js/generated/go/librsync/rsync.go is excluded by !**/generated/**
  • pkg/js/generated/ts/rsync.ts is excluded by !**/generated/**
📒 Files selected for processing (2)
  • go.mod (2 hunks)
  • pkg/js/libs/rsync/rsync.go (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/js/libs/rsync/rsync.go (2)
pkg/protocols/common/protocolstate/state.go (1)
  • GetDialersWithId (39-45)
pkg/js/generated/ts/rsync.ts (3)
  • RsyncClient (25-70)
  • ListModules (53-55)
  • ListFilesInModule (67-69)
⏰ 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 (macOS-latest)
  • GitHub Check: Tests (ubuntu-latest)
  • GitHub Check: Tests (windows-latest)
🔇 Additional comments (1)
go.mod (1)

247-247: No change needed for kubuffer require

Running go mod why -m github.com/kaiakz/ubuffer shows it is pulled in via github.com/Mzack9999/go-rsync (which your module imports) and thus isn’t pruned by go mod tidy. This explicit indirect requirement is required to pin the version for reproducible builds, so it should remain.

Comment on lines +50 to +54
RsyncListResponse struct {
Modules []string
Files []string
Output string
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

JS API mismatch: Go returns RsyncListResponse, TS definitions expect string[]

The generated TS in pkg/js/generated/ts/rsync.ts documents:

  • ListModules(...): string[] | null
  • ListFilesInModule(...): string[] | null

But Go returns RsyncListResponse with { Modules|Files, Output }. This will confuse users and may break typings.

Two options:

  • Update TS signatures and docs to return an object with { modules?: string[]; files?: string[]; output?: string }.
  • Or change Go to return []string and expose logs via a separate debug method/flag.

I can open a follow-up PR to update the TS definitions—let me know.

Comment on lines +111 to +114
func (c *RsyncClient) ListModules(ctx context.Context, host string, port int, username string, password string) (RsyncListResponse, error) {
executionId := ctx.Value("executionId").(string)
return listModules(executionId, host, port, username, password)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid panic on missing executionId in context

Direct type assertion will panic if the key is absent or of the wrong type. Return a clean error instead.

-func (c *RsyncClient) ListModules(ctx context.Context, host string, port int, username string, password string) (RsyncListResponse, error) {
-  executionId := ctx.Value("executionId").(string)
-  return listModules(executionId, host, port, username, password)
-}
+func (c *RsyncClient) ListModules(ctx context.Context, host string, port int, username string, password string) (RsyncListResponse, error) {
+  executionId, ok := ctx.Value("executionId").(string)
+  if !ok || executionId == "" {
+    return RsyncListResponse{}, fmt.Errorf("rsync: missing executionId in context")
+  }
+  return listModules(executionId, host, port, username, password)
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (c *RsyncClient) ListModules(ctx context.Context, host string, port int, username string, password string) (RsyncListResponse, error) {
executionId := ctx.Value("executionId").(string)
return listModules(executionId, host, port, username, password)
}
func (c *RsyncClient) ListModules(ctx context.Context, host string, port int, username string, password string) (RsyncListResponse, error) {
executionId, ok := ctx.Value("executionId").(string)
if !ok || executionId == "" {
return RsyncListResponse{}, fmt.Errorf("rsync: missing executionId in context")
}
return listModules(executionId, host, port, username, password)
}
🤖 Prompt for AI Agents
In pkg/js/libs/rsync/rsync.go around lines 111 to 114, the function uses a
direct type assertion on ctx.Value("executionId").(string) which will panic if
the key is missing or not a string; change it to retrieve the value with the
comma-ok idiom (v, ok := ctx.Value("executionId").(string)) and return a clear
error (e.g. fmt.Errorf or errors.New) when ok is false instead of allowing a
panic; then pass the validated executionId to listModules.

Comment on lines +124 to +127
func (c *RsyncClient) ListFilesInModule(ctx context.Context, host string, port int, username string, password string, module string) (RsyncListResponse, error) {
executionId := ctx.Value("executionId").(string)
return listFilesInModule(executionId, host, port, username, password, module)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Same: guard against missing executionId to prevent panic

Repeat the safe-assertion pattern for ListFilesInModule.

-func (c *RsyncClient) ListFilesInModule(ctx context.Context, host string, port int, username string, password string, module string) (RsyncListResponse, error) {
-  executionId := ctx.Value("executionId").(string)
-  return listFilesInModule(executionId, host, port, username, password, module)
-}
+func (c *RsyncClient) ListFilesInModule(ctx context.Context, host string, port int, username string, password string, module string) (RsyncListResponse, error) {
+  executionId, ok := ctx.Value("executionId").(string)
+  if !ok || executionId == "" {
+    return RsyncListResponse{}, fmt.Errorf("rsync: missing executionId in context")
+  }
+  return listFilesInModule(executionId, host, port, username, password, module)
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (c *RsyncClient) ListFilesInModule(ctx context.Context, host string, port int, username string, password string, module string) (RsyncListResponse, error) {
executionId := ctx.Value("executionId").(string)
return listFilesInModule(executionId, host, port, username, password, module)
}
func (c *RsyncClient) ListFilesInModule(ctx context.Context, host string, port int, username string, password string, module string) (RsyncListResponse, error) {
executionId, ok := ctx.Value("executionId").(string)
if !ok || executionId == "" {
return RsyncListResponse{}, fmt.Errorf("rsync: missing executionId in context")
}
return listFilesInModule(executionId, host, port, username, password, module)
}
🤖 Prompt for AI Agents
In pkg/js/libs/rsync/rsync.go around lines 124 to 127, the code unconditionally
type-asserts ctx.Value("executionId").(string) which can panic if the value is
missing; update ListFilesInModule to safely retrieve the executionId using the
comma-ok form (val, ok := ctx.Value("executionId").(string)) and return a
descriptive error if ok is false (matching the safe-assertion pattern used in
the other method), then pass the validated executionId into listFilesInModule.

Comment on lines +137 to +147
// Create a bytes buffer for logging
var logBuffer bytes.Buffer

// Create a custom slog handler that writes to the buffer
logHandler := slog.NewTextHandler(&logBuffer, &slog.HandlerOptions{
Level: slog.LevelDebug,
})

// Create a logger that writes to our buffer
logger := slog.New(logHandler)

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Sensitive data risk: driver logs are surfaced verbatim via Output

You capture driver logs at debug level and return them to templates (RsyncListResponse.Output). Depending on the driver, logs may include credentials or server banners that we don’t want to leak downstream or to user logs.

Mitigations:

  • Only attach a logger when an explicit “debug”/“verbose” flag is enabled.
  • Redact credentials from the buffer before returning.
  • Cap output length to avoid memory blowups.

Minimal, localized change to redact obvious secrets:

-  result := RsyncListResponse{
-    Modules: make([]string, len(sr)),
-    Output:  logBuffer.String(),
-  }
+  result := RsyncListResponse{
+    Modules: make([]string, len(sr)),
+    Output:  sanitizeRsyncLogs(logBuffer.String(), username, password),
+  }

Add this helper (and strings import) elsewhere in the file:

// sanitizeRsyncLogs removes obvious secrets from log output.
// Best-effort: relies on the caller passing the same creds used for auth.
func sanitizeRsyncLogs(out, user, pass string) string {
  // Skip work quickly
  if out == "" {
    return out
  }
  // Redact password first to avoid accidental leaking
  if pass != "" {
    out = strings.ReplaceAll(out, pass, "******")
  }
  if user != "" {
    out = strings.ReplaceAll(out, user, "***")
  }
  // Optionally cap to N bytes
  const max = 8 << 10 // 8KiB
  if len(out) > max {
    out = out[:max] + "...[truncated]"
  }
  return out
}

If preferred, I can refactor to enable logging only under an explicit debug setting.

Also applies to: 157-161

Comment on lines +203 to +206
result := RsyncListResponse{
Files: make([]string, len(list)),
Output: logBuffer.String(),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Apply the same redaction/capping to Output in files listing

Mirror the sanitizeRsyncLogs usage here to prevent leaking secrets and cap size.

-  result := RsyncListResponse{
-    Files:  make([]string, len(list)),
-    Output: logBuffer.String(),
-  }
+  result := RsyncListResponse{
+    Files:  make([]string, len(list)),
+    Output: sanitizeRsyncLogs(logBuffer.String(), username, password),
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
result := RsyncListResponse{
Files: make([]string, len(list)),
Output: logBuffer.String(),
}
result := RsyncListResponse{
Files: make([]string, len(list)),
Output: sanitizeRsyncLogs(logBuffer.String(), username, password),
}
🤖 Prompt for AI Agents
In pkg/js/libs/rsync/rsync.go around lines 203 to 206, the
RsyncListResponse.Output is assigned the raw logBuffer.String() which can leak
secrets and exceed size limits; apply the same sanitizeRsyncLogs redaction and
capping used elsewhere to the Output field (call
sanitizeRsyncLogs(logBuffer.String()) and assign that result, ensuring it honors
the existing max length/cap logic) so Output is redacted and size-limited before
being returned.

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: 2

🧹 Nitpick comments (4)
cmd/integration-test/javascript.go (4)

105-133: Remove ineffective pool.Retry wrapper; it never retries.

The closure always returns nil, so pool.Retry won’t retry. Either return the actual error from the closure or drop pool.Retry and call directly (you already have an outer retry loop).

Apply this minimal change:

-        _ = pool.Retry(func() error {
-            //let rsync server start
-            time.Sleep(3 * time.Second)
-            results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
-            return nil
-        })
-        if err != nil {
-            return err
-        }
+        // let rsync server start
+        time.Sleep(3 * time.Second)
+        results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
+        if err != nil {
+            return err
+        }

111-111: Prefer 127.0.0.1 over localhost for stability.

Avoids IPv6/hosts-file surprises when the daemon only listens on IPv4.

-    finalURL := "localhost:" + tempPort
+    finalURL := "127.0.0.1:" + tempPort

205-205: Make config writing more portable and remove ambiguity in credentials.

  • Use printf instead of echo -e for reliability.
  • The OS user password (mysecret) differs from rsync secret (MySecret123). Consider aligning or dropping the OS password step since rsync auth uses the secrets file.
-  Cmd:        []string{"sh", "-c", "apk add --no-cache rsync shadow && useradd -m rsyncuser && echo 'rsyncuser:mysecret' | chpasswd && echo 'rsyncuser:MySecret123' > /etc/rsyncd.secrets && chmod 600 /etc/rsyncd.secrets && echo -e '[data]\\n  path = /data\\n  comment = Local Rsync Share\\n  read only = false\\n  auth users = rsyncuser\\n  secrets file = /etc/rsyncd.secrets' > /etc/rsyncd.conf && mkdir -p /data && exec rsync --daemon --no-detach --config=/etc/rsyncd.conf"},
+  Cmd:        []string{"sh", "-c", "apk add --no-cache rsync shadow && useradd -m rsyncuser && echo 'rsyncuser:MySecret123' > /etc/rsyncd.secrets && chmod 600 /etc/rsyncd.secrets && printf '[data]\\n  path = /data\\n  comment = Local Rsync Share\\n  read only = false\\n  auth users = rsyncuser\\n  secrets file = /etc/rsyncd.secrets\\n' > /etc/rsyncd.conf && mkdir -p /data && exec rsync --daemon --no-detach --config=/etc/rsyncd.conf"},

103-134: Optional: collapse result-count check into the retry loop.

You can return the assertion from inside the loop to avoid tracking an errors slice.

-    if err := expectResultsCount(results, 1); err == nil {
-        return nil
-    } else {
-        errs = append(errs, err)
-    }
+    if err := expectResultsCount(results, 1); err == nil {
+        return nil
+    } else {
+        errs = append(errs, err)
+    }

If you adopt the earlier suggestion to remove pool.Retry, consider returning on success and continuing on error, keeping logic concise.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 36e7701 and 47f45d3.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • integration_tests/protocols/javascript/rsync-test.yaml is excluded by !**/*.yaml
📒 Files selected for processing (2)
  • cmd/integration-test/javascript.go (3 hunks)
  • go.mod (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • go.mod
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/integration-test/javascript.go (1)
pkg/testutils/integration.go (2)
  • TestCase (247-250)
  • RunNucleiTemplateAndGetResults (30-32)
⏰ 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: Lint
🔇 Additional comments (2)
cmd/integration-test/javascript.go (2)

18-18: Rsync JS testcase entry looks good.

Disabled on Windows/macOS consistent with other dockerized tests. No issues.


24-24: Resource handle addition is appropriate.

rsyncResource mirrors existing Redis/SSH patterns.

{Path: "protocols/javascript/ssh-server-fingerprint.yaml", TestCase: &javascriptSSHServerFingerprint{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
{Path: "protocols/javascript/net-multi-step.yaml", TestCase: &networkMultiStep{}},
{Path: "protocols/javascript/net-https.yaml", TestCase: &javascriptNetHttps{}},
{Path: "protocols/javascript/rsync-test.yaml", TestCase: &javascriptRsyncTest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Sanity-check that the template matches container credentials and module.

Ensure protocols/javascript/rsync-test.yaml uses:

  • user: rsyncuser
  • pass: MySecret123
  • module: data
  • target: host:port provided here

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -nC2 -e 'rsyncuser' -e 'MySecret123' -e '\bdata\b' protocols/javascript/rsync-test.yaml || {
  echo "Note: verify the template uses the expected credentials/module."
}

Length of output: 322


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate any rsync-test.yaml files in the repo
paths=$(fd rsync-test.yaml)

if [ -z "$paths" ]; then
  echo "No rsync-test.yaml file found in the repository."
  exit 0
fi

# For each found file, verify the expected credentials/module
for file in $paths; do
  echo "Checking $file:"
  rg -nC2 -e 'user:\s*rsyncuser' -e 'pass:\s*MySecret123' -e 'module:\s*data' "$file" \
    || echo "⚠️ Note: verify that $file uses user: rsyncuser, pass: MySecret123, module: data."
done

Length of output: 182


Critical: Verify existence of the referenced YAML template

It appears the integration test is pointing at protocols/javascript/rsync-test.yaml, but no such file is present in the repository. This will cause test discovery to fail.

• File: cmd/integration-test/javascript.go
Line: 18

{Path: "protocols/javascript/rsync-test.yaml", TestCase: &javascriptRsyncTest{}, DisableOn: …},

Action required:

  • Confirm whether the YAML lives under a different path and update the Path accordingly, or
  • Add the missing protocols/javascript/rsync-test.yaml template (ensuring it uses user: rsyncuser, pass: MySecret123, module: data, and the correct target).
🤖 Prompt for AI Agents
In cmd/integration-test/javascript.go around line 18, the test references
protocols/javascript/rsync-test.yaml which is missing from the repo; update the
Path to the actual location if the YAML exists elsewhere or add the missing file
at protocols/javascript/rsync-test.yaml containing a valid rsync template that
includes user: rsyncuser, pass: MySecret123, module: data and the correct target
(ensure the target matches the integration test expectations), then run test
discovery to confirm the test picks up the template.

Comment on lines +201 to +216
// setup a temporary rsync server
rsyncResource, err = pool.RunWithOptions(&dockertest.RunOptions{
Repository: "alpine",
Tag: "latest",
Cmd: []string{"sh", "-c", "apk add --no-cache rsync shadow && useradd -m rsyncuser && echo 'rsyncuser:mysecret' | chpasswd && echo 'rsyncuser:MySecret123' > /etc/rsyncd.secrets && chmod 600 /etc/rsyncd.secrets && echo -e '[data]\\n path = /data\\n comment = Local Rsync Share\\n read only = false\\n auth users = rsyncuser\\n secrets file = /etc/rsyncd.secrets' > /etc/rsyncd.conf && mkdir -p /data && exec rsync --daemon --no-detach --config=/etc/rsyncd.conf"},
Platform: "linux/amd64",
})
if err != nil {
log.Printf("Could not start Rsync resource: %s", err)
return
}
// by default expire after 30 sec
if err := rsyncResource.Expire(30); err != nil {
log.Printf("Could not expire Rsync resource: %s", err)
}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Rsync port 873 isn’t exposed; GetPort("873/tcp") will be empty.

Alpine image doesn’t EXPOSE 873, so no host port is published unless you set it explicitly. Expose and bind 873/tcp.

Apply this diff in the run options:

 rsyncResource, err = pool.RunWithOptions(&dockertest.RunOptions{
   Repository: "alpine",
   Tag:        "latest",
   Cmd:        []string{"sh", "-c", "apk add --no-cache rsync shadow && useradd -m rsyncuser && echo 'rsyncuser:mysecret' | chpasswd && echo 'rsyncuser:MySecret123' > /etc/rsyncd.secrets && chmod 600 /etc/rsyncd.secrets && echo -e '[data]\\n  path = /data\\n  comment = Local Rsync Share\\n  read only = false\\n  auth users = rsyncuser\\n  secrets file = /etc/rsyncd.secrets' > /etc/rsyncd.conf && mkdir -p /data && exec rsync --daemon --no-detach --config=/etc/rsyncd.conf"},
+  ExposedPorts: []string{"873/tcp"},
+  PortBindings: map[docker.Port][]docker.PortBinding{
+    "873/tcp": {{HostIP: "0.0.0.0", HostPort: ""}},
+  },
   Platform:   "linux/amd64",
 })

Also add the import:

// at the top imports
"github.com/ory/dockertest/v3/docker"
🤖 Prompt for AI Agents
In cmd/integration-test/javascript.go around lines 201-216, the rsync container
never exposes or binds port 873 so GetPort("873/tcp") will be empty; update the
RunWithOptions to declare ExposedPorts and HostConfig PortBindings for "873/tcp"
(map container port 873 to a random host port) in the RunOptions by supplying a
docker HostConfig with PortBindings and ExposedPorts, and add the import
"github.com/ory/dockertest/v3/docker" at the top of the file.

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.

[FEATURE] Authentication support in Javascript RSYNC Protocol

2 participants