Skip to content

fix(ro): correct checksum alignment for 10-digit CUI numbers#145

Open
shayanzarei wants to merge 1 commit intokoblas:mainfrom
shayanzarei:fix/romanian-cui-padding
Open

fix(ro): correct checksum alignment for 10-digit CUI numbers#145
shayanzarei wants to merge 1 commit intokoblas:mainfrom
shayanzarei:fix/romanian-cui-padding

Conversation

@shayanzarei
Copy link

Summary
This MR fixes a logic error in the Romanian CUI (Codul Unic de Înregistrare) validator where 10-digit numbers were incorrectly aligned with the weighting key, leading to false positives (e.g., RO1234567890 was marked as valid).

Technical Breakdown
The Romanian CUI algorithm requires right-alignment against the testing key 753217532.

Previous Logic: Used value.padStart(9, '0'). For a 10-digit input, this did nothing, causing the splitAt function to provide a 9-digit "front" to a 9-weight array. This resulted in left-alignment instead of the required right-alignment.

New Logic: Uses value.padStart(10, '0') before splitting. This ensures the extracted front is always correctly positioned relative to the check digit, regardless of whether the input is 2 digits or 10 digits long.

Validation & Testing
Parity: This change aligns the JS implementation with the python-stdnum library and official Romanian tax logic.

Regression Tests: Added a specific test case for 1234567890 (should be invalid) and 1234567897 (should be valid).

All existing tests in test/ro/cui.spec.ts pass.

Fixes
Prevents false positives for maximum-length Romanian business identifiers.

Resolves validation discrepancies between Frontend (JS) and Backend (Python) environments.

@gemini-code-assist
Copy link

Summary of Changes

Hello @shayanzarei, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug in the Romanian CUI validation logic, specifically for longer identification numbers. By adjusting the padding mechanism, the system now correctly aligns CUI numbers for checksum calculation, eliminating false positives and ensuring accurate validation. This improvement enhances data integrity and consistency across different system components.

Highlights

  • Checksum Alignment Fix: Corrected a logic error in the Romanian CUI (Codul Unic de Înregistrare) validator that caused 10-digit numbers to be incorrectly aligned with the weighting key, leading to false positives.
  • Improved Validation Logic: The padStart function was updated from 9 to 10 digits, ensuring that the CUI number is always right-aligned against the testing key, regardless of its original length.
  • Enhanced Test Coverage: New test cases were added to specifically validate 8-digit CUI numbers, including both valid and invalid scenarios, to confirm the fix and prevent regressions.
  • Cross-Environment Consistency: This change aligns the JavaScript implementation with the python-stdnum library and official Romanian tax logic, resolving validation discrepancies between frontend and backend environments.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/ro/cui.spec.ts
    • Added a test case for an 8-digit valid CUI number to verify correct padding and checksum validation.
    • Included a test case for an 8-digit invalid CUI number to confirm proper error handling after padding.
  • src/ro/cui.ts
    • Modified the padStart method from 9 to 10 digits to ensure correct right-alignment of CUI numbers for checksum calculation.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@shayanzarei
Copy link
Author

shayanzarei commented Feb 25, 2026

Technical Summary: Validation Discrepancy (RO VAT)
The Situation
We discovered a "False Positive" bug in our Frontend (JS) validation that does not match our Backend (Python) validation.

Input: RO1234567890 (A 10-digit Romanian CUI)

Frontend (JS): Returns Valid ✅

Backend (Python): Returns Invalid Checksum ❌

The Core Problem: "The Padding Shift"
The Romanian CUI algorithm is based on a 9-digit weight key. For the math to work, the numbers must be right-aligned against that key.

The JS Logic Bug: The JS code was padding the number to 9 digits. When a user entered a 10-digit number, the padding did nothing. This caused the first 9 digits to "slide" into the wrong positions against the weights, accidentally resulting in a mathematical "pass" for invalid numbers.

The Python Logic: The Python library correctly aligns the weights regardless of length, identifying that the check digit (the last number) should be a 7, not a 0.

The Impact
User Friction: Users are told their VAT is "Good" by the UI, but then receive a "400 Bad Request" from the server upon submission. This creates a confusing "Feedback Loop."

Data Integrity: If the backend check were ever disabled or bypassed, our database would store mathematically impossible tax IDs, leading to issues with invoice generation for the Filtro-Cafe or Brunchbar branches.

The Solution (The Fix)
I have updated the Frontend logic to pad to 10 digits instead of 9. This forces the "Front" of the number to always be exactly 9 digits, ensuring the weights align perfectly with the check digit every time.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request correctly addresses a logic error in the Romanian CUI validator by ensuring numbers are padded to 10 digits before checksum calculation, guaranteeing a consistent 9-digit front for the weighted sum and implementing required right-alignment. However, a critical security vulnerability was identified: the underlying checksum validation logic is fundamentally broken. The current implementation incorrectly expects a check digit of '0' due to a mathematical error in the modulo operation (sum % 10 where sum is a multiple of 10), leading to a significant validation bypass for identifiers ending in '0' and a denial of service for most legitimate identifiers. This logic flaw must be remediated to ensure the validator functions as intended. Additionally, a minor suggestion is to improve a code comment for better long-term clarity.

// FIX: Pad to 10 total digits.
// This ensures that 'front' is always exactly 9 digits,
// perfectly matching the 9 weights provided.
const [front, check] = strings.splitAt(value.padStart(10, '0'), -1);

Choose a reason for hiding this comment

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

security-high high

The Romanian CUI validation logic is fundamentally flawed and remains broken despite the alignment fix. The checksum calculation on line 72 (sum % 10) always evaluates to 0 because sum is defined as 10 * weightedSum(...) on line 65.

This creates a significant security bypass where the validator incorrectly marks any CUI ending in '0' as valid (provided it meets length and digit requirements) and rejects almost all valid CUIs that do not end in '0'.

To correctly implement the Romanian CUI algorithm, the logic should be: (Sum * 10) % 11, and if the result is 10, the check digit is 0. This can be achieved by changing the logic to ((weightedSum(...) * 10) % 11) % 10.

Comment on lines +60 to +62
// FIX: Pad to 10 total digits.
// This ensures that 'front' is always exactly 9 digits,
// perfectly matching the 9 weights provided.

Choose a reason for hiding this comment

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

medium

While the comment is helpful, using prefixes like FIX: can be mistaken for temporary code markers (like TODO or FIXME) and may cause confusion for future maintainers. For long-term clarity, it's better to have a comment that explains the logic's purpose. I suggest rephrasing to focus on why the padding is necessary.

Suggested change
// FIX: Pad to 10 total digits.
// This ensures that 'front' is always exactly 9 digits,
// perfectly matching the 9 weights provided.
// Pad to 10 total digits to ensure the `front` part is always 9 digits.
// This correctly right-aligns numbers with fewer than 10 digits
// for the checksum calculation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant