Skip to content

Conversation

@killev
Copy link
Collaborator

@killev killev commented Jul 22, 2025

  • Add mongo-migrate.js script with batch processing, verification, and error handling for database migrations
  • Add s3-copy.js script for cross-account S3 bucket copying with retry logic and ACL preservation
  • Update package.json with AWS SDK dependency and migration script commands
  • Update ESLint configuration and workspace rules for new utility scripts

These utilities are essential for deployment automation and data migration workflows. The MongoDB migration script provides safe, verified database transfers with batching and error recovery. The S3 copy script enables seamless cross-account asset migration while preserving permissions and metadata.

…n updates

- Add mongo-migrate.js script with batch processing, verification, and error handling
- Add s3-copy.js script for cross-account S3 bucket copying with retry logic
- Update package.json with AWS SDK dependency and migration script commands
- Update ESLint configuration and workspace rules for new scripts
Copilot AI review requested due to automatic review settings July 22, 2025 08:57
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 22, 2025

📝 Walkthrough
## Walkthrough

This update adds two new utility scripts: one for migrating MongoDB collections between databases with CLI options and environment validation, and another for copying AWS S3 bucket objects between accounts with batching, metadata, and ACL preservation. It also updates ESLint config to exempt the new S3 copy script from line count limits, modifies package.json dependencies and scripts, and updates a subproject commit reference. Additionally, several new workflow documents and GitHub PR-related scripts for managing PR comments and conversations were introduced.

## Changes

| Files/Paths                         | Change Summary                                                                                              |
|-----------------------------------|-------------------------------------------------------------------------------------------------------------|
| .cursor/rules/common               | Updated subproject commit reference.                                                                        |
| .cursor/rules/conversation-process.mdc | Added new workflow document defining automated processing of PR conversation comments with decision-based actions and error handling. |
| .cursor/rules/conversation-read.mdc | Added new workflow document analyzing PR comments to determine relevance and generate categorized reports.  |
| .gitignore                        | Added `tmp` directory to ignore list.                                                                       |
| website/.eslintrc.js               | Added ESLint override disabling `max-lines` rule for `scripts/s3-copy.js`.                                  |
| website/package.json               | Removed some npm scripts, added `@aws-sdk/client-s3` dependency, reordered dependencies.                    |
| website/scripts/get-pr-number.js   | Added new script to find and display GitHub PR number for current git branch using GitHub CLI.               |
| website/scripts/list-pr-conversations.js | Added new script to fetch and list unresolved PR review comment threads via GitHub CLI GraphQL API.         |
| website/scripts/mongo-migrate.js  | Added new MongoDB migration script with CLI, env loading, batch copy of collections and indexes, exports.   |
| website/scripts/resolve-pr-conversation.js | Added new script to add comments and resolve PR review threads via GitHub CLI GraphQL API.                 |
| website/scripts/s3-copy.js         | Added new AWS S3 bucket copy script with CLI, env loading, batching, metadata and ACL preservation, exports.|

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant CLI
    participant Env
    participant SourceDB
    participant TargetDB

    User->>CLI: Run mongo-migrate.js with options
    CLI->>Env: Load environment variables
    CLI->>SourceDB: Connect and list collections
    CLI->>TargetDB: Connect
    loop For each collection
        CLI->>TargetDB: Drop collection if exists
        CLI->>SourceDB: Read documents in batches
        CLI->>TargetDB: Insert documents in batches
        CLI->>SourceDB: Get indexes
        CLI->>TargetDB: Create indexes
    end
    CLI->>SourceDB: Count documents
    CLI->>TargetDB: Count documents
    CLI->>User: Log results
sequenceDiagram
    participant User
    participant CLI
    participant Env
    participant SourceS3
    participant DestS3

    User->>CLI: Run s3-copy.js with options
    CLI->>Env: Load environment variables
    CLI->>SourceS3: List all object keys
    loop For each batch of objects
        CLI->>SourceS3: Get object and ACL
        CLI->>DestS3: Upload object with metadata and ACL
    end
    CLI->>User: Log progress and summary
Loading

Estimated code review effort

4 (~80 minutes)

Possibly related PRs

Suggested reviewers

  • yuramax
  • VitalyyP
  • IhorMasechko

</details>

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

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


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between dd2ba3642acf31eee8f82cdcb08fbec0c2189309 and 44d80a6c6717d642a83e5df5c923d42f0b9eee08.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `website/scripts/list-pr-conversations.js` (1 hunks)
* `website/scripts/mongo-migrate.js` (1 hunks)
* `website/scripts/resolve-pr-conversation.js` (1 hunks)
* `website/scripts/s3-copy.js` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (4)</summary>

* website/scripts/list-pr-conversations.js
* website/scripts/mongo-migrate.js
* website/scripts/s3-copy.js
* website/scripts/resolve-pr-conversation.js

</details>

<details>
<summary>⏰ 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). (4)</summary>

* GitHub Check: lint
* GitHub Check: e2e-tests
* GitHub Check: unit-tests
* GitHub Check: security-scan

</details>

</details>
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=speedandfunction/website&utm_content=207):

- 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](https://www.coderabbit.ai/contact-us/support) 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](https://docs.coderabbit.ai/finishing-touches/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](https://docs.coderabbit.ai/guides/configure-coderabbit) 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](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds MongoDB migration and S3 cross-account copy utilities with supporting configuration updates to enable deployment automation and data migration workflows. The MongoDB migration script provides safe database transfers with batching, verification, and error handling, while the S3 copy script enables seamless cross-account asset migration.

  • Add MongoDB migration script with batch processing, verification, and error handling for database transfers
  • Add S3 copy script for cross-account bucket copying with retry logic and ACL preservation
  • Update package.json with AWS SDK dependency and migration script commands

Reviewed Changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
website/scripts/s3-copy.js Implements S3 cross-account copy utility with batch processing, retry logic, and ACL preservation
website/scripts/mongo-migrate.js Implements MongoDB migration script with document batching, index copying, and verification
website/package.json Adds AWS SDK dependency and migration npm script commands
website/.eslintrc.js Adds ESLint rule exception for s3-copy.js file length
.cursor/rules/common Updates subproject commit reference

@github-actions
Copy link

github-actions bot commented Jul 22, 2025

🔍 Vulnerabilities of apostrophe-cms:test

📦 Image Reference apostrophe-cms:test
digestsha256:4eeffc3d23620ad8aef3d90ac32ae365f216808c078dd53f99dadb3a5ea556cf
vulnerabilitiescritical: 1 high: 3 medium: 0 low: 0
platformlinux/amd64
size295 MB
packages1079
📦 Base Image node:23-alpine
also known as
  • 23-alpine3.22
  • 23.11-alpine
  • 23.11-alpine3.22
  • 23.11.1-alpine
  • 23.11.1-alpine3.22
digestsha256:b9d38d589853406ff0d4364f21969840c3e0397087643aef8eede40edbb6c7cd
vulnerabilitiescritical: 0 high: 0 medium: 1 low: 1
critical: 1 high: 0 medium: 0 low: 0 form-data 4.0.2 (npm)

pkg:npm/[email protected]

critical 9.4: CVE--2025--7783 Use of Insufficiently Random Values

Affected range>=4.0.0
<4.0.4
Fixed version4.0.4
CVSS Score9.4
CVSS VectorCVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N
EPSS Score0.042%
EPSS Percentile12th percentile
Description

Summary

form-data uses Math.random() to select a boundary value for multipart form-encoded data. This can lead to a security issue if an attacker:

  1. can observe other values produced by Math.random in the target application, and
  2. can control one field of a request made using form-data

Because the values of Math.random() are pseudo-random and predictable (see: https://blog.securityevaluators.com/hacking-the-javascript-lottery-80cc437e3b7f), an attacker who can observe a few sequential values can determine the state of the PRNG and predict future values, includes those used to generate form-data's boundary value. The allows the attacker to craft a value that contains a boundary value, allowing them to inject additional parameters into the request.

This is largely the same vulnerability as was recently found in undici by parrot409 -- I'm not affiliated with that researcher but want to give credit where credit is due! My PoC is largely based on their work.

Details

The culprit is this line here: https://github.com/form-data/form-data/blob/426ba9ac440f95d1998dac9a5cd8d738043b048f/lib/form_data.js#L347

An attacker who is able to predict the output of Math.random() can predict this boundary value, and craft a payload that contains the boundary value, followed by another, fully attacker-controlled field. This is roughly equivalent to any sort of improper escaping vulnerability, with the caveat that the attacker must find a way to observe other Math.random() values generated by the application to solve for the state of the PRNG. However, Math.random() is used in all sorts of places that might be visible to an attacker (including by form-data itself, if the attacker can arrange for the vulnerable application to make a request to an attacker-controlled server using form-data, such as a user-controlled webhook -- the attacker could observe the boundary values from those requests to observe the Math.random() outputs). A common example would be a x-request-id header added by the server. These sorts of headers are often used for distributed tracing, to correlate errors across the frontend and backend. Math.random() is a fine place to get these sorts of IDs (in fact, opentelemetry uses Math.random for this purpose)

PoC

PoC here: https://github.com/benweissmann/CVE-2025-7783-poc

Instructions are in that repo. It's based on the PoC from https://hackerone.com/reports/2913312 but simplified somewhat; the vulnerable application has a more direct side-channel from which to observe Math.random() values (a separate endpoint that happens to include a randomly-generated request ID).

Impact

For an application to be vulnerable, it must:

  • Use form-data to send data including user-controlled data to some other system. The attacker must be able to do something malicious by adding extra parameters (that were not intended to be user-controlled) to this request. Depending on the target system's handling of repeated parameters, the attacker might be able to overwrite values in addition to appending values (some multipart form handlers deal with repeats by overwriting values instead of representing them as an array)
  • Reveal values of Math.random(). It's easiest if the attacker can observe multiple sequential values, but more complex math could recover the PRNG state to some degree of confidence with non-sequential values.

If an application is vulnerable, this allows an attacker to make arbitrary requests to internal systems.

critical: 0 high: 1 medium: 0 low: 0 connect-multiparty 2.2.0 (npm)

pkg:npm/[email protected]

high 7.8: CVE--2022--29623 Unrestricted Upload of File with Dangerous Type

Affected range<=2.2.0
Fixed versionNot Fixed
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.320%
EPSS Percentile54th percentile
Description

An arbitrary file upload vulnerability in the file upload module of Express Connect-Multiparty 2.2.0 allows attackers to execute arbitrary code via a crafted PDF file. NOTE: the Supplier has not verified this vulnerability report.

critical: 0 high: 1 medium: 0 low: 0 async 0.9.2 (npm)

pkg:npm/[email protected]

high 7.8: CVE--2021--43138 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range<2.6.4
Fixed version2.6.4, 3.2.2
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.907%
EPSS Percentile75th percentile
Description

A vulnerability exists in Async through 3.2.1 (fixed in 3.2.2), which could let a malicious user obtain privileges via the mapValues() method.

critical: 0 high: 1 medium: 0 low: 0 async 1.5.2 (npm)

pkg:npm/[email protected]

high 7.8: CVE--2021--43138 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range<2.6.4
Fixed version2.6.4, 3.2.2
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.907%
EPSS Percentile75th percentile
Description

A vulnerability exists in Async through 3.2.1 (fixed in 3.2.2), which could let a malicious user obtain privileges via the mapValues() method.

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

🧹 Nitpick comments (3)
website/scripts/mongo-migrate.js (2)

6-6: Consider making BATCH_SIZE configurable.

The batch size is hardcoded to 1000. For flexibility across different environments and collection sizes, consider making it configurable via environment variable or command-line argument.

-const BATCH_SIZE = 1000;
+const BATCH_SIZE = parseInt(process.env.MIGRATION_BATCH_SIZE || '1000', 10);

8-21: Consider using yargs for argument parsing.

Since yargs is already in your dependencies, consider using it for more robust argument parsing with built-in validation and help generation.

Example implementation:

const yargs = require('yargs');

const parseArguments = () => {
  return yargs
    .option('env', {
      describe: 'Path to .env file',
      type: 'string'
    })
    .option('dry-run', {
      describe: 'Preview migration',
      type: 'boolean'
    })
    .option('verbose', {
      alias: 'v',
      describe: 'Verbose logging',
      type: 'boolean'
    })
    .help('help')
    .alias('help', 'h')
    .argv;
};
website/scripts/s3-copy.js (1)

105-122: Consider handling additional ACL types.

The current implementation only handles public-read and private ACLs. S3 supports additional canned ACLs that might need preservation.

 async getACL(key, bucket, client) {
   try {
-    const { Grants } = await client.send(
+    const { Grants, Owner } = await client.send(
       new GetObjectAclCommand({ Bucket: bucket, Key: key }),
     );
     const isPublic = Grants?.some(
       (grant) =>
         grant.Grantee?.URI ===
           'https://acs.amazonaws.com/groups/global/AllUsers' &&
         grant.Permission === 'READ',
     );
-    if (isPublic) return 'public-read';
-    return 'private';
+    
+    // Check for other common ACL patterns
+    const isPublicReadWrite = Grants?.some(
+      (grant) =>
+        grant.Grantee?.URI ===
+          'https://acs.amazonaws.com/groups/global/AllUsers' &&
+        grant.Permission === 'WRITE',
+    );
+    
+    if (isPublicReadWrite) return 'public-read-write';
+    if (isPublic) return 'public-read';
+    
+    // For custom ACLs, you might want to preserve the full Grants array
+    // and use PutObjectAclCommand instead of the ACL parameter
+    return 'private';
   } catch (err) {
     if (err.name === 'AccessDenied') return 'private';
     throw err;
   }
 },
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 336cb19 and 7804b8b.

⛔ Files ignored due to path filters (1)
  • website/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • .cursor/rules/common (1 hunks)
  • website/.eslintrc.js (1 hunks)
  • website/package.json (3 hunks)
  • website/scripts/mongo-migrate.js (1 hunks)
  • website/scripts/s3-copy.js (1 hunks)
🧠 Learnings (3)
📓 Common learnings
Learnt from: killev
PR: speedandfunction/website#76
File: website/.eslintrc.js:5-5
Timestamp: 2025-05-10T21:03:18.519Z
Learning: The user (killev) prefers to use 'eslint:all' in the ESLint configuration to enable all rules, despite potential drawbacks like excessive noise, false positives, higher maintenance, and slower linting.
website/.eslintrc.js (13)

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum lines per file: 300

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum line length: 80 characters

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum function length enforced (avoid excessive length)

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.test.{js,jsx} : Test files have relaxed rules for function length, statements, extraneous requires, and destructuring

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to app.js : app.js: relaxed rules for function lines, function style, and quote properties

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to modules/asset/ui/src/index.js : modules/asset/ui/src/index.js: relaxed function lines and style rules

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum parameters: 5

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.e2e.{js,jsx} : E2E test files: relaxed import, ternary, and sorting rules

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum depth: 4 levels

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No inline comments

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.js : No missing imports in Node.js

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No unresolved imports

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No duplicate object keys

website/package.json (1)

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to modules/asset/ui/src/swipers.js : modules/asset/ui/src/swipers.js: relaxed import rules

🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: killev
PR: speedandfunction/website#76
File: website/.eslintrc.js:5-5
Timestamp: 2025-05-10T21:03:18.519Z
Learning: The user (killev) prefers to use 'eslint:all' in the ESLint configuration to enable all rules, despite potential drawbacks like excessive noise, false positives, higher maintenance, and slower linting.
website/.eslintrc.js (13)

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum lines per file: 300

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum line length: 80 characters

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum function length enforced (avoid excessive length)

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.test.{js,jsx} : Test files have relaxed rules for function length, statements, extraneous requires, and destructuring

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to app.js : app.js: relaxed rules for function lines, function style, and quote properties

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to modules/asset/ui/src/index.js : modules/asset/ui/src/index.js: relaxed function lines and style rules

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum parameters: 5

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.e2e.{js,jsx} : E2E test files: relaxed import, ternary, and sorting rules

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum depth: 4 levels

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No inline comments

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.js : No missing imports in Node.js

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No unresolved imports

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No duplicate object keys

website/package.json (1)

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to modules/asset/ui/src/swipers.js : modules/asset/ui/src/swipers.js: relaxed import rules

⏰ 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). (4)
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: e2e-tests
  • GitHub Check: security-scan
🔇 Additional comments (8)
.cursor/rules/common (1)

1-1: Confirm accompanying submodule update
Only the commit SHA for the sub-project has changed. Make sure you also pushed the referenced commit and ran git submodule update --init --recursive so CI and collaborators fetch the correct contents.

website/.eslintrc.js (1)

182-187: LGTM! ESLint override correctly configured.

The override properly disables the max-lines rule for the S3 copy utility script, which is appropriate given the comprehensive nature of the utility.

website/package.json (1)

16-18: Scripts correctly added for MongoDB migration utility.

The new npm scripts provide convenient access to the migration tool with and without help documentation.

website/scripts/mongo-migrate.js (3)

130-144: Index copying implementation looks good.

The function correctly filters out the default _id_ index and properly removes version and namespace fields before creating indexes on the target collection.


270-278: Excellent error handling and graceful shutdown implementation.

The script properly handles unhandled rejections and SIGINT signals, ensuring clean process termination.


53-73: Avoid exposing sensitive MongoDB URIs in error messages.

The function correctly validates environment variables, but be cautious about logging MongoDB URIs as they may contain credentials. Consider sanitizing URIs before logging.

+const sanitizeUri = (uri) => {
+  try {
+    const url = new URL(uri);
+    if (url.password) {
+      url.password = '****';
+    }
+    return url.toString();
+  } catch {
+    return 'invalid-uri';
+  }
+};

 console.log('🚀 Starting MongoDB migration...');
-console.log(`📤 Source: ${config.exportDbName}`);
-console.log(`📥 Target: ${config.importDbName}`);
+console.log(`📤 Source: ${config.exportDbName} (${sanitizeUri(config.exportUri)})`);
+console.log(`📥 Target: ${config.importDbName} (${sanitizeUri(config.importUri)})`);
⛔ Skipped due to learnings
Learnt from: killev
PR: speedandfunction/website#100
File: website/modules/@apostrophecms/form/index.js:227-227
Timestamp: 2025-05-19T20:40:04.914Z
Learning: The project intentionally uses the `getEnv` function for all environment variable access, including in placeholder values. This ensures that all required environment variables are present at application startup (fail-fast approach), even for features that might not be enabled.
website/scripts/s3-copy.js (2)

270-301: Well-implemented retry logic with clear separation of attempts.

The retry strategy correctly handles failed objects and provides clear summaries for both initial and retry attempts.


304-372: Well-structured service class with clear separation of concerns.

The S3CopyService class follows good design principles with static validation methods and clear method responsibilities.

killev added 3 commits July 22, 2025 11:31
- Remove lint:pr-script for merged PRs script

- Remove format:pr-script for merged PRs script

- Remove migrate:db and migrate:db:help scripts
- Replace forEach with for...of loop in mongo-migrate.js parseArguments function

- Fix anti-pattern of using forEach with throw statement for proper control flow
- Fix missing closing brace in mongo-migrate.js conditional block
- Fix missing closing parenthesis in verifyMigration function call
- Resolve syntax errors that prevented linting from completing
- Scripts now parse correctly for further linting improvements
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

♻️ Duplicate comments (2)
website/scripts/mongo-migrate.js (2)

5-5: Make BATCH_SIZE configurable via environment variable.

The hardcoded batch size may not be optimal for all environments. Different deployment scenarios may benefit from different batch sizes based on memory constraints and network conditions.

-const BATCH_SIZE = 1000;
+const BATCH_SIZE = parseInt(process.env.BATCH_SIZE, 10) || 1000;

120-130: Fix error counting in batch processing.

When insertMany fails with ordered: false, some documents may still be inserted successfully. The current implementation counts all documents in the batch as errors, which is incorrect.

 try {
-  await targetCol.insertMany(batch, { ordered: false });
+  const result = await targetCol.insertMany(batch, { ordered: false });
   processed += batch.length;
   
   if (verbose) {
     process.stdout.write(`\r   Progress: ${processed}/${count}`);
   }
 } catch (error) {
-  errors += batch.length;
-  if (verbose) console.error(`\n⚠️  Batch error: ${error.message}`);
+  // For BulkWriteError, writeErrors contains the actual failed documents
+  if (error.name === 'BulkWriteError' && error.result) {
+    const successCount = error.result.nInserted || 0;
+    processed += successCount;
+    errors += batch.length - successCount;
+    if (verbose) console.error(`\n⚠️  Batch partially failed: ${successCount}/${batch.length} inserted`);
+  } else {
+    errors += batch.length;
+    if (verbose) console.error(`\n⚠️  Batch error: ${error.message}`);
+  }
 }
🧹 Nitpick comments (1)
website/scripts/list-pr-conversations.js (1)

85-92: Simplify the sorting logic.

The sorting logic can be simplified for better readability.

-    // Sort by creation date of first comment in each conversation
-    conversations.sort((a, b) => {
-      const aFirstComment = a.comments[0]?.createdAt || '';
-      const bFirstComment = b.comments[0]?.createdAt || '';
-      return (
-        new Date(aFirstComment).getTime() - new Date(bFirstComment).getTime()
-      );
-    });
+    // Sort by creation date of first comment in each conversation
+    conversations.sort((a, b) => {
+      const aDate = new Date(a.comments[0]?.createdAt || 0);
+      const bDate = new Date(b.comments[0]?.createdAt || 0);
+      return aDate - bDate;
+    });
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e1d9318 and b58260a.

📒 Files selected for processing (6)
  • .cursor/rules/conversation-process.mdc (1 hunks)
  • .cursor/rules/conversation-read.mdc (1 hunks)
  • website/scripts/get-pr-number.js (1 hunks)
  • website/scripts/list-pr-conversations.js (1 hunks)
  • website/scripts/mongo-migrate.js (1 hunks)
  • website/scripts/resolve-pr-conversation.js (1 hunks)
🧠 Learnings (6)
📓 Common learnings
Learnt from: killev
PR: speedandfunction/website#76
File: website/.eslintrc.js:5-5
Timestamp: 2025-05-10T21:03:18.519Z
Learning: The user (killev) prefers to use 'eslint:all' in the ESLint configuration to enable all rules, despite potential drawbacks like excessive noise, false positives, higher maintenance, and slower linting.
website/scripts/resolve-pr-conversation.js (1)

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

website/scripts/get-pr-number.js (2)

Learnt from: killev
PR: #21
File: scripts/merged-prs-last-24h.js:0-0
Timestamp: 2025-04-22T06:57:44.687Z
Learning: For console scripts like merged-prs-last-24h.js, the preferred approach is to allow fatal errors rather than implementing explicit error handling with try-catch blocks, as this makes errors more visible and provides complete stack traces for debugging.

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

.cursor/rules/conversation-read.mdc (4)

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Capitalize all comments

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

Learnt from: yuramax
PR: #139
File: website/jest.config.cjs:4-4
Timestamp: 2025-06-03T16:27:46.172Z
Learning: When reviewing PRs, focus suggestions on the main objectives stated in the PR description. Skip suggestions for incidental changes that are unrelated to the PR's primary purpose, especially when the user explicitly requests to stay focused on the main feature/improvement.

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No inline comments

website/scripts/mongo-migrate.js (4)

Learnt from: killev
PR: #21
File: scripts/merged-prs-last-24h.js:0-0
Timestamp: 2025-04-22T06:57:44.687Z
Learning: For console scripts like merged-prs-last-24h.js, the preferred approach is to allow fatal errors rather than implementing explicit error handling with try-catch blocks, as this makes errors more visible and provides complete stack traces for debugging.

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum parameters: 5

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Use destructuring where possible

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No ternary operators (use if/else)

website/scripts/list-pr-conversations.js (2)

Learnt from: killev
PR: #21
File: scripts/merged-prs-last-24h.js:0-0
Timestamp: 2025-04-22T06:57:44.687Z
Learning: For console scripts like merged-prs-last-24h.js, the preferred approach is to allow fatal errors rather than implementing explicit error handling with try-catch blocks, as this makes errors more visible and provides complete stack traces for debugging.

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

🧬 Code Graph Analysis (2)
website/scripts/resolve-pr-conversation.js (2)
website/scripts/get-pr-number.js (2)
  • require (25-25)
  • result (115-118)
website/scripts/list-pr-conversations.js (3)
  • require (3-3)
  • query (74-74)
  • result (77-80)
website/scripts/get-pr-number.js (3)
website/scripts/list-pr-conversations.js (2)
  • require (3-3)
  • result (77-80)
website/scripts/resolve-pr-conversation.js (3)
  • require (1-1)
  • result (24-27)
  • result (88-91)
website/scripts/mongo-migrate.js (3)
  • require (1-1)
  • result (46-46)
  • result (226-226)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: killev
PR: speedandfunction/website#76
File: website/.eslintrc.js:5-5
Timestamp: 2025-05-10T21:03:18.519Z
Learning: The user (killev) prefers to use 'eslint:all' in the ESLint configuration to enable all rules, despite potential drawbacks like excessive noise, false positives, higher maintenance, and slower linting.
website/scripts/resolve-pr-conversation.js (1)

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

website/scripts/get-pr-number.js (2)

Learnt from: killev
PR: #21
File: scripts/merged-prs-last-24h.js:0-0
Timestamp: 2025-04-22T06:57:44.687Z
Learning: For console scripts like merged-prs-last-24h.js, the preferred approach is to allow fatal errors rather than implementing explicit error handling with try-catch blocks, as this makes errors more visible and provides complete stack traces for debugging.

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

.cursor/rules/conversation-read.mdc (4)

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Capitalize all comments

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

Learnt from: yuramax
PR: #139
File: website/jest.config.cjs:4-4
Timestamp: 2025-06-03T16:27:46.172Z
Learning: When reviewing PRs, focus suggestions on the main objectives stated in the PR description. Skip suggestions for incidental changes that are unrelated to the PR's primary purpose, especially when the user explicitly requests to stay focused on the main feature/improvement.

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No inline comments

website/scripts/mongo-migrate.js (4)

Learnt from: killev
PR: #21
File: scripts/merged-prs-last-24h.js:0-0
Timestamp: 2025-04-22T06:57:44.687Z
Learning: For console scripts like merged-prs-last-24h.js, the preferred approach is to allow fatal errors rather than implementing explicit error handling with try-catch blocks, as this makes errors more visible and provides complete stack traces for debugging.

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum parameters: 5

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Use destructuring where possible

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No ternary operators (use if/else)

website/scripts/list-pr-conversations.js (2)

Learnt from: killev
PR: #21
File: scripts/merged-prs-last-24h.js:0-0
Timestamp: 2025-04-22T06:57:44.687Z
Learning: For console scripts like merged-prs-last-24h.js, the preferred approach is to allow fatal errors rather than implementing explicit error handling with try-catch blocks, as this makes errors more visible and provides complete stack traces for debugging.

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

🧬 Code Graph Analysis (2)
website/scripts/resolve-pr-conversation.js (2)
website/scripts/get-pr-number.js (2)
  • require (25-25)
  • result (115-118)
website/scripts/list-pr-conversations.js (3)
  • require (3-3)
  • query (74-74)
  • result (77-80)
website/scripts/get-pr-number.js (3)
website/scripts/list-pr-conversations.js (2)
  • require (3-3)
  • result (77-80)
website/scripts/resolve-pr-conversation.js (3)
  • require (1-1)
  • result (24-27)
  • result (88-91)
website/scripts/mongo-migrate.js (3)
  • require (1-1)
  • result (46-46)
  • result (226-226)
⏰ 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). (4)
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: e2e-tests
  • GitHub Check: security-scan
🔇 Additional comments (15)
website/scripts/mongo-migrate.js (13)

7-20: LGTM!

Good implementation of argument parsing with proper error handling for unknown arguments. The use of for...of loop correctly addresses the previous review feedback.


22-40: LGTM!

Clear and comprehensive help documentation that covers all options and required environment variables.


42-50: LGTM!

Proper environment loading with file access validation and error handling. Good user feedback with success message.


52-80: LGTM!

Excellent environment validation with proper trimming, missing variable detection, and prevention of identical source/target configuration. The validation logic is comprehensive and prevents common configuration errors.


82-89: LGTM!

Good MongoDB client configuration with appropriate timeout settings for production use.


91-94: LGTM!

Clean utility function for retrieving collection names.


96-99: Performance consideration for large collections.

The countDocuments() method can be slow on very large collections, but it's appropriate for migration scripts where accurate counts are essential for verification.


137-151: LGTM!

Proper index migration implementation with correct filtering of the default _id_ index and good error handling for individual index creation failures.


153-173: LGTM!

Excellent verification implementation with parallel processing and clear reporting of count mismatches. The boolean return value makes it easy to determine overall migration success.


175-177: Consider parameter structure for better maintainability.

The function properly uses destructuring from the options parameter, which aligns with the coding conventions for destructuring usage.


266-281: LGTM!

Clean entry point implementation with appropriate error handling for a console script. The fatal error approach aligns with the preferred pattern for such scripts.


283-291: LGTM!

Proper process-level error handling with graceful shutdown support for interrupts.


293-297: LGTM!

Standard Node.js module pattern with appropriate exports for testing and reuse.

website/scripts/get-pr-number.js (1)

1-140: Well-implemented PR number detection script.

The script demonstrates good practices with comprehensive error handling, clear documentation, and proper separation of concerns. The fatal error approach aligns with the preferred pattern for console scripts.

.cursor/rules/conversation-process.mdc (1)

1-167: Comprehensive workflow documentation.

The workflow documentation is well-structured with clear process flows, visual diagrams, and comprehensive decision matrices. It effectively guides the automated processing of PR comments.

Comment on lines +13 to +14
1. Get PR Number: `npx tsx scripts/get-pr-number.ts`
2. Fetch PR Comments: `npx tsx scripts/list-pr-conversations.ts <PR_NUMBER>`
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

Fix script references to match actual implementation.

The workflow references TypeScript scripts (get-pr-number.ts, list-pr-conversations.ts), but the actual scripts are implemented in JavaScript (.js extension).

-1. Get PR Number: `npx tsx scripts/get-pr-number.ts`
-2. Fetch PR Comments: `npx tsx scripts/list-pr-conversations.ts <PR_NUMBER>`
+1. Get PR Number: `node scripts/get-pr-number.js`
+2. Fetch PR Comments: `node scripts/list-pr-conversations.js <PR_NUMBER>`
📝 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
1. Get PR Number: `npx tsx scripts/get-pr-number.ts`
2. Fetch PR Comments: `npx tsx scripts/list-pr-conversations.ts <PR_NUMBER>`
1. Get PR Number: `node scripts/get-pr-number.js`
2. Fetch PR Comments: `node scripts/list-pr-conversations.js <PR_NUMBER>`
🤖 Prompt for AI Agents
In .cursor/rules/conversation-read.mdc around lines 13 to 14, the script
references use the .ts extension, but the actual script files are JavaScript
with .js extensions. Update the commands to use the correct .js file names
instead of .ts to match the actual implementation.

```

## Important Notes
- The `list-pr-comments.ts` script outputs JSON to console for programmatic processing
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

Correct script filename reference.

The documentation references list-pr-comments.ts but the actual script is named list-pr-conversations.js.

-- The `list-pr-comments.ts` script outputs JSON to console for programmatic processing
+- The `list-pr-conversations.js` script outputs JSON to console for programmatic processing
📝 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
- The `list-pr-comments.ts` script outputs JSON to console for programmatic processing
The `list-pr-conversations.js` script outputs JSON to console for programmatic processing
🤖 Prompt for AI Agents
In .cursor/rules/conversation-read.mdc at line 74, update the script filename
reference from `list-pr-comments.ts` to the correct `list-pr-conversations.js`
to ensure the documentation matches the actual script name.

function getPRNumber() {
const args = process.argv.slice(2);
if (args.length === 0) {
console.error('Usage: list-pr-comments.js [PR_NUMBER]');
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

Fix error message script name reference.

The error message references the wrong script name.

-    console.error('Usage: list-pr-comments.js [PR_NUMBER]');
+    console.error('Usage: list-pr-conversations.js [PR_NUMBER]');
📝 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
console.error('Usage: list-pr-comments.js [PR_NUMBER]');
console.error('Usage: list-pr-conversations.js [PR_NUMBER]');
🤖 Prompt for AI Agents
In website/scripts/list-pr-conversations.js at line 8, the error message
incorrectly references the script name as 'list-pr-comments.js'. Update the
error message string to correctly reflect the current script name
'list-pr-conversations.js' to avoid confusion.

Comment on lines 13 to 22
const query = `mutation {
addPullRequestReviewThreadReply(input: {
pullRequestReviewThreadId: "${threadId}",
body: "${comment.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')}"
}) {
comment {
id
}
}
}`;
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

Address GraphQL injection vulnerability.

The GraphQL mutation construction uses direct string interpolation without proper escaping, which could lead to GraphQL injection vulnerabilities if malicious input is provided.

Consider using a GraphQL client library or implement proper parameter binding:

-    const query = `mutation {
-      addPullRequestReviewThreadReply(input: {
-        pullRequestReviewThreadId: "${threadId}",
-        body: "${comment.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')}"
-      }) {
-        comment {
-          id
-        }
-      }
-    }`;
-
-    const result = execSync(`gh api graphql -f query='${query}'`, {
+    const mutation = `mutation($threadId: ID!, $body: String!) {
+      addPullRequestReviewThreadReply(input: {
+        pullRequestReviewThreadId: $threadId,
+        body: $body
+      }) {
+        comment {
+          id
+        }
+      }
+    }`;
+
+    const result = execSync(`gh api graphql -f query='${mutation}' -F threadId='${threadId}' -F body='${comment}'`, {

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In website/scripts/resolve-pr-conversation.js around lines 13 to 22, the GraphQL
mutation query is constructed using direct string interpolation with user input,
which risks GraphQL injection. To fix this, replace the string interpolation
with a GraphQL client library that supports parameterized queries or implement
proper escaping and parameter binding to safely insert variables into the
mutation. Avoid directly embedding user input in the query string.

Comment on lines +79 to +83
const query = `mutation {
resolveReviewThread(input: {threadId: "${conversationId}"}) {
thread { id isResolved }
}
}`;
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 security fix for thread resolution.

The thread resolution mutation has the same GraphQL injection vulnerability.

-    const query = `mutation { 
-      resolveReviewThread(input: {threadId: "${conversationId}"}) { 
-        thread { id isResolved } 
-      } 
-    }`;
+    const mutation = `mutation($threadId: ID!) { 
+      resolveReviewThread(input: {threadId: $threadId}) { 
+        thread { id isResolved } 
+      } 
+    }`;

And update the execSync call:

-    const result = execSync(`gh api graphql -f query='${query}'`, {
+    const result = execSync(`gh api graphql -f query='${mutation}' -F threadId='${conversationId}'`, {
📝 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
const query = `mutation {
resolveReviewThread(input: {threadId: "${conversationId}"}) {
thread { id isResolved }
}
}`;
// Before: direct interpolation leads to potential injection
- const query = `mutation {
- resolveReviewThread(input: {threadId: "${conversationId}"}) {
- thread { id isResolved }
- }
- }`;
+ // Use a parameterized mutation to avoid GraphQL injection
+ const mutation = `mutation($threadId: ID!) {
+ resolveReviewThread(input: {threadId: $threadId}) {
+ thread { id isResolved }
+ }
+ }`;
// ...
- const result = execSync(`gh api graphql -f query='${query}'`, {
+ const result = execSync(
+ `gh api graphql -f query='${mutation}' -F threadId='${conversationId}'`,
+ {
cwd: repoLocalPath,
encoding: 'utf-8',
}
);
🤖 Prompt for AI Agents
In website/scripts/resolve-pr-conversation.js around lines 79 to 83, the GraphQL
mutation string for resolving a review thread is constructed by directly
embedding the conversationId, causing a GraphQL injection vulnerability. To fix
this, refactor the mutation to use GraphQL variables instead of string
interpolation for the threadId. Also, update the execSync call to pass the
variables object properly, ensuring the threadId is safely injected into the
mutation without risk of injection.

- Fix repository owner in PR conversation script from ondatra-ai to speedandfunction

- Fix temporal coupling by moving dotenv config before object definition

- Add AWS credential validation to prevent exposure in error messages

- Add tmp directory to gitignore for temporary files
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

♻️ Duplicate comments (3)
website/scripts/list-pr-conversations.js (1)

8-8: Fix error message script name reference.

The error message references the wrong script name.

-    console.error('Usage: list-pr-comments.js [PR_NUMBER]');
+    console.error('Usage: list-pr-conversations.js [PR_NUMBER]');
website/scripts/s3-copy.js (2)

29-52: LGTM! Robust credential validation implemented.

The credential validation effectively prevents exposure of sensitive AWS credentials in error messages while ensuring proper format checks.


135-142: Missing timeout and size limits in streamToBuffer.

The implementation appears to be missing the timeout and size limit safeguards that were previously suggested and marked as "Acknowledged and resolved". This could lead to memory issues with large objects or hanging streams.

🧹 Nitpick comments (2)
website/scripts/list-pr-conversations.js (1)

76-99: Consider removing explicit error handling to align with console script preferences.

Based on your established preference for console scripts, consider allowing fatal errors rather than explicit try-catch handling for better visibility and complete stack traces.

-  try {
-    const result = execSync(
-      `gh api graphql -f query='${query}' -F prNumber=${prNumber}`,
-      { encoding: 'utf8' },
-    );
-
-    const data = JSON.parse(result);
-    const conversations = parseConversations(data);
-
-    // Sort by creation date of first comment in each conversation
-    conversations.sort((a, b) => {
-      const aFirstComment = a.comments[0]?.createdAt || '';
-      const bFirstComment = b.comments[0]?.createdAt || '';
-      return (
-        new Date(aFirstComment).getTime() - new Date(bFirstComment).getTime()
-      );
-    });
-
-    // Output JSON by default for programmatic use
-    console.log(JSON.stringify(conversations, null, 2));
-  } catch (error) {
-    console.error('Error fetching PR comments:', error);
-    process.exit(1);
-  }
+  const result = execSync(
+    `gh api graphql -f query='${query}' -F prNumber=${prNumber}`,
+    { encoding: 'utf8' },
+  );
+
+  const data = JSON.parse(result);
+  const conversations = parseConversations(data);
+
+  // Sort by creation date of first comment in each conversation
+  conversations.sort((a, b) => {
+    const aFirstComment = a.comments[0]?.createdAt || '';
+    const bFirstComment = b.comments[0]?.createdAt || '';
+    return (
+      new Date(aFirstComment).getTime() - new Date(bFirstComment).getTime()
+    );
+  });
+
+  // Output JSON by default for programmatic use
+  console.log(JSON.stringify(conversations, null, 2));
website/scripts/s3-copy.js (1)

81-106: Add safety limits for very large S3 buckets.

The function loads all object keys into memory at once. For buckets with millions of objects, this could cause memory issues. Consider adding a configurable limit or implementing a streaming approach.

Add an optional maxObjects parameter:

-listObjects(bucket, client) {
+listObjects(bucket, client, maxObjects = null) {
   const fetchPage = (continuationToken) => {
     const command = new ListObjectsV2Command({
       Bucket: bucket,
       ContinuationToken: continuationToken,
+      MaxKeys: maxObjects ? Math.min(1000, maxObjects) : 1000,
     });
     return client.send(command);
   };

   const getAllPages = (token = null, allObjects = []) => {
+    if (maxObjects && allObjects.length >= maxObjects) {
+      return allObjects.slice(0, maxObjects);
+    }
     return fetchPage(token).then((response) => {
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b58260a and dd2ba36.

📒 Files selected for processing (3)
  • .gitignore (1 hunks)
  • website/scripts/list-pr-conversations.js (1 hunks)
  • website/scripts/s3-copy.js (1 hunks)
🧠 Learnings (3)
📓 Common learnings
Learnt from: killev
PR: speedandfunction/website#76
File: website/.eslintrc.js:5-5
Timestamp: 2025-05-10T21:03:18.519Z
Learning: The user (killev) prefers to use 'eslint:all' in the ESLint configuration to enable all rules, despite potential drawbacks like excessive noise, false positives, higher maintenance, and slower linting.
website/scripts/list-pr-conversations.js (2)

Learnt from: killev
PR: #21
File: scripts/merged-prs-last-24h.js:0-0
Timestamp: 2025-04-22T06:57:44.687Z
Learning: For console scripts like merged-prs-last-24h.js, the preferred approach is to allow fatal errors rather than implementing explicit error handling with try-catch blocks, as this makes errors more visible and provides complete stack traces for debugging.

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

website/scripts/s3-copy.js (4)

Learnt from: killev
PR: #100
File: website/modules/@apostrophecms/form/index.js:227-227
Timestamp: 2025-05-19T20:40:04.914Z
Learning: The project intentionally uses the getEnv function for all environment variable access, including in placeholder values. This ensures that all required environment variables are present at application startup (fail-fast approach), even for features that might not be enabled.

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No secrets in code

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum function length enforced (avoid excessive length)

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: killev
PR: speedandfunction/website#76
File: website/.eslintrc.js:5-5
Timestamp: 2025-05-10T21:03:18.519Z
Learning: The user (killev) prefers to use 'eslint:all' in the ESLint configuration to enable all rules, despite potential drawbacks like excessive noise, false positives, higher maintenance, and slower linting.
website/scripts/list-pr-conversations.js (2)

Learnt from: killev
PR: #21
File: scripts/merged-prs-last-24h.js:0-0
Timestamp: 2025-04-22T06:57:44.687Z
Learning: For console scripts like merged-prs-last-24h.js, the preferred approach is to allow fatal errors rather than implementing explicit error handling with try-catch blocks, as this makes errors more visible and provides complete stack traces for debugging.

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

website/scripts/s3-copy.js (4)

Learnt from: killev
PR: #100
File: website/modules/@apostrophecms/form/index.js:227-227
Timestamp: 2025-05-19T20:40:04.914Z
Learning: The project intentionally uses the getEnv function for all environment variable access, including in placeholder values. This ensures that all required environment variables are present at application startup (fail-fast approach), even for features that might not be enabled.

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : No secrets in code

Learnt from: CR
PR: speedandfunction/website#0
File: .cursor/rules/code-conventions.mdc:0-0
Timestamp: 2025-07-01T07:44:33.034Z
Learning: Applies to **/*.{js,jsx} : Maximum function length enforced (avoid excessive length)

Learnt from: yuramax
PR: #120
File: website/modules/asset/ui/src/index.js:43-67
Timestamp: 2025-05-26T06:19:32.209Z
Learning: When reviewing PRs focused on styling, defer functional JavaScript improvements to separate tasks to maintain clear scope separation.

⏰ 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). (4)
  • GitHub Check: e2e-tests
  • GitHub Check: security-scan
  • GitHub Check: unit-tests
  • GitHub Check: lint
🔇 Additional comments (2)
website/scripts/list-pr-conversations.js (2)

14-43: LGTM! GraphQL query structure is well-designed.

The query correctly fetches review threads with necessary comment details, and the hardcoded repository reference appears to have been properly updated to match the actual repository.


45-71: LGTM! Clean data transformation logic.

The function effectively filters unresolved threads and structures the comment data appropriately for programmatic use.

- Replace short variable names with descriptive ones (a,b -> conversationA,conversationB)

- Add Unicode flags to regex patterns for proper Unicode handling

- Replace ternary operators with if/else statements for better readability

- Use array destructuring for command line argument parsing

- Initialize variables at declaration time

- Use underscore prefix for unused destructured variables
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
6 Security Hotspots
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

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.

2 participants