Repository navigation
correct payment stripe - #148
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR persists checkout-session state (sessionId and optional receiptId) in the Invoices UI and, upon Stripe checkout completion, conditionally confirms payment with the backend using those IDs; it also adds the optional ChangesInvoices UI & Types
Tests & Test Runner
CI / Build / Containerization
Monitoring & Observability
Misc Tooling & Formatting
Sequence Diagram(s)sequenceDiagram
participant Browser
participant InvoicesUI as Invoices Component
participant Stripe as Stripe Checkout
participant Backend as InvoicesService/API
participant Cache as ReactQuery Cache
Browser->>InvoicesUI: open checkout dialog
InvoicesUI->>Stripe: createCheckoutSession()
Stripe-->>InvoicesUI: checkoutSessionResponse { sessionId, receiptId? }
InvoicesUI->>InvoicesUI: persist sessionId, receiptId
Browser->>Stripe: complete payment
Stripe-->>InvoicesUI: sessionId (callback)
alt sessionId and receiptId present
InvoicesUI->>Backend: confirmPayment(sessionId, receiptId)
Backend-->>InvoicesUI: confirmation success
InvoicesUI->>Cache: invalidate invoices query
InvoicesUI->>Browser: show success toast, clear state
else missing IDs
InvoicesUI->>Cache: invalidate invoices query
InvoicesUI->>Browser: clear state, show fallback
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
components/app/invoices/Invoices.tsx (2)
254-255: ⚡ Quick winConsider using
invoice.idas fallback forreceiptId.The
receiptIdfield is optional in the response, but you already passinvoice.idtocreateIndividualCheckoutSession. If the backend doesn't returnreceiptId, the confirmation flow at line 1311 will be skipped. Using the invoice ID as a fallback would make this more robust.Proposed fix using mutation variables
- onSuccess: async (data) => { + onSuccess: async (data, invoice) => { // Stripe Embedded Checkout gère l'affichage du succès/échec setSelectedInvoice(undefined); setPaymentInvoiceLabel(''); setPaymentClientSecret(data.clientSecret ?? ''); setPaymentSessionId(data.sessionId); - setPaymentReceiptId(data.receiptId); + setPaymentReceiptId(data.receiptId ?? invoice.id);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/app/invoices/Invoices.tsx` around lines 254 - 255, The backend's optional data.receiptId may be undefined causing the confirmation flow to be skipped; update the call site after createIndividualCheckoutSession to setPaymentReceiptId(data.receiptId ?? invoice.id) so the invoice.id is used as a fallback while still calling setPaymentSessionId(data.sessionId); modify the logic around setPaymentReceiptId in the component to prefer data.receiptId but default to invoice.id to ensure the confirmation flow (which checks the receipt ID) always runs.
1329-1337: 💤 Low valueConsider clearing dialog state after confirmation failure.
When
confirmPaymentfails, the error toast is shown but the payment dialog remains open with stale state. Since the Stripe payment may have already succeeded, leaving the checkout UI visible could confuse the user. Consider clearing state in the catch block as well.Proposed fix
.catch((error: unknown) => { + setPaymentClientSecret(undefined); + setPaymentSessionId(undefined); + setPaymentReceiptId(undefined); + setPaymentInvoiceLabel(''); toast.error( localizeErrorMessage( error, dictionary, t.fetchError ) ); + void queryClient.invalidateQueries({ + queryKey: ['received-invoices'], + }); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/app/invoices/Invoices.tsx` around lines 1329 - 1337, When confirmPayment fails in the .catch block, clear the payment dialog state so stale UI doesn't remain; after showing the toast call the same state-reset logic used on successful close — e.g. call setIsPaymentDialogOpen(false) (or the component's equivalent), resetPaymentForm() (or clear payment form fields), setSelectedPaymentMethod(null), and setPaymentProcessing(false) so the dialog closes and internal payment-related state is cleared; reference the confirmPayment catch handler and the state setters/reset helpers used elsewhere in Invoices.tsx (like setIsPaymentDialogOpen, resetPaymentForm, setSelectedPaymentMethod) to implement the cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@components/app/invoices/Invoices.tsx`:
- Around line 1338-1346: The else branch that clears payment state
(setPaymentClientSecret, setPaymentSessionId, setPaymentReceiptId,
setPaymentInvoiceLabel) and invalidates the received-invoices query currently
gives no user feedback; update that branch to also show the same success
toast/notification used in the success path (the one invoked around line 1326)
so users receive confirmation after completing Stripe checkout even when
session/receipt IDs are absent, ensuring the toast is called after state clears
and before/after queryClient.invalidateQueries(['received-invoices']) as
appropriate.
---
Nitpick comments:
In `@components/app/invoices/Invoices.tsx`:
- Around line 254-255: The backend's optional data.receiptId may be undefined
causing the confirmation flow to be skipped; update the call site after
createIndividualCheckoutSession to setPaymentReceiptId(data.receiptId ??
invoice.id) so the invoice.id is used as a fallback while still calling
setPaymentSessionId(data.sessionId); modify the logic around setPaymentReceiptId
in the component to prefer data.receiptId but default to invoice.id to ensure
the confirmation flow (which checks the receipt ID) always runs.
- Around line 1329-1337: When confirmPayment fails in the .catch block, clear
the payment dialog state so stale UI doesn't remain; after showing the toast
call the same state-reset logic used on successful close — e.g. call
setIsPaymentDialogOpen(false) (or the component's equivalent),
resetPaymentForm() (or clear payment form fields),
setSelectedPaymentMethod(null), and setPaymentProcessing(false) so the dialog
closes and internal payment-related state is cleared; reference the
confirmPayment catch handler and the state setters/reset helpers used elsewhere
in Invoices.tsx (like setIsPaymentDialogOpen, resetPaymentForm,
setSelectedPaymentMethod) to implement the cleanup.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 20d80269-c2b7-4386-b36c-5684e77d0284
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (2)
components/app/invoices/Invoices.tsxtypes/services/invoicesResponses.ts
| } else { | ||
| setPaymentClientSecret(undefined); | ||
| setPaymentSessionId(undefined); | ||
| setPaymentReceiptId(undefined); | ||
| setPaymentInvoiceLabel(''); | ||
| void queryClient.invalidateQueries({ | ||
| queryKey: ['received-invoices'], | ||
| }); | ||
| } |
There was a problem hiding this comment.
Missing user feedback when IDs are absent.
When paymentSessionId or paymentReceiptId is missing, the else branch clears state and invalidates queries but shows no success toast. The user completes payment in Stripe's UI but receives no confirmation message, which creates an inconsistent experience compared to the success path at line 1326.
Proposed fix to add success feedback
} else {
setPaymentClientSecret(undefined);
setPaymentSessionId(undefined);
setPaymentReceiptId(undefined);
setPaymentInvoiceLabel('');
void queryClient.invalidateQueries({
queryKey: ['received-invoices'],
- });
+ }).then(() => {
+ toast.success(t.payment.successful);
+ });
}📝 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.
| } else { | |
| setPaymentClientSecret(undefined); | |
| setPaymentSessionId(undefined); | |
| setPaymentReceiptId(undefined); | |
| setPaymentInvoiceLabel(''); | |
| void queryClient.invalidateQueries({ | |
| queryKey: ['received-invoices'], | |
| }); | |
| } | |
| } else { | |
| setPaymentClientSecret(undefined); | |
| setPaymentSessionId(undefined); | |
| setPaymentReceiptId(undefined); | |
| setPaymentInvoiceLabel(''); | |
| void queryClient.invalidateQueries({ | |
| queryKey: ['received-invoices'], | |
| }).then(() => { | |
| toast.success(t.payment.successful); | |
| }); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/app/invoices/Invoices.tsx` around lines 1338 - 1346, The else
branch that clears payment state (setPaymentClientSecret, setPaymentSessionId,
setPaymentReceiptId, setPaymentInvoiceLabel) and invalidates the
received-invoices query currently gives no user feedback; update that branch to
also show the same success toast/notification used in the success path (the one
invoked around line 1326) so users receive confirmation after completing Stripe
checkout even when session/receipt IDs are absent, ensuring the toast is called
after state clears and before/after
queryClient.invalidateQueries(['received-invoices']) as appropriate.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
test/Invoices.test.tsx (1)
11-15: ⚡ Quick winMock the full
useQuerycontract used byInvoices.In
components/app/invoices/Invoices.tsx(Lines 165-194), the component consumesisFetching,refetch, andisError. The current mock omits these and can let undefined behavior slip through tests.♻️ Proposed mock shape update
vi.mock('@tanstack/react-query', () => ({ - useQuery: () => ({ data: undefined, isLoading: false, error: undefined }), + useQuery: () => ({ + data: undefined, + isLoading: false, + isFetching: false, + isError: false, + error: undefined, + refetch: vi.fn(), + }), useMutation: () => ({ mutate: vi.fn(), isPending: false }), useQueryClient: () => ({ invalidateQueries: vi.fn() }), }));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/Invoices.test.tsx` around lines 11 - 15, The test mock for useQuery in test/Invoices.test.tsx is missing fields the Invoices component reads (isFetching, refetch, isError); update the vi.mock for '@tanstack/react-query' so the useQuery mock returns the full contract used by components/app/invoices/Invoices.tsx — include isFetching (boolean), isError (boolean), and refetch (vi.fn() or async noop) alongside data/isLoading/error; keep sensible defaults (false/undefined) and use vi.fn() for refetch to avoid undefined behavior in tests.vitest.setup.ts (1)
6-6: ⚡ Quick winAlign test backend URL with the app API base path.
Line 6setsNEXT_PUBLIC_BACKENDtohttp://localhost:3000, while app request code defaults to an/apibase (lib/requests.ts, Lines 66-68). Keeping tests on an API-shaped base avoids path-related false positives.♻️ Proposed change
-process.env.NEXT_PUBLIC_BACKEND = 'http://localhost:3000'; +process.env.NEXT_PUBLIC_BACKEND = 'http://127.0.0.1:4789/api';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vitest.setup.ts` at line 6, The test env sets NEXT_PUBLIC_BACKEND to 'http://localhost:3000' which doesn't include the app's API base path used in lib/requests.ts (the code that appends '/api' to requests), causing path mismatches in tests; update the value in vitest.setup.ts to include the same API base (for example 'http://localhost:3000/api') so tests use the same base path as the request-building logic (referencing NEXT_PUBLIC_BACKEND and lib/requests.ts).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@test/Invoices.test.tsx`:
- Around line 26-72: Add tests exercising the checkout-completion flow in
Invoices: simulate the component behavior when a checkout completion is detected
(e.g., URL query params or props that trigger the flow), mock the confirmPayment
function to return success and failure cases, mock/session storage helpers that
persist session/receipt (e.g., persistSession or persistReceipt) and ensure they
are read then cleared, and mock the cache invalidation function (e.g.,
invalidateQueries) and toast helpers (e.g., showToastSuccess/showToastError).
For success: assert confirmPayment is called, invalidateQueries is invoked,
session/receipt persistence is removed, and success toast was shown; for
failure: assert confirmPayment was called, cleanup still runs, and error toast
was shown. Use the Invoices component render with RTL, jest.fn() mocks for
confirmPayment/persistence/invalidation/toasts, and simulate the completion
trigger (query param or prop) to validate both success and error paths.
In `@test/Logs.test.tsx`:
- Around line 159-164: The test title and assertion are mismatched: update the
spec for the Logs component so it either (A) is renamed to reflect that it only
verifies the search input (change the it() description) or (B) actually asserts
the "no results" behavior by rendering Logs with an empty logs dataset (pass an
empty logs prop or a mock with zero items) and then asserting the no-results
message is shown (use screen.getByText(...) or getByRole to check the "no
results" string from mockDictionary). Locate the test containing render(<Logs
dictionary={mockDictionary} lang="en" />) and screen.getByPlaceholderText(...)
and apply one of these two fixes.
In `@vitest.config.ts`:
- Line 6: Replace the use of import.meta.dirname by deriving __dirname from the
imported fileURLToPath and path utilities: use fileURLToPath(import.meta.url)
and path.dirname to compute __dirname instead of import.meta.dirname; update the
const __dirname declaration that currently references import.meta.dirname to
call fileURLToPath(import.meta.url) wrapped by path.dirname so it works on Node
versions older than 20.11.0.
---
Nitpick comments:
In `@test/Invoices.test.tsx`:
- Around line 11-15: The test mock for useQuery in test/Invoices.test.tsx is
missing fields the Invoices component reads (isFetching, refetch, isError);
update the vi.mock for '@tanstack/react-query' so the useQuery mock returns the
full contract used by components/app/invoices/Invoices.tsx — include isFetching
(boolean), isError (boolean), and refetch (vi.fn() or async noop) alongside
data/isLoading/error; keep sensible defaults (false/undefined) and use vi.fn()
for refetch to avoid undefined behavior in tests.
In `@vitest.setup.ts`:
- Line 6: The test env sets NEXT_PUBLIC_BACKEND to 'http://localhost:3000' which
doesn't include the app's API base path used in lib/requests.ts (the code that
appends '/api' to requests), causing path mismatches in tests; update the value
in vitest.setup.ts to include the same API base (for example
'http://localhost:3000/api') so tests use the same base path as the
request-building logic (referencing NEXT_PUBLIC_BACKEND and lib/requests.ts).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ec517208-117c-4d74-b28c-99f803eefb83
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (7)
package.jsonsonar-project.propertiestest/BusinessProducts.test.tsxtest/Invoices.test.tsxtest/Logs.test.tsxvitest.config.tsvitest.setup.ts
✅ Files skipped from review due to trivial changes (1)
- sonar-project.properties
| describe('Invoices Component', () => { | ||
| const mockDictionary = { | ||
| pages: { | ||
| invoices: { | ||
| title: 'Mes Factures', | ||
| description: 'Consultez et gérez vos factures', | ||
| totalInvoices: 'Total des factures', | ||
| totalPaid: 'Total payé', | ||
| totalPending: 'Total en attente', | ||
| invoiceList: 'Liste des factures', | ||
| refresh: 'Actualiser', | ||
| createBusinessButton: 'Créer une nouvelle entreprise', | ||
| payment: { | ||
| securePayment: 'Paiement sécurisé', | ||
| completeCardInfo: 'Complétez les informations de votre carte', | ||
| validation: { | ||
| nameRequired: 'Nom du titulaire de la carte requis', | ||
| numberInvalid: 'Numéro de carte invalide', | ||
| expiryInvalid: "Date d'expiration invalide", | ||
| cvcInvalid: 'CVC invalide', | ||
| countryRequired: 'Pays requis', | ||
| }, | ||
| countryGroups: { | ||
| northAfrica: 'Afrique du Nord', | ||
| }, | ||
| }, | ||
| stripeConnect: { | ||
| title: 'Stripe Connect', | ||
| description: 'Connectez votre compte Stripe', | ||
| }, | ||
| }, | ||
| }, | ||
| common: { | ||
| retry: 'Réessayer', | ||
| }, | ||
| } as unknown as Dictionary; | ||
|
|
||
| it('should render the title correctly', () => { | ||
| render(<Invoices dictionary={mockDictionary} lang="fr" />); | ||
| expect(screen.getByText('Mes Factures')).toBeDefined(); | ||
| }); | ||
|
|
||
| it('should render the refresh button', () => { | ||
| render(<Invoices dictionary={mockDictionary} lang="fr" />); | ||
| expect(screen.getByText('Actualiser')).toBeDefined(); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift
Add tests for the checkout-completion confirmation path changed in this PR.
Current cases validate static rendering only. The payment-critical behavior described in this PR (session/receipt persistence, confirmPayment call, invalidation, cleanup, success/error toasts) is not exercised.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/Invoices.test.tsx` around lines 26 - 72, Add tests exercising the
checkout-completion flow in Invoices: simulate the component behavior when a
checkout completion is detected (e.g., URL query params or props that trigger
the flow), mock the confirmPayment function to return success and failure cases,
mock/session storage helpers that persist session/receipt (e.g., persistSession
or persistReceipt) and ensure they are read then cleared, and mock the cache
invalidation function (e.g., invalidateQueries) and toast helpers (e.g.,
showToastSuccess/showToastError). For success: assert confirmPayment is called,
invalidateQueries is invoked, session/receipt persistence is removed, and
success toast was shown; for failure: assert confirmPayment was called, cleanup
still runs, and error toast was shown. Use the Invoices component render with
RTL, jest.fn() mocks for confirmPayment/persistence/invalidation/toasts, and
simulate the completion trigger (query param or prop) to validate both success
and error paths.
| it('should show no results message when filtering results in 0 items', () => { | ||
| // We can't easily test client-side useMemo filtering without actual data changes | ||
| // But we can verify the search input exists | ||
| render(<Logs dictionary={mockDictionary} lang="en" />); | ||
| expect(screen.getByPlaceholderText(/search actor email.../i)).toBeDefined(); | ||
| }); |
There was a problem hiding this comment.
Test intent and assertion are mismatched.
Line 159 claims no-results behavior, but the assertion only checks that the search input exists. Rename the test or assert the actual no-results message with an empty logs mock.
✏️ Minimal fix (rename to match behavior)
- it('should show no results message when filtering results in 0 items', () => {
+ it('should render the search input', () => {
// We can't easily test client-side useMemo filtering without actual data changes
// But we can verify the search input exists
render(<Logs dictionary={mockDictionary} lang="en" />);
expect(screen.getByPlaceholderText(/search actor email.../i)).toBeDefined();
});📝 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.
| it('should show no results message when filtering results in 0 items', () => { | |
| // We can't easily test client-side useMemo filtering without actual data changes | |
| // But we can verify the search input exists | |
| render(<Logs dictionary={mockDictionary} lang="en" />); | |
| expect(screen.getByPlaceholderText(/search actor email.../i)).toBeDefined(); | |
| }); | |
| it('should render the search input', () => { | |
| // We can't easily test client-side useMemo filtering without actual data changes | |
| // But we can verify the search input exists | |
| render(<Logs dictionary={mockDictionary} lang="en" />); | |
| expect(screen.getByPlaceholderText(/search actor email.../i)).toBeDefined(); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/Logs.test.tsx` around lines 159 - 164, The test title and assertion are
mismatched: update the spec for the Logs component so it either (A) is renamed
to reflect that it only verifies the search input (change the it() description)
or (B) actually asserts the "no results" behavior by rendering Logs with an
empty logs dataset (pass an empty logs prop or a mock with zero items) and then
asserting the no-results message is shown (use screen.getByText(...) or
getByRole to check the "no results" string from mockDictionary). Locate the test
containing render(<Logs dictionary={mockDictionary} lang="en" />) and
screen.getByPlaceholderText(...) and apply one of these two fixes.
There was a problem hiding this comment.
Actionable comments posted: 11
♻️ Duplicate comments (1)
vitest.config.ts (1)
5-5:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReplace
import.meta.dirnamewith a cross-version-safe dirname derivation.
Line 5may break on environments that don’t supportimport.meta.dirname. UsefileURLToPath(import.meta.url)+path.dirname(...)instead.🛠️ Proposed fix
import { defineConfig } from 'vitest/config'; import react from '@vitejs/plugin-react'; import path from 'node:path'; +import { fileURLToPath } from 'node:url'; -const __dirname = import.meta.dirname; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename);Run this read-only check to confirm the compatibility risk and current implementation:
#!/bin/bash set -euo pipefail echo "Engines declared in package.json:" jq -r '.engines // {}' package.json echo echo "Current dirname usage in vitest config:" rg -n --fixed-strings 'import.meta.dirname' vitest.config.ts echo echo "Cross-version-safe pattern presence:" rg -n 'fileURLToPath\(import\.meta\.url\)|path\.dirname\(' vitest.config.ts🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@vitest.config.ts` at line 5, Replace the unsafe use of import.meta.dirname when deriving __dirname: locate the declaration of the __dirname variable (currently set via import.meta.dirname) and change it to compute __dirname using fileURLToPath(import.meta.url) combined with path.dirname; ensure you import or reference fileURLToPath and path (from 'url' and 'path' respectively) as needed so __dirname is derived with path.dirname(fileURLToPath(import.meta.url)).
🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)
17-20: ⚡ Quick winPin Bun to an explicit version instead of
latestfor reproducible CI.Using
latestintroduces risk of unexpected breakages as new Bun releases roll out. Pin to a stable version (e.g.,1.3.13) to ensure consistent lint/test/build outcomes across CI runs.Also applies to: 37-40
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/ci.yml around lines 17 - 20, The CI uses the "Setup Bun" step with bun-version: latest which risks non-reproducible failures; update the GitHub Actions steps that use oven-sh/setup-bun@v1 (both occurrences of the "Setup Bun" step) to pin bun-version to a specific stable release (for example "1.3.13") instead of "latest" so builds/lints/tests are reproducible across CI runs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.dockerignore:
- Around line 1-11: The .dockerignore currently omits common build artifacts but
not environment files, which risks leaking secrets into Docker build context;
update the .dockerignore (the file named ".dockerignore" itself) to explicitly
ignore environment files by adding entries such as .env, *.env, .env.*,
.env.local, .env.production, .env.development, .env.test, and any
project-specific secret filenames so they are excluded from the build context
and image layers.
In `@app/api/metrics/route.ts`:
- Around line 7-25: Move the call to collectDefaultMetrics out of the GET
handler and into module initialization so it runs once per process (e.g., call
collectDefaultMetrics({ register }) at top-level when the module loads), remove
the try-catch around register.metrics() in the GET function, and have GET simply
await register.metrics() and return it with the appropriate headers; refer to
collectDefaultMetrics, register, and the exported GET function when making the
change.
In `@app/layout.tsx`:
- Around line 2-3: The current change mocks next/font by replacing imports for
Geist, Geist_Mono, and Noto_Sans_Arabic with literal class tokens, which
prevents CSS variables and fonts from loading; restore the proper font loader
usage by re-importing from next/font/google (or switch to next/font/local with
checked-in files if build-time network access is blocked) and use the actual
loader output (the objects returned by Geist, Geist_Mono, Noto_Sans_Arabic) for
the variable property and className wherever you set
variable="--font-geist-sans" or similar so the generated class names and CSS
variables are applied; update the places referenced in the diff (the import
lines and the variable/className usages around lines noted) to use the real font
objects.
In `@docker-compose-jenkins.yml`:
- Around line 5-12: The compose snippet exposes a host-compromise path by using
privileged: true, user: root and binding /var/run/docker.sock; remove
privileged: true and user: root entries and stop mounting the host Docker socket
directly (the privileged/user symbols and the volumes entry referencing
/var/run/docker.sock), and instead add a controlled Docker-in-Docker sidecar
(e.g., image docker:dind) or a docker socket proxy and configure the Jenkins
container to use DOCKER_HOST (tcp) to talk to that sidecar over the compose
network; ensure the sidecar is hardened (use TLS or an authenticated proxy) and
keep the jenkins_home volume mount but avoid granting host root or direct socket
access.
- Around line 13-14: The compose file currently hardcodes Windows developer
paths in the workspace mounts; replace those two host-specific bindings (the
lines mounting C:\Users\Asus\Desktop\accountia-web and accountia-api) with
parameterized values or named volumes so other hosts/agents can run the stack.
Update the volume entries to use environment variables like
${WORKSPACE_ACCOUNTIA_WEB} and ${WORKSPACE_ACCOUNTIA_API} (and add them to the
.env or CI agent env), or switch to named volumes such as
jenkins_workspace_accountia_web and jenkins_workspace_accountia_api and create
those volumes in the compose file; ensure any documentation or .env.example is
updated so agents know to set the paths.
In `@docker-compose-monitoring.yml`:
- Line 5: Replace the three image tags that use :latest (e.g., "image:
prom/prometheus:latest" and the Grafana and AlertManager lines) with explicit
versioned tags to ensure reproducible deployments, and remove the hardcoded
Grafana admin credential by wiring GF_SECURITY_ADMIN_PASSWORD to an environment
variable or secret (e.g., GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD})
instead of using "admin"; also add GF_USERS_ALLOW_SIGN_UP=false and require the
deployer to supply a strong 12+ character password via the
GRAFANA_ADMIN_PASSWORD secret/ENV rather than embedding it in the compose file.
In `@Dockerfile`:
- Around line 16-26: The final image currently runs as root; create and use a
non-root user in the runner stage by adding a user (e.g., "appuser" or "node"),
chown the application directory (WORKDIR /app) and any copied files to that user
after the COPY steps, and set USER to that user before EXPOSE/CMD so the
container no longer runs as root; update Dockerfile runner stage (WORKDIR, COPY
lines, EXPOSE, CMD) to include the user creation, chown, and USER instruction.
- Around line 19-23: The runtime image is missing env.js which next.config.ts
imports (causing module resolution errors when running next start); update the
Dockerfile runtime COPY stage to also COPY --from=builder /app/env.js ./ (i.e.,
include env.js alongside next.config.ts and package.json) so env.js is present
at runtime for next.config.ts to import.
In `@Jenkinsfile`:
- Around line 11-12: Replace hardcoded SOURCE_DIR and any other hardcoded
workspace references (e.g., the value assigned to SOURCE_DIR and similar uses
around lines referenced) with Jenkins' provided environment variable
${WORKSPACE}; update BUILD_DIR usage if it assumes a fixed source path by
deriving it from ${WORKSPACE} or using WORKSPACE for any workspace-relative
operations. Locate assignments to SOURCE_DIR and any occurrences of the
hardcoded path in the Jenkinsfile and substitute them to reference the WORKSPACE
variable so the pipeline works across multibranch and different agents.
- Line 39: Remove the "|| true" that is suppressing failures in the pipeline:
locate the shell invocations using the pattern "sh 'npm run lint:check || true'"
(and the other occurrence with "|| true") and change them to simply run the
command without "|| true" so the Jenkins step fails on lint/test errors; if you
need to capture output while still failing, run the command normally and rely on
Jenkins to report the non-zero exit code or explicitly check the exit status
after the command.
- Around line 53-62: After running the SonarQube scanner in the "SonarQube
Analysis" stage, add a blocking quality-gate check by invoking
waitForQualityGate() inside the withSonarQubeEnv context (or immediately after
the scanner run) so the pipeline fails when the SonarQube quality gate is not
met; update the stage that calls sh "${SCANNER_HOME}/bin/sonar-scanner" to call
waitForQualityGate() and handle the returned result (or throw an error) to
prevent later "Docker Build" / "Deploy" stages from running on failed quality
gates.
---
Duplicate comments:
In `@vitest.config.ts`:
- Line 5: Replace the unsafe use of import.meta.dirname when deriving __dirname:
locate the declaration of the __dirname variable (currently set via
import.meta.dirname) and change it to compute __dirname using
fileURLToPath(import.meta.url) combined with path.dirname; ensure you import or
reference fileURLToPath and path (from 'url' and 'path' respectively) as needed
so __dirname is derived with path.dirname(fileURLToPath(import.meta.url)).
---
Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 17-20: The CI uses the "Setup Bun" step with bun-version: latest
which risks non-reproducible failures; update the GitHub Actions steps that use
oven-sh/setup-bun@v1 (both occurrences of the "Setup Bun" step) to pin
bun-version to a specific stable release (for example "1.3.13") instead of
"latest" so builds/lints/tests are reproducible across CI runs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7e060139-a84f-4ef2-a6bf-937dd1f53ac8
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (17)
.dockerignore.github/workflows/ci.yml.gitignoreDockerfileJenkinsfileREADME.mdalert_rules.ymlapp/api/metrics/route.tsapp/layout.tsxdocker-compose-jenkins.ymldocker-compose-monitoring.ymleslint.config.mjspackage.jsonprettier.config.jsprometheus.ymlsonar-project.propertiesvitest.config.ts
✅ Files skipped from review due to trivial changes (4)
- .gitignore
- README.md
- eslint.config.mjs
- prettier.config.js
🚧 Files skipped from review as they are similar to previous changes (2)
- package.json
- sonar-project.properties
| node_modules | ||
| npm-debug.log | ||
| Dockerfile | ||
| .dockerignore | ||
| .git | ||
| .gitignore | ||
| .next | ||
| out | ||
| build | ||
| coverage | ||
| jenkins_home |
There was a problem hiding this comment.
Add environment file exclusions to prevent accidental secret inclusion
Because the Docker build copies the full context, missing .env ignores can leak secrets into image layers/build cache.
Suggested change
+.env
+.env.*
+!.env.example📝 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.
| node_modules | |
| npm-debug.log | |
| Dockerfile | |
| .dockerignore | |
| .git | |
| .gitignore | |
| .next | |
| out | |
| build | |
| coverage | |
| jenkins_home | |
| node_modules | |
| npm-debug.log | |
| Dockerfile | |
| .dockerignore | |
| .git | |
| .gitignore | |
| .next | |
| out | |
| build | |
| coverage | |
| jenkins_home | |
| .env | |
| .env.* | |
| !.env.example |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.dockerignore around lines 1 - 11, The .dockerignore currently omits common
build artifacts but not environment files, which risks leaking secrets into
Docker build context; update the .dockerignore (the file named ".dockerignore"
itself) to explicitly ignore environment files by adding entries such as .env,
*.env, .env.*, .env.local, .env.production, .env.development, .env.test, and any
project-specific secret filenames so they are excluded from the build context
and image layers.
| export async function GET() { | ||
| try { | ||
| // On lance la collecte si elle n'est pas déjà active | ||
| client.collectDefaultMetrics({ register }); | ||
|
|
||
| const metrics = await register.metrics(); | ||
|
|
||
| return new NextResponse(metrics, { | ||
| headers: { | ||
| 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8', | ||
| 'Cache-Control': 'no-store, no-cache, must-revalidate', | ||
| }, | ||
| }); | ||
| } catch { | ||
| // Si c'est déjà enregistré, on renvoie juste les métriques | ||
| const metrics = await register.metrics(); | ||
| return new NextResponse(metrics, { | ||
| headers: { 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8' }, | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For prom-client v15.x, is collectDefaultMetrics intended to be called once at startup (not per HTTP request), and what happens if called repeatedly on the same registry?
💡 Result:
For prom-client v15.x, collectDefaultMetrics is intended to be called once during process startup (not per HTTP request). Evidence: the prom-client docs state that “Default metrics are collected on scrape of metrics endpoint, not on an interval,” and show calling collectDefaultMetrics once (typically at app startup) rather than inside the request handler. [1][2] What happens if you call it repeatedly on the same registry? 1) It will re-register the same default metrics on the registry, which can cause errors/panics about duplicate metrics. Evidence: prom-client throws when a metric name is already registered (example error: “A metric with the name … has already been registered”), and a maintainer response explains that adding DefaultMetrics twice to the default Registry happens when collectDefaultMetrics is called from two places; the fix is to “only call collectDefaultMetrics once.” [3] 2) If you want to avoid the duplicate-registration behavior, use a separate Registry instance (or ensure collectDefaultMetrics is only invoked once per registry). Evidence: prom-client’s collectDefaultMetrics supports an explicit registry option, and docs describe registering default metrics to a custom registry to keep them separate from application metrics. [4][1] So: call collectDefaultMetrics once per process (once per registry). Calling it repeatedly for the same registry leads to duplicate metric registration attempts and will typically throw an error/panic for metric names already registered. [3]
Citations:
- 1: https://github.com/siimon/prom-client
- 2: https://github.com/siimon/prom-client?tab=readme-ov-file
- 3: Error: A metric with the name process_cpu_user_seconds_total has already been registered. prometheus/client_js#439
- 4: https://tessl.io/registry/tessl/npm-prom-client/15.1.0/files/docs/default-metrics.md
🏁 Script executed:
find . -name "route.ts" -path "*/api/metrics/*" | head -5Repository: mAmineChniti/accountia-web
Length of output: 97
🏁 Script executed:
cat app/api/metrics/route.ts 2>/dev/null || echo "File not found, searching..."
git ls-files | grep -E "metrics.*route\.ts"Repository: mAmineChniti/accountia-web
Length of output: 917
🏁 Script executed:
cat package.json | grep -A 2 -B 2 "prom-client"Repository: mAmineChniti/accountia-web
Length of output: 203
Initialize default metrics once at module load; don't call on every request.
collectDefaultMetrics is called on every GET request (line 10), but prom-client v15.1.3 requires it to be called once per process. Calling it repeatedly on the same registry throws a "metric already registered" error. The catch block (lines 20–25) silently swallows these errors, accidentally working around the issue instead of fixing it. This violates the API contract and masks real failures.
Move the collectDefaultMetrics call to module initialization and remove the try-catch error suppression:
Proposed fix
import { NextResponse } from 'next/server';
import * as client from 'prom-client';
// On utilise le registre par défaut de prom-client
const register = client.register;
+let defaultMetricsInitialized = false;
export async function GET() {
try {
- // On lance la collecte si elle n'est pas déjà active
- client.collectDefaultMetrics({ register });
+ if (!defaultMetricsInitialized) {
+ client.collectDefaultMetrics({ register });
+ defaultMetricsInitialized = true;
+ }
const metrics = await register.metrics();
return new NextResponse(metrics, {
headers: {
'Content-Type': 'text/plain; version=0.0.4; charset=utf-8',
'Cache-Control': 'no-store, no-cache, must-revalidate',
},
});
- } catch {
- // Si c'est déjà enregistré, on renvoie juste les métriques
- const metrics = await register.metrics();
- return new NextResponse(metrics, {
- headers: { 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8' },
- });
+ } catch {
+ return NextResponse.json(
+ { error: 'Unable to produce metrics' },
+ { status: 500 }
+ );
}
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/api/metrics/route.ts` around lines 7 - 25, Move the call to
collectDefaultMetrics out of the GET handler and into module initialization so
it runs once per process (e.g., call collectDefaultMetrics({ register }) at
top-level when the module loads), remove the try-catch around register.metrics()
in the GET function, and have GET simply await register.metrics() and return it
with the appropriate headers; refer to collectDefaultMetrics, register, and the
exported GET function when making the change.
| privileged: true | ||
| user: root | ||
| ports: | ||
| - '8080:8080' | ||
| - '50000:50000' | ||
| volumes: | ||
| - ./jenkins_home:/var/jenkins_home | ||
| - /var/run/docker.sock:/var/run/docker.sock |
There was a problem hiding this comment.
Avoid running Jenkins as privileged root with host Docker socket access
Line 5, Line 6, and Line 12 together create a host-compromise path (container escape equivalent privileges). This is a release blocker for CI hardening.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docker-compose-jenkins.yml` around lines 5 - 12, The compose snippet exposes
a host-compromise path by using privileged: true, user: root and binding
/var/run/docker.sock; remove privileged: true and user: root entries and stop
mounting the host Docker socket directly (the privileged/user symbols and the
volumes entry referencing /var/run/docker.sock), and instead add a controlled
Docker-in-Docker sidecar (e.g., image docker:dind) or a docker socket proxy and
configure the Jenkins container to use DOCKER_HOST (tcp) to talk to that sidecar
over the compose network; ensure the sidecar is hardened (use TLS or an
authenticated proxy) and keep the jenkins_home volume mount but avoid granting
host root or direct socket access.
| - C:\Users\Asus\Desktop\accountia-web:/var/jenkins_home/workspace/accountia-web | ||
| - C:\Users\Asus\Desktop\accountia-api:/var/jenkins_home/workspace/accountia-api |
There was a problem hiding this comment.
Replace machine-specific Windows mounts with parameterized paths
Line 13 and Line 14 hardcode one developer machine path, so this compose file will fail on other hosts/agents. Use environment variables (or named volumes) for workspace mapping.
Suggested change
- - C:\Users\Asus\Desktop\accountia-web:/var/jenkins_home/workspace/accountia-web
- - C:\Users\Asus\Desktop\accountia-api:/var/jenkins_home/workspace/accountia-api
+ - ${ACCOUNTIA_WEB_PATH}:/var/jenkins_home/workspace/accountia-web
+ - ${ACCOUNTIA_API_PATH}:/var/jenkins_home/workspace/accountia-api📝 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.
| - C:\Users\Asus\Desktop\accountia-web:/var/jenkins_home/workspace/accountia-web | |
| - C:\Users\Asus\Desktop\accountia-api:/var/jenkins_home/workspace/accountia-api | |
| - ${ACCOUNTIA_WEB_PATH}:/var/jenkins_home/workspace/accountia-web | |
| - ${ACCOUNTIA_API_PATH}:/var/jenkins_home/workspace/accountia-api |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docker-compose-jenkins.yml` around lines 13 - 14, The compose file currently
hardcodes Windows developer paths in the workspace mounts; replace those two
host-specific bindings (the lines mounting C:\Users\Asus\Desktop\accountia-web
and accountia-api) with parameterized values or named volumes so other
hosts/agents can run the stack. Update the volume entries to use environment
variables like ${WORKSPACE_ACCOUNTIA_WEB} and ${WORKSPACE_ACCOUNTIA_API} (and
add them to the .env or CI agent env), or switch to named volumes such as
jenkins_workspace_accountia_web and jenkins_workspace_accountia_api and create
those volumes in the compose file; ensure any documentation or .env.example is
updated so agents know to set the paths.
| FROM node:20-alpine AS runner | ||
| WORKDIR /app | ||
| ENV NODE_ENV=production | ||
| COPY --from=builder /app/next.config.ts ./ | ||
| COPY --from=builder /app/public ./public | ||
| COPY --from=builder /app/.next ./.next | ||
| COPY --from=builder /app/node_modules ./node_modules | ||
| COPY --from=builder /app/package.json ./package.json | ||
|
|
||
| EXPOSE 3000 | ||
| CMD ["npm", "start"] |
There was a problem hiding this comment.
Run the final container as a non-root user
The runner stage has no USER, so the app runs as root (also flagged by DS-0002). Please drop privileges in the final image.
Suggested change
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
@@
COPY --from=builder /app/package.json ./package.json
+RUN chown -R node:node /app
+USER node
EXPOSE 3000
CMD ["npm", "start"]📝 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.
| FROM node:20-alpine AS runner | |
| WORKDIR /app | |
| ENV NODE_ENV=production | |
| COPY --from=builder /app/next.config.ts ./ | |
| COPY --from=builder /app/public ./public | |
| COPY --from=builder /app/.next ./.next | |
| COPY --from=builder /app/node_modules ./node_modules | |
| COPY --from=builder /app/package.json ./package.json | |
| EXPOSE 3000 | |
| CMD ["npm", "start"] | |
| FROM node:20-alpine AS runner | |
| WORKDIR /app | |
| ENV NODE_ENV=production | |
| COPY --from=builder /app/next.config.ts ./ | |
| COPY --from=builder /app/public ./public | |
| COPY --from=builder /app/.next ./.next | |
| COPY --from=builder /app/node_modules ./node_modules | |
| COPY --from=builder /app/package.json ./package.json | |
| RUN chown -R node:node /app | |
| USER node | |
| EXPOSE 3000 | |
| CMD ["npm", "start"] |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Dockerfile` around lines 16 - 26, The final image currently runs as root;
create and use a non-root user in the runner stage by adding a user (e.g.,
"appuser" or "node"), chown the application directory (WORKDIR /app) and any
copied files to that user after the COPY steps, and set USER to that user before
EXPOSE/CMD so the container no longer runs as root; update Dockerfile runner
stage (WORKDIR, COPY lines, EXPOSE, CMD) to include the user creation, chown,
and USER instruction.
| COPY --from=builder /app/next.config.ts ./ | ||
| COPY --from=builder /app/public ./public | ||
| COPY --from=builder /app/.next ./.next | ||
| COPY --from=builder /app/node_modules ./node_modules | ||
| COPY --from=builder /app/package.json ./package.json |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify next.config.ts imports env.js and Dockerfile does/doesn't copy it.
rg -n "import './env.js'" next.config.ts
rg -n "COPY --from=builder /app/env.js" DockerfileRepository: mAmineChniti/accountia-web
Length of output: 91
Copy env.js into the runner image to avoid runtime config failure
Line 19 copies next.config.ts, which imports ./env.js on line 2; without copying env.js to the runtime stage, next start will fail with module resolution errors.
Suggested change
COPY --from=builder /app/next.config.ts ./
+COPY --from=builder /app/env.js ./
COPY --from=builder /app/public ./public📝 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.
| COPY --from=builder /app/next.config.ts ./ | |
| COPY --from=builder /app/public ./public | |
| COPY --from=builder /app/.next ./.next | |
| COPY --from=builder /app/node_modules ./node_modules | |
| COPY --from=builder /app/package.json ./package.json | |
| COPY --from=builder /app/next.config.ts ./ | |
| COPY --from=builder /app/env.js ./ | |
| COPY --from=builder /app/public ./public | |
| COPY --from=builder /app/.next ./.next | |
| COPY --from=builder /app/node_modules ./node_modules | |
| COPY --from=builder /app/package.json ./package.json |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Dockerfile` around lines 19 - 23, The runtime image is missing env.js which
next.config.ts imports (causing module resolution errors when running next
start); update the Dockerfile runtime COPY stage to also COPY --from=builder
/app/env.js ./ (i.e., include env.js alongside next.config.ts and package.json)
so env.js is present at runtime for next.config.ts to import.
| SOURCE_DIR = "/var/jenkins_home/workspace/accountia-web" | ||
| BUILD_DIR = "/tmp/accountia_build" |
There was a problem hiding this comment.
Use Jenkins-provided workspace instead of hardcoded source path
Line 11 hardcodes one workspace path, which breaks across multibranch/job naming and agent differences. Prefer ${WORKSPACE} directly.
Also applies to: 22-22, 76-76
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Jenkinsfile` around lines 11 - 12, Replace hardcoded SOURCE_DIR and any other
hardcoded workspace references (e.g., the value assigned to SOURCE_DIR and
similar uses around lines referenced) with Jenkins' provided environment
variable ${WORKSPACE}; update BUILD_DIR usage if it assumes a fixed source path
by deriving it from ${WORKSPACE} or using WORKSPACE for any workspace-relative
operations. Locate assignments to SOURCE_DIR and any occurrences of the
hardcoded path in the Jenkinsfile and substitute them to reference the WORKSPACE
variable so the pipeline works across multibranch and different agents.
| stage('SonarQube Analysis') { | ||
| steps { | ||
| dir("${BUILD_DIR}") { | ||
| echo 'Analyse de la qualité du code (SonarQube)...' | ||
| withSonarQubeEnv('SonarQube') { | ||
| sh "${SCANNER_HOME}/bin/sonar-scanner" | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
git ls-files | grep -i jenkinsfile | head -20Repository: mAmineChniti/accountia-web
Length of output: 82
🏁 Script executed:
cat -n JenkinsfileRepository: mAmineChniti/accountia-web
Length of output: 3771
Add a SonarQube quality-gate blocking step before Docker build/deploy
The SonarQube Analysis stage runs the scanner but does not enforce quality gate results. Add waitForQualityGate() after the SonarQube stage to prevent builds with quality gate failures from proceeding to Docker Build and Deploy stages.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Jenkinsfile` around lines 53 - 62, After running the SonarQube scanner in the
"SonarQube Analysis" stage, add a blocking quality-gate check by invoking
waitForQualityGate() inside the withSonarQubeEnv context (or immediately after
the scanner run) so the pipeline fails when the SonarQube quality gate is not
met; update the stage that calls sh "${SCANNER_HOME}/bin/sonar-scanner" to call
waitForQualityGate() and handle the returned result (or throw an error) to
prevent later "Docker Build" / "Deploy" stages from running on failed quality
gates.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@sonar-project.properties`:
- Line 13: Remove the hardcoded Sonar token from sonar.login in
sonar-project.properties and replace its usage with an environment-based
approach (e.g., read SONAR_TOKEN from CI/agent or pass -Dsonar.login at scan
time); revoke/rotate the exposed token immediately, remove the secret from the
repo (rewrite history or use git-secrets to purge), and update build/CI
configuration to inject SONAR_TOKEN securely so sonar.login is no longer stored
in source.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 67bc3916-2c1d-4f9b-9820-e0cc86a29a26
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (3)
package.jsonsonar-project.propertiestsconfig.sonar.json
✅ Files skipped from review due to trivial changes (1)
- tsconfig.sonar.json
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (3)
Jenkinsfile (3)
11-12:⚠️ Potential issue | 🟠 Major | ⚡ Quick winUse Jenkins workspace variables instead of hardcoded source paths.
Line 11 hardcodes a job-specific workspace path, which breaks across agents and multibranch job naming. Use
${WORKSPACE}(orpwd()) for workspace-relative operations.Suggested patch
- SOURCE_DIR = "/var/jenkins_home/workspace/accountia-web" - BUILD_DIR = "/tmp/accountia_build" + SOURCE_DIR = "${WORKSPACE}" + BUILD_DIR = "${WORKSPACE}/.jenkins-build-${BUILD_NUMBER}"Also applies to: 22-22, 82-82
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Jenkinsfile` around lines 11 - 12, The Jenkinsfile currently hardcodes SOURCE_DIR and BUILD_DIR (SOURCE_DIR = "/var/jenkins_home/workspace/accountia-web", BUILD_DIR = "/tmp/accountia_build"), which breaks on different agents and multibranch jobs; change SOURCE_DIR to use the Jenkins workspace variable (e.g., set SOURCE_DIR = "${WORKSPACE}" or use pwd() where SOURCE_DIR is referenced) and make BUILD_DIR workspace-relative (e.g., "${WORKSPACE}/tmp/accountia_build" or "${WORKSPACE}/build") so all workspace operations use Jenkins-provided paths; update every occurrence of SOURCE_DIR and BUILD_DIR in the Jenkinsfile (including other instances noted around lines 22 and 82) to reference these variables.
45-45:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDo not suppress lint/test failures in CI stages.
Line 45 and Line 54 use
|| true, so quality checks cannot fail the pipeline.Suggested patch
- sh 'npm run lint:check || true' + sh 'npm run lint:check' @@ - sh 'npm run test:cov || true' + sh 'npm run test:cov'Also applies to: 54-54
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Jenkinsfile` at line 45, The CI lint/test stages currently append "|| true" to the shell steps (e.g., the sh lines containing "npm run lint:check || true" and the similar command at the other occurrence), which masks failures; remove the "|| true" from those sh commands in the Jenkinsfile so that failed lint or test commands cause the pipeline to fail (ensure you update both occurrences).
59-68:⚠️ Potential issue | 🟠 Major | ⚡ Quick winBlock the pipeline on SonarQube quality gate before build/deploy.
Line 64 runs analysis, but the pipeline does not wait for gate status. Add a quality-gate wait to stop downstream Docker stages on failed quality.
Suggested patch
stage('SonarQube Analysis') { steps { dir("${BUILD_DIR}") { echo 'Analyse de la qualite du code (SonarQube)...' withSonarQubeEnv('SonarQube') { sh "${SCANNER_HOME}/bin/sonar-scanner" } } } } + stage('SonarQube Quality Gate') { + steps { + timeout(time: 10, unit: 'MINUTES') { + waitForQualityGate abortPipeline: true + } + } + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Jenkinsfile` around lines 59 - 68, Add a blocking quality-gate wait after the SonarQube analysis so the pipeline fails when the gate is not OK: inside the "SonarQube Analysis" stage after running withSonarQubeEnv and sh "${SCANNER_HOME}/bin/sonar-scanner", call waitForQualityGate() (optionally wrapped in a timeout) and throw an error / error out the build if the returned status is not "OK"; update the stage that currently uses withSonarQubeEnv and sh to include this check so downstream Docker/build/deploy stages are prevented when the quality gate fails.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Jenkinsfile`:
- Around line 63-64: Remove the hardcoded Sonar token from
sonar-project.properties (the sonar.login entry) and ensure the pipeline uses
Jenkins-managed credentials via withSonarQubeEnv('SonarQube') so the scanner run
(sh "${SCANNER_HOME}/bin/sonar-scanner") picks up the token from the
environment; update or remove any sonar.login lines in sonar-project.properties
and, if needed, set SONAR_TOKEN/sonar.login only via Jenkins credentials binding
or the SonarQube server configuration so no secret is stored in the repo.
- Around line 74-75: The pipeline currently tags and deploys the mutable
"latest" image which can cause wrong images to roll out; update the Docker
workflow so the deployment step uses the immutable tag built with
${BUILD_NUMBER} instead of ${DOCKER_IMAGE}:latest — i.e., ensure the build (sh
"docker build -t ${DOCKER_IMAGE}:${BUILD_NUMBER} .") and subsequent
tagging/deploy steps reference ${DOCKER_IMAGE}:${BUILD_NUMBER} (or remove the
automatic latest tag) so deployments always use the exact BUILD_NUMBER image.
---
Duplicate comments:
In `@Jenkinsfile`:
- Around line 11-12: The Jenkinsfile currently hardcodes SOURCE_DIR and
BUILD_DIR (SOURCE_DIR = "/var/jenkins_home/workspace/accountia-web", BUILD_DIR =
"/tmp/accountia_build"), which breaks on different agents and multibranch jobs;
change SOURCE_DIR to use the Jenkins workspace variable (e.g., set SOURCE_DIR =
"${WORKSPACE}" or use pwd() where SOURCE_DIR is referenced) and make BUILD_DIR
workspace-relative (e.g., "${WORKSPACE}/tmp/accountia_build" or
"${WORKSPACE}/build") so all workspace operations use Jenkins-provided paths;
update every occurrence of SOURCE_DIR and BUILD_DIR in the Jenkinsfile
(including other instances noted around lines 22 and 82) to reference these
variables.
- Line 45: The CI lint/test stages currently append "|| true" to the shell steps
(e.g., the sh lines containing "npm run lint:check || true" and the similar
command at the other occurrence), which masks failures; remove the "|| true"
from those sh commands in the Jenkinsfile so that failed lint or test commands
cause the pipeline to fail (ensure you update both occurrences).
- Around line 59-68: Add a blocking quality-gate wait after the SonarQube
analysis so the pipeline fails when the gate is not OK: inside the "SonarQube
Analysis" stage after running withSonarQubeEnv and sh
"${SCANNER_HOME}/bin/sonar-scanner", call waitForQualityGate() (optionally
wrapped in a timeout) and throw an error / error out the build if the returned
status is not "OK"; update the stage that currently uses withSonarQubeEnv and sh
to include this check so downstream Docker/build/deploy stages are prevented
when the quality gate fails.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 90d99f61-6085-43b8-9dc0-cd095400766f
📒 Files selected for processing (2)
Jenkinsfiletsconfig.sonar.json
✅ Files skipped from review due to trivial changes (1)
- tsconfig.sonar.json
| sh "docker build -t ${DOCKER_IMAGE}:${BUILD_NUMBER} ." | ||
| sh "docker tag ${DOCKER_IMAGE}:${BUILD_NUMBER} ${DOCKER_IMAGE}:latest" |
There was a problem hiding this comment.
Deploy the immutable build tag, not latest.
Line 87 deploys accountia-web-app:latest while build tags are created per ${BUILD_NUMBER}. Using latest can roll out the wrong image when builds overlap.
Suggested patch
- sh "docker run -d --name accountia-web-app -p 3001:3000 accountia-web-app:latest"
+ sh "docker run -d --name accountia-web-app -p 3001:3000 ${DOCKER_IMAGE}:${BUILD_NUMBER}"Also applies to: 87-87
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Jenkinsfile` around lines 74 - 75, The pipeline currently tags and deploys
the mutable "latest" image which can cause wrong images to roll out; update the
Docker workflow so the deployment step uses the immutable tag built with
${BUILD_NUMBER} instead of ${DOCKER_IMAGE}:latest — i.e., ensure the build (sh
"docker build -t ${DOCKER_IMAGE}:${BUILD_NUMBER} .") and subsequent
tagging/deploy steps reference ${DOCKER_IMAGE}:${BUILD_NUMBER} (or remove the
automatic latest tag) so deployments always use the exact BUILD_NUMBER image.
Summary by CodeRabbit
Bug Fixes
New Features
Tests
Chores