Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughRefactors Outlook/Microsoft Graph paging to prefer direct nextLink URL-based pagination, updates message query functions to return raw Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
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. Comment |
| filters.push("parentFolderId eq 'inbox'"); | ||
| } | ||
| // Determine endpoint and build filters based on query type | ||
| let endpoint = "/me/messages"; |
There was a problem hiding this comment.
parentFolderId is a GUID, not a well-known name. Filtering with parentFolderId eq 'inbox'/'archive' and lowercasing labelId will return no results. Consider resolving folder IDs (e.g., via getFolderIds) and use those IDs, or switch to folder-specific endpoints like /me/mailFolders('inbox')/messages.
🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/cli/src/main.ts (1)
66-71: Version mismatch with version.txt.The CLI version is hardcoded as
"2.21.16"butversion.txtshowsv2.21.29. Consider keeping these in sync or reading the version dynamically.program .name("inbox-zero") .description("CLI tool for running Inbox Zero - AI email assistant") - .version("2.21.16"); + .version("2.21.29");
🧹 Nitpick comments (4)
packages/cli/src/utils.test.ts (1)
181-199: Test assertion may not verify intended behavior.The test "should append values not found in template" expects
CUSTOM_VARto be appended, but the comment on lines 197-198 acknowledges that only values set viasetValuewill be added. SinceCUSTOM_VARis not explicitly handled ingenerateEnvFile, this test doesn't actually verify the append behavior—it only checks thatAUTH_SECRETis set.Consider either:
- Removing this test if append behavior isn't intended for arbitrary env keys
- Or adding an assertion that explicitly validates whether
CUSTOM_VARappears in the resultpackages/cli/src/utils.ts (1)
22-37: Static analysis flagged potential ReDoS, but risk is low in current usage.The static analysis tool flagged regex construction from variable input (CWE-1333). However, in the current implementation,
keyvalues are hardcoded environment variable names (e.g.,DATABASE_URL,AUTH_SECRET), which are safe and don't contain regex metacharacters.The risk would only materialize if
setValuewere exposed to untrusted input. Consider adding a brief comment noting this assumption for future maintainers:// Helper to set a value (handles both commented and uncommented lines) + // Note: key is assumed to be a safe env var name (alphanumeric + underscore) const setValue = (key: string, value: string | undefined) => {packages/cli/src/main.ts (1)
947-959: Main module detection may have edge cases.The
isMainModulecheck relies onprocess.argv[1]ending with specific filenames. This could fail if:
- The script is invoked via a symlink with a different name
- The path contains URL-encoded characters
Consider using a more robust approach if this causes issues in practice:
-const isMainModule = - process.argv[1] && - (process.argv[1].endsWith("main.ts") || - process.argv[1].endsWith("inbox-zero.js") || - process.argv[1].endsWith("inbox-zero")); +import { fileURLToPath } from "node:url"; + +const isMainModule = (() => { + try { + const currentFile = fileURLToPath(import.meta.url); + return process.argv[1] === currentFile; + } catch { + // Fallback for non-file URLs + return process.argv[1]?.endsWith("main.ts") || + process.argv[1]?.endsWith("inbox-zero.js") || + process.argv[1]?.endsWith("inbox-zero"); + } +})();apps/web/utils/email/microsoft.ts (1)
1026-1028: Consider adding retry logic for the direct URL fetch.The direct URL fetch path doesn't use
withOutlookRetry, unlike the similar implementations inmessage.ts(lines 165-166, 309-310). This inconsistency could lead to failures on transient errors.Apply this diff to add retry logic:
// If pageToken is a URL, fetch directly (per MS docs, don't extract $skiptoken) if (options.pageToken?.startsWith("http")) { - response = await client.api(options.pageToken).get(); + response = await withOutlookRetry(() => client.api(options.pageToken).get()); } else {Note: You'll need to import
withOutlookRetryfrom@/utils/outlook/retryif not already imported.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
apps/web/utils/email/microsoft.ts(2 hunks)apps/web/utils/outlook/message.ts(5 hunks)packages/cli/package.json(1 hunks)packages/cli/src/main.ts(8 hunks)packages/cli/src/utils.test.ts(1 hunks)packages/cli/src/utils.ts(1 hunks)packages/cli/vitest.config.ts(1 hunks)version.txt(1 hunks)
🧰 Additional context used
📓 Path-based instructions (13)
!(pages/_document).{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
Don't use the next/head module in pages/_document.js on Next.js projects
Files:
version.txtpackages/cli/vitest.config.tspackages/cli/src/utils.tspackages/cli/src/utils.test.tsapps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.tspackages/cli/src/main.tspackages/cli/package.json
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor error handling in async operations
**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
**/*.{ts,tsx}: For early access feature flags, create hooks using the naming conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g.,inbox-cleaner,pricing-options-2)
Always define types for A/B test variant flags (e.g.,type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting
**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the!postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
packages/cli/vitest.config.tspackages/cli/src/utils.tspackages/cli/src/utils.test.tsapps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.tspackages/cli/src/main.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
packages/cli/vitest.config.tspackages/cli/src/utils.tspackages/cli/src/utils.test.tsapps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.tspackages/cli/src/main.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma'sselectoption. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. AllfindUnique/findFirstcalls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
AllfindManyqueries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g.,emailAccount: { id: emailAccountId }) to validate ownership
Files:
packages/cli/vitest.config.tspackages/cli/src/utils.tspackages/cli/src/utils.test.tsapps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.tspackages/cli/src/main.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
packages/cli/vitest.config.tspackages/cli/src/utils.tspackages/cli/src/utils.test.tsapps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.tspackages/cli/src/main.ts
**/*.{tsx,ts,css}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
Implement responsive design with Tailwind CSS using a mobile-first approach
Files:
packages/cli/vitest.config.tspackages/cli/src/utils.tspackages/cli/src/utils.test.tsapps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.tspackages/cli/src/main.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-hidden="true"on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like<marquee>or<blink>
Only use thescopeprop on<th>elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include atitleelement for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
AssigntabIndexto non-interactive HTML elements witharia-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...
Files:
packages/cli/vitest.config.tspackages/cli/src/utils.tspackages/cli/src/utils.test.tsapps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.tspackages/cli/src/main.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)
**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g.,import groupBy from 'lodash/groupBy')
Files:
packages/cli/vitest.config.tspackages/cli/src/utils.tspackages/cli/src/utils.test.tsapps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.tspackages/cli/src/main.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
**/*.test.{ts,tsx}: Usevitestfor testing the application
Tests should be colocated next to the tested file with.test.tsor.test.tsxextension (e.g.,dir/format.tsanddir/format.test.ts)
Mockserver-onlyusingvi.mock("server-only", () => ({}))
Mock Prisma usingvi.mock("@/utils/prisma")and import the mock from@/utils/__mocks__/prisma
Usevi.clearAllMocks()inbeforeEachto clean up mocks between tests
Each test should be independent
Use descriptive test names
Mock external dependencies in tests
Do not mock the Logger
Avoid testing implementation details
Use test helpersgetEmail,getEmailAccount, andgetRulefrom@/__tests__/helpersfor mocking emails, accounts, and rules
Files:
packages/cli/src/utils.test.ts
**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Make sure the assertion function, like expect, is placed inside an it() function call
Don't use disabled tests
Files:
packages/cli/src/utils.test.ts
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use@/path aliases for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Follow consistent naming conventions using PascalCase for components
Centralize shared types in dedicated type filesImport specific lodash functions rather than entire lodash library to minimize bundle size (e.g.,
import groupBy from 'lodash/groupBy')
Files:
apps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.ts
**/{server,api,actions,utils}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/{server,api,actions,utils}/**/*.ts: UsecreateScopedLoggerfrom "@/utils/logger" for logging in backend code
Add thecreateScopedLoggerinstantiation at the top of the file with an appropriate scope name
Use.with()method to attach context variables only within specific functions, not on global loggers
For large functions with reused variables, usecreateScopedLogger().with()to attach context once and reuse the logger without passing variables repeatedly
Files:
apps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.ts
**/package.json
📄 CodeRabbit inference engine (.cursor/rules/installing-packages.mdc)
Use
pnpmas the package manager
Files:
packages/cli/package.json
🧠 Learnings (26)
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Use vitest imports (`describe`, `expect`, `test`, `vi`, `beforeEach`) in LLM test files
Applied to files:
packages/cli/vitest.config.tspackages/cli/src/utils.test.tspackages/cli/package.json
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use `vitest` for testing the application
Applied to files:
packages/cli/vitest.config.tspackages/cli/package.json
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/{.env.example,env.ts,turbo.json} : Add environment variables to `.env.example`, `env.ts`, and `turbo.json`
Applied to files:
packages/cli/src/utils.tspackages/cli/src/main.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to apps/web/env.ts : Add client-side environment variables to `apps/web/env.ts` under the `client` object with `NEXT_PUBLIC_` prefix and Zod schema validation
Applied to files:
packages/cli/src/utils.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to apps/web/env.ts : Add client-side environment variables to `apps/web/env.ts` under the `experimental__runtimeEnv` object to enable runtime access
Applied to files:
packages/cli/src/utils.ts
📚 Learning: 2025-11-25T14:36:43.454Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:43.454Z
Learning: Applies to apps/web/env.ts : Define environment variables in `apps/web/env.ts` using Zod schema validation, organizing them into `server` and `client` sections
Applied to files:
packages/cli/src/utils.ts
📚 Learning: 2025-11-25T14:36:43.454Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:43.454Z
Learning: Applies to apps/web/env.ts : For client-side environment variables in `apps/web/env.ts`, prefix them with `NEXT_PUBLIC_` and add them to both the `client` and `experimental__runtimeEnv` sections
Applied to files:
packages/cli/src/utils.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to {.env.example,apps/web/env.ts} : Client-side environment variables must be prefixed with `NEXT_PUBLIC_`
Applied to files:
packages/cli/src/utils.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to apps/web/env.ts : Add server-only environment variables to `apps/web/env.ts` under the `server` object with Zod schema validation
Applied to files:
packages/cli/src/utils.ts
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't hardcode sensitive data like API keys and tokens
Applied to files:
packages/cli/src/utils.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to turbo.json : Add new environment variables to `turbo.json` under `tasks.build.env` as a global dependency for the build task
Applied to files:
packages/cli/src/utils.ts
📚 Learning: 2025-11-25T14:36:18.416Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-11-25T14:36:18.416Z
Learning: Applies to apps/web/**/*NEXT_PUBLIC_* : Prefix client-side environment variables with `NEXT_PUBLIC_`
Applied to files:
packages/cli/src/utils.ts
📚 Learning: 2025-11-25T14:39:04.892Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-11-25T14:39:04.892Z
Learning: No hardcoded secrets in code; all secrets must be stored in environment variables (e.g., CRON_SECRET)
Applied to files:
packages/cli/src/utils.ts
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to **/*.test.ts : Include security tests in test suites to verify: authentication is required, IDOR protection works (other users cannot access resources), parameter validation rejects invalid inputs, and error messages don't leak information
Applied to files:
packages/cli/src/utils.test.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/__tests__/**/*.{ts,tsx} : AI tests must be placed in the `__tests__` directory and are not run by default (they use a real LLM)
Applied to files:
packages/cli/src/utils.test.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use descriptive test names
Applied to files:
packages/cli/src/utils.test.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Use `console.debug()` for outputting generated LLM content in tests, e.g., `console.debug("Generated content:\n", result.content);`
Applied to files:
packages/cli/src/utils.test.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Each test should be independent
Applied to files:
packages/cli/src/utils.test.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers
Applied to files:
packages/cli/src/utils.test.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Use `describe.runIf(isAiTest)` with environment variable `RUN_AI_TESTS === "true"` to conditionally run LLM tests
Applied to files:
packages/cli/src/utils.test.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules
Applied to files:
packages/cli/src/utils.test.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Avoid testing implementation details
Applied to files:
packages/cli/src/utils.test.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Applied to files:
apps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Applied to files:
apps/web/utils/email/microsoft.tsapps/web/utils/outlook/message.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Keep Gmail provider-specific implementation details isolated within the apps/web/utils/gmail/ directory
Applied to files:
apps/web/utils/email/microsoft.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
Applied to files:
apps/web/utils/email/microsoft.ts
🧬 Code graph analysis (3)
packages/cli/src/utils.ts (2)
apps/web/scripts/check-enum-imports.js (1)
content(74-74)apps/web/env.ts (1)
env(17-244)
apps/web/utils/outlook/message.ts (1)
apps/web/utils/outlook/retry.ts (1)
withOutlookRetry(19-80)
packages/cli/src/main.ts (2)
apps/web/env.ts (1)
env(17-244)packages/cli/src/utils.ts (1)
generateEnvFile(11-134)
🪛 ast-grep (0.40.0)
packages/cli/src/utils.ts
[warning] 25-25: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^${key}=.*$, "m")
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
[warning] 26-26: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^# ${key}=.*$, "m")
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
⏰ 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: cubic · AI code reviewer
- GitHub Check: Review for correctness
- GitHub Check: test
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (19)
version.txt (1)
1-1: LGTM!Version bump to v2.21.29 aligns with the CLI fixes and test additions in this PR.
packages/cli/package.json (1)
16-27: LGTM!Test scripts and Vitest dependency are properly configured. Based on learnings, using
vitestfor testing aligns with the project's testing standards.packages/cli/vitest.config.ts (1)
1-13: LGTM!Clean Vitest configuration. Single-threaded execution is appropriate for CLI tests that may interact with filesystem or environment variables.
packages/cli/src/utils.test.ts (2)
1-26: LGTM!Well-structured tests for
generateSecretcovering length, format validation, and uniqueness. Good use of descriptive test names as per coding guidelines.
28-389: Comprehensive test coverage forgenerateEnvFile.Excellent coverage of:
- Value replacement in templates
- Docker-specific configuration
- Multiple LLM providers (Anthropic, OpenAI, Bedrock)
- Commented line handling
- Template structure preservation
Tests are independent and use descriptive names as per coding guidelines.
packages/cli/src/utils.ts (3)
6-9: LGTM!Secure secret generation using
node:crypto'srandomByteswith proper hex encoding.
43-56: Verify quoted value handling consistency.
DATABASE_URLandUPSTASH_REDIS_URLare wrapped in quotes (lines 48-49, 53-54), whileUPSTASH_REDIS_TOKENand other values are not. This is intentional for URLs containing special characters, but ensure the template and downstream parsing handle this consistently.
113-131: LGTM!Clean provider-specific API key handling with a well-structured mapping. The conditional logic correctly distinguishes Bedrock (multi-key) from other providers (single API key).
packages/cli/src/main.ts (5)
9-9: LGTM!Clean import of utilities from the new utils module, properly separating concerns.
168-193: LGTM!Good UX enhancement asking users whether the web app runs on host or in Docker, with clear hints for each option. Proper cancellation handling.
524-533: LGTM!Correctly differentiates container hostnames (
db,serverless-redis-http) when web runs in Docker vslocalhostwith exposed ports when running on host.
584-608: LGTM!Template fetching with proper error handling and spinner feedback. The
generateEnvFileintegration cleanly delegates env content generation to the utility function.
909-928: LGTM!Clean template loading with local file fallback for in-repo development and remote fetch for standalone usage. Proper error propagation.
apps/web/utils/outlook/message.ts (3)
163-174: LGTM - Correct URL-based pagination implementation.The direct fetch approach for URL-based pageToken follows Microsoft Graph API best practices. Using the full
@odata.nextLinkURL preserves all query parameters and state.One consideration: the folder filtering after fetch (lines 168-170) could return fewer results than expected per page when
folderIdis specified, since filtering happens client-side.
306-314: LGTM - Consistent URL-based pagination handling.The implementation mirrors the approach in
queryBatchMessages, maintaining consistency across both query functions. The retry wrapper is correctly applied.
263-264: Clarify the orderby mechanism for subsequent pages.The comment "Only add orderby for first page to avoid sorting complexity errors" doesn't explain how this is enforced. In reality, subsequent pages use URL-based pagination (
@odata.nextLink) which bypasses this code path entirely via the early return at line 30. The unconditionalorderbyis correct but would be clearer if the comment explained that URL-based pagination on subsequent pages avoids reapplying it.apps/web/utils/email/microsoft.ts (3)
1012-1022: Good addition of local type for type safety.The
GraphMessagetype provides better type safety for the Microsoft Graph response. This is a clean approach for handling the API response structure.
1029-1090: LGTM - Well-structured request construction.The request construction logic is cleanly organized with:
- Proper endpoint selection based on query type
- Appropriate filter building for different scenarios
- Conditional ordering to avoid complexity errors with
fromEmailfilterThe use of
escapeODataStringfor user inputs provides proper protection against OData injection.
1187-1187: LGTM - Consistent nextPageToken handling.Using the raw
@odata.nextLinkvalue aligns with the pagination changes inmessage.ts, ensuring consistent behavior across the codebase.
There was a problem hiding this comment.
2 issues found across 9 files
Prompt for AI agents (all 2 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/cli/src/utils.test.ts">
<violation number="1" location="packages/cli/src/utils.test.ts:181">
P2: Test title claims to verify "append values not found in template" but has no assertion for `CUSTOM_VAR`. The comment suggests uncertainty about the expected behavior. Either add an assertion to verify `CUSTOM_VAR` is/isn't in the result, or rename the test to accurately reflect what it tests.</violation>
</file>
<file name="packages/cli/src/utils.ts">
<violation number="1" location="packages/cli/src/utils.ts:48">
P1: When `env.DATABASE_URL` is undefined, the template literal produces the string `"undefined"` (not the `undefined` value), bypassing `setValue`'s undefined check and writing an invalid `DATABASE_URL="undefined"` to the env file. Same issue affects lines 48, 52, 53.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
packages/cli/src/utils.test.ts
Outdated
| expect(result).not.toContain("# DATABASE_URL="); | ||
| }); | ||
|
|
||
| it("should append values not found in template", () => { |
There was a problem hiding this comment.
P2: Test title claims to verify "append values not found in template" but has no assertion for CUSTOM_VAR. The comment suggests uncertainty about the expected behavior. Either add an assertion to verify CUSTOM_VAR is/isn't in the result, or rename the test to accurately reflect what it tests.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/utils.test.ts, line 181:
<comment>Test title claims to verify "append values not found in template" but has no assertion for `CUSTOM_VAR`. The comment suggests uncertainty about the expected behavior. Either add an assertion to verify `CUSTOM_VAR` is/isn't in the result, or rename the test to accurately reflect what it tests.</comment>
<file context>
@@ -0,0 +1,390 @@
+ expect(result).not.toContain("# DATABASE_URL=");
+ });
+
+ it("should append values not found in template", () => {
+ const minimalTemplate = `# Minimal
+AUTH_SECRET=
</file context>
✅ Addressed in a1612d8
packages/cli/src/utils.ts
Outdated
| setValue("POSTGRES_USER", env.POSTGRES_USER); | ||
| setValue("POSTGRES_PASSWORD", env.POSTGRES_PASSWORD); | ||
| setValue("POSTGRES_DB", env.POSTGRES_DB); | ||
| setValue("DATABASE_URL", `"${env.DATABASE_URL}"`); |
There was a problem hiding this comment.
P1: When env.DATABASE_URL is undefined, the template literal produces the string "undefined" (not the undefined value), bypassing setValue's undefined check and writing an invalid DATABASE_URL="undefined" to the env file. Same issue affects lines 48, 52, 53.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/utils.ts, line 48:
<comment>When `env.DATABASE_URL` is undefined, the template literal produces the string `"undefined"` (not the `undefined` value), bypassing `setValue`'s undefined check and writing an invalid `DATABASE_URL="undefined"` to the env file. Same issue affects lines 48, 52, 53.</comment>
<file context>
@@ -0,0 +1,134 @@
+ setValue("POSTGRES_USER", env.POSTGRES_USER);
+ setValue("POSTGRES_PASSWORD", env.POSTGRES_PASSWORD);
+ setValue("POSTGRES_DB", env.POSTGRES_DB);
+ setValue("DATABASE_URL", `"${env.DATABASE_URL}"`);
+ setValue("UPSTASH_REDIS_URL", `"${env.UPSTASH_REDIS_URL}"`);
+ setValue("UPSTASH_REDIS_TOKEN", env.UPSTASH_REDIS_TOKEN);
</file context>
✅ Addressed in a1612d8
|
|
||
| // Helper to wrap a value in quotes if defined (prevents "undefined" string bug) | ||
| const wrapInQuotes = (value: string | undefined): string | undefined => | ||
| value !== undefined ? `"${value}"` : undefined; |
There was a problem hiding this comment.
wrapInQuotes doesn’t escape " or \, so values with quotes/backslashes can produce invalid .env lines. Consider escaping backslashes first, then quotes, before wrapping.
- value !== undefined ? `"${value}"` : undefined;
+ value !== undefined ? `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"` : undefined;🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
| ]; | ||
| for (const pattern of patterns) { | ||
| if (pattern.test(content)) { | ||
| content = content.replace(pattern, `${key}=${value}`); |
There was a problem hiding this comment.
String.prototype.replace treats $ in the replacement string as special tokens, so values like $1/$& corrupt the output. Consider using the functional form of replace to ensure value is inserted verbatim.
| content = content.replace(pattern, `${key}=${value}`); | |
| content = content.replace(pattern, () => `${key}=${value}`); |
🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
There was a problem hiding this comment.
1 issue found across 4 files (changes from recent commits).
Prompt for AI agents (all 1 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/cli/src/main.ts">
<violation number="1" location="packages/cli/src/main.ts:661">
P2: Missing `--env-file ${envFile}` flag for standalone installs. For consistency with the `runWebInDocker` case and to ensure Docker Compose can find environment variables (POSTGRES_PASSWORD, UPSTASH_REDIS_TOKEN, etc.) needed by database and Redis containers, the `--env-file` flag should be included.
(Based on your team's feedback about cross-service env var dependency.) [FEEDBACK_USED]</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| // Web app runs on host (pnpm dev or pnpm start) | ||
| const dockerStep = useDockerInfra | ||
| ? "# Start Docker services (database & Redis):\ndocker compose --profile local-db --profile local-redis up -d\n\n" | ||
| ? `# Start Docker services (database & Redis):\n${composeCmd} --profile local-db --profile local-redis up -d\n\n` |
There was a problem hiding this comment.
P2: Missing --env-file ${envFile} flag for standalone installs. For consistency with the runWebInDocker case and to ensure Docker Compose can find environment variables (POSTGRES_PASSWORD, UPSTASH_REDIS_TOKEN, etc.) needed by database and Redis containers, the --env-file flag should be included.
(Based on your team's feedback about cross-service env var dependency.)
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/main.ts, line 661:
<comment>Missing `--env-file ${envFile}` flag for standalone installs. For consistency with the `runWebInDocker` case and to ensure Docker Compose can find environment variables (POSTGRES_PASSWORD, UPSTASH_REDIS_TOKEN, etc.) needed by database and Redis containers, the `--env-file` flag should be included.
(Based on your team's feedback about cross-service env var dependency.) </comment>
<file context>
@@ -640,26 +640,25 @@ Full guide: https://docs.getinboxzero.com/self-hosting/microsoft-oauth`,
// Web app runs on host (pnpm dev or pnpm start)
const dockerStep = useDockerInfra
- ? "# Start Docker services (database & Redis):\ndocker compose --profile local-db --profile local-redis up -d\n\n"
+ ? `# Start Docker services (database & Redis):\n${composeCmd} --profile local-db --profile local-redis up -d\n\n`
: "";
const migrateCmd = isDevMode
</file context>
| ? `# Start Docker services (database & Redis):\n${composeCmd} --profile local-db --profile local-redis up -d\n\n` | |
| ? `# Start Docker services (database & Redis):\n${composeCmd} --env-file ${envFile} --profile local-db --profile local-redis up -d\n\n` |
Switch Outlook pagination to accept and return full @odata.nextLink URLs and add CLI .env template generation with test coverage
Update Outlook message queries to use full
@odata.nextLinkURLs instead of$skiptoken, and refactor the CLI to generate.envfrom a template with Docker/host-aware values and add Vitest tests.📍Where to Start
Start with
OutlookProvider.getMessagesin microsoft.ts, then review CLI entry in main.ts and the.envgenerator in utils.ts.📊 Macroscope summarized 78b32d8. 5 files reviewed, 18 issues evaluated, 18 issues filtered, 0 comments posted
🗂️ Filtered Issues
apps/web/utils/email/microsoft.ts — 0 comments posted, 5 evaluated, 5 filtered
parentFolderId eq 'inbox'or'archive'(and mappinglabelIdviatoLowerCase()intoparentFolderId) is wrong.parentFolderIdcontains the actual folder GUID/ID, not the well-known name. These filters will usually return no results. For well-known folders, use endpoints like/me/mailFolders('inbox')/messages; for arbitrary folders, resolve the folder ID first (e.g., viagetFolderIdsor lookup) and filter by that ID. [ Already posted ]labelIdfromThreadsQueryas Outlook folder ID. The query schema comment indicateslabelIdis "For Google". Treating it asparentFolderIdin Outlook (filters.push("parentFolderId eq '${labelId.toLowerCase()}'")) may filter on an unrelated string and return empty or wrong results. Outlook categories are separate from folders; if the intent is to filter by folder, accept a dedicated Outlook folder ID/name and resolve to the actual folder ID; if by category, usecategoriesin filters. [ Already posted ]options.pageTokenis provided and is NOT a full URL, the code no longer appliesskipToken(pageToken)to the request, causing the first page to be refetched and breaking pagination. Only URL tokens are supported now, which is a silent behavior change. This can lead to repeated results or stalled pagination if callers pass$skiptokenvalues. Fix by supporting both formats: ifpageTokenstarts withhttp, fetch it directly; otherwise call.skipToken(pageToken)on the request. [ Low confidence ]convertMessages(...).filter(!isDraft)), this implementation buildsParsedMessageobjects directly from Graph messages without checkingmessage.isDraft. As a result, threads can include draft messages, which likely violates expected thread content semantics and may surface incomplete/internal drafts to clients. Add a check to skip messages withisDraft === truebefore grouping or when mapping toParsedMessage. [ Low confidence ]nextPageToken: previously code extracted$skiptokenvianew URL(nextLink).searchParams.get("$skiptoken"), returning the token string. Now it returns the full@odata.nextLinkURL. If upstream clients or APIs expect the bare$skiptoken(as suggested by earlier code and common Graph SDK patterns), this breaks pagination interoperability and may cause clients to pass non-URL tokens back, which this method no longer honors. Clarify and consistently enforce token format or support both formats on input and output. [ Low confidence ]apps/web/utils/outlook/message.ts — 0 comments posted, 3 evaluated, 3 filtered
options.maxResults > 20,queryBatchMessageslogs{ maxResults }(lines 156-157), butmaxResultshas already been capped withMath.min(...)and will be ≤ 20. This misreports the requested value in logs, making diagnostics misleading. Logoptions.maxResultsinstead. [ Low confidence ]queryBatchMessagesnow returnsnextPageTokenas the full@odata.nextLinkURL (see assignments tonextPageToken), and only consumes apageTokenwhen itstartsWith("http")(lines 164-174). Any existing callers that previously stored and passed the extracted$skiptoken(a non-URL string) will now have theirpageTokensilently ignored, causing the function to re-fetch the first page and potentially loop or duplicate results. This is a runtime regression and externally-visible contract change. Ensure either backward compatibility (accept old$skiptokenvia.skipToken) or explicitly migrate all callers to pass the full@odata.nextLinkURL. [ Low confidence ]queryMessagesWithFiltersnow returnsnextPageTokenas the full@odata.nextLinkURL (line 363), and only consumes apageTokenwhen itstartsWith("http")(lines 308-314). If existing callers pass previously returned non-URL$skiptokenstrings, the token is ignored and the function re-fetches the first page, breaking pagination and risking duplicate/looped results. Maintain backward compatibility by accepting legacy$skiptokenvia.skipToken(pageToken)or require and enforce migration to URL tokens. [ Low confidence ]packages/cli/src/main.ts — 0 comments posted, 5 evaluated, 5 filtered
REPO_ROOTis truthy (running inside the repo), the code writes the env file toapps/web/.envwithout ensuring that the parent directoryapps/webexists. OnlyensureConfigDir(configDir)is called withconfigDirset toREPO_ROOT, which does not createapps/web. If the repository structure is missingapps/web(e.g., partial checkout, renamed folder, or different layout),writeFileSync(envFile, envContent)will throw at runtime withENOENT. [ Low confidence ]fetchEnvExampleperforms a network request without timeout/abort handling. In degraded networks the call can hang indefinitely, stalling the CLI with no fallback or user-visible outcome. [ Low confidence ]fetchis used without a polyfill or environment guard. In Node.js versions prior to 18,fetchis not defined, causing aReferenceErrorat runtime whenfetchEnvExampleis invoked. [ Low confidence ]getEnvTemplateonly falls back tofetchEnvExamplewhen the file does not exist. If the file exists but is unreadable (e.g., EACCES) or becomes missing after the check, the function throws instead of providing a defined fallback path, violating the intended contract of always returning the template or fetching it remotely. [ Low confidence ]existsSync(templatePath)can return true whilereadFileSync(templatePath, "utf-8")subsequently throws (e.g., file removed or permission denied), causing an unhandled exception instead of falling back tofetchEnvExample. [ Already posted ]packages/cli/src/utils.ts — 0 comments posted, 5 evaluated, 5 filtered
wrapInQuotesreturns"${value}"without escaping inner quotes (") or backslashes (\). Values containing quotes/backslashes will produce ambiguous or invalid.enventries. Implement proper escaping (e.g., replace"with\"and\with\\) before wrapping. [ Low confidence ]setValueonly updates the first match and returns, leaving other occurrences stale. This silently produces duplicate or inconsistent entries in the output.env. To enforce uniqueness, update all occurrences or remove extras, then write a single canonical entry. [ Low confidence ]String.prototype.replacewith a regex and a literal replacement string that includes the user-suppliedvaluecan corrupt the output whenvaluecontains$sequences (e.g.,$1,$&,$$). In JavaScript,$tokens in the replacement string are interpreted specially. This can produce malformed.envlines or strip parts of secrets. To avoid this, use the functional form ofreplace(e.g.,content = content.replace(pattern, () =>${key}=${value})) or escape$invaluebefore replacing. [ Already posted ].envfile without quoting or escaping. If a value contains spaces,#,=, newlines, or quotes, the resulting line can be malformed or parsed incorrectly by dotenv parsers. OnlyDATABASE_URLandUPSTASH_REDIS_URLare wrapped in quotes; other keys (including secrets and tokens) are not. All values should be consistently quoted and inner quotes/backslashes escaped to ensure valid, parseable output. [ Already posted ]llmProvideris used to decide which API key to set, but the code also writesDEFAULT_LLM_PROVIDERfromenv.DEFAULT_LLM_PROVIDERwithout validating consistency. IfllmProviderdiffers fromenv.DEFAULT_LLM_PROVIDER, the output.envcan specify provider A while configuring an API key for provider B, leading to misconfiguration at runtime. Validate and align these or derive one from the other. [ Low confidence ]Summary by CodeRabbit
Refactor
New Features
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.