Skip to content

Implement certificate metadata issuance system#4922

Open
anurag2787 wants to merge 18 commits into
OWASP:feature/contributor-recognition-programfrom
anurag2787:certificate-metadata
Open

Implement certificate metadata issuance system#4922
anurag2787 wants to merge 18 commits into
OWASP:feature/contributor-recognition-programfrom
anurag2787:certificate-metadata

Conversation

@anurag2787

@anurag2787 anurag2787 commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Proposed change

This PR adds the backend flow for issuing contributor certificates by creating and storing certificate metadata when a contributor reaches a recognition tier.

Resolves #4921

Checklist

  • Required: I followed the contributing workflow
  • Required: I verified that my code works as intended and resolves the issue as described
  • Required: I ran make check-test locally: all warnings addressed, tests passed
  • I used AI for code, documentation, tests, or communication related to this PR

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Introduces the OWASP Contributor Recognition Program (CRP) scoring and certificate infrastructure. Four CRP model db_table names are renamed to the owasp_crp_recognition_* namespace (with a migration). A new ContributionScoreCalculator computes scores from PR/issue counts, assigns tiers, and persists ContributionScore rows. A pluggable certificate provider/service layer issues Certificate records. A management command, Makefile target, and admin action expose bulk and per-user recalculation.

Changes

CRP Contribution Scoring & Certificate Issuance

Layer / File(s) Summary
StateReason enum and CRP model table renames
backend/apps/github/models/generic_issue_model.py, backend/apps/owasp/models/crp/certificate.py, backend/apps/owasp/models/crp/contribution_score.py, backend/apps/owasp/models/crp/leaderboard_snapshot.py, backend/apps/owasp/models/crp/scoring_weight.py, backend/apps/owasp/migrations/0074_alter_certificate_table_and_more.py, backend/apps/owasp/models/__init__.py
GenericIssueModel gains StateReason.COMPLETED; all four CRP models update db_table to owasp_crp_recognition_* names and switch enum imports to the CRP-local recognition_enums module; migration records the table renames.
Certificate provider abstraction and service
backend/apps/owasp/services/__init__.py, backend/apps/owasp/services/certificate_providers.py, backend/apps/owasp/services/certificate_service.py, backend/apps/owasp/exceptions.py
BaseCertificateProvider defines the issuance contract; LocalCertificateProvider writes Certificate ORM rows; CertificateProviderFactory resolves the provider from settings.CERTIFICATE_PROVIDER; CertificateService.issue_certificate adds idempotency check, provider resolution, and error-logged issuance; CertificateIssuanceError exception for provider/issuance failures.
ContributionScoreCalculator core logic
backend/apps/owasp/score_calculator.py
Loads active ScoringWeight records, counts merged/opened PRs and completed issues per user against OWASP-org repos, computes weighted totals, maps scores to tier thresholds, and bulk-upserts ContributionScore rows while issuing certificates. Includes both recalculate_all (batched, bulk-save) and recalculate_user (single user, update_or_create).
Admin action, management command, and Makefile target
backend/apps/owasp/admin/contribution_score.py, backend/apps/owasp/admin/certificate.py, backend/apps/owasp/admin/leaderboard_snapshot.py, backend/apps/owasp/admin/scoring_weight.py, backend/apps/owasp/management/commands/owasp_crp_recognition_recalculate_scores.py, backend/apps/owasp/Makefile, cspell/custom-dict.txt
ContributionScoreAdmin gains a recalculate action that calls recalculate_user per selected row and reports counts. A new management command calls recalculate_all with styled stdout output. A Makefile target wires the command. Admin imports for Certificate, LeaderboardSnapshot, and ScoringWeight are updated to CRP module paths.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Suggested reviewers

  • arkid15r
  • kasya
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: implementing a certificate metadata issuance system, which is the primary focus across multiple file changes.
Linked Issues check ✅ Passed The PR implements certificate metadata creation and storage system as required by issue #4921, including certificate provider abstraction, service layer, database models, admin integration, and score calculator.
Out of Scope Changes check ✅ Passed All changes are directly related to certificate metadata issuance and the Contributor Recognition Program infrastructure, including model reorganization, calculator implementation, and admin tooling.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description check ✅ Passed The pull request description clearly explains the proposed change and links to the relevant issue (#4921).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 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 `@backend/apps/owasp/admin/contribution_score.py`:
- Around line 56-61: The exception handling in the batch admin action for score
recalculation is too narrow. Change the except clause from catching only
ValueError and TypeError to catching the broader Exception class instead. This
allows the batch operation to continue processing remaining contributors even if
an individual score recalculation fails for any reason, rather than aborting the
entire action. The logging statement is already in place and will capture all
exceptions, so only the except clause needs to be modified.

In `@backend/apps/owasp/score_calculator.py`:
- Around line 89-99: The `calculate()` method is being called once per user in
`recalculate_all()`, causing three separate COUNT queries per user (from
`count_merged_pull_requests()`, `count_opened_pull_requests()`, and
`count_opened_issues()`). Refactor `recalculate_all()` to pre-aggregate counts
grouped by `author_id` in a single batch query instead of iterating through
users and calling `calculate()` individually. Build a dictionary of aggregated
counts keyed by author_id, then compute scores for all users from this
pre-aggregated data, eliminating the query amplification of 3 queries per user.

In `@backend/apps/owasp/services/certificate_providers.py`:
- Line 1: The services directory is missing an __init__.py file, which is
required to make it a proper Python package. Create a new __init__.py file in
the services directory with a simple docstring identifying it as the OWASP
services package to enable proper module imports from this directory.
- Line 11: The import of TierChoices at the top level should be moved into the
TYPE_CHECKING block since it is only used in type annotations (not at runtime).
Remove the import statement `from apps.owasp.models.crp.recognition_enums import
TierChoices` from the unconditional imports section and add it within the `if
TYPE_CHECKING:` block at the top of the file alongside other type-checking
imports. This avoids the runtime import overhead while keeping TierChoices
available for type annotations.
- Around line 69-73: The ValueError raised in the provider class lookup section
violates Ruff rules TRY003 and EM102 because the exception message uses an
f-string literal directly in the raise statement. Create a variable to hold the
error message first, then use that variable in the raise ValueError statement.
Specifically, assign the message containing the provider_type to a variable (for
example, msg or error_message) before the raise statement, then pass that
variable to ValueError instead of the inline f-string.

In `@backend/apps/owasp/services/certificate_service.py`:
- Line 1: The file has three Ruff linting blockers that must be fixed before
merge. First, create a missing `__init__.py` file in the
`backend/apps/owasp/services/` directory to resolve the INP001 implicit
namespace package error. Second, at the locations indicated (lines 9-9 and
44-45), fix the TC001 error by creating custom exception classes instead of
using generic exceptions, and fix the TRY401 error by ensuring proper exception
handling patterns (such as using `raise ... from e` syntax where appropriate).
Review the code at those line ranges and replace generic exception handling with
properly structured custom exceptions and correct error chaining.
- Around line 42-46: The issue_certificate method currently logs errors and
returns silently when certificate provider initialization or issuance fails,
preventing callers from knowing whether the operation succeeded. Modify the
method to expose failures to callers by changing its return type to bool (or
raising a domain exception). At the exception handling block where
CertificateProviderFactory.get_provider() fails (lines 42-46), return False
instead of silently returning. Apply the same fix at lines 54-61 where the
issuance failure is also caught and silently returned. This allows admin and
command flows to accurately track and report failed certificate issuance
attempts.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a9a876d0-c836-42d9-b903-25320d44546f

📥 Commits

Reviewing files that changed from the base of the PR and between 5bae1cc and 839d772.

📒 Files selected for processing (19)
  • backend/apps/github/models/generic_issue_model.py
  • backend/apps/owasp/Makefile
  • backend/apps/owasp/admin/certificate.py
  • backend/apps/owasp/admin/contribution_score.py
  • backend/apps/owasp/admin/leaderboard_snapshot.py
  • backend/apps/owasp/admin/scoring_weight.py
  • backend/apps/owasp/management/commands/owasp_crp_recognition_recalculate_scores.py
  • backend/apps/owasp/migrations/0074_alter_certificate_table_and_more.py
  • backend/apps/owasp/models/__init__.py
  • backend/apps/owasp/models/crp/__init__.py
  • backend/apps/owasp/models/crp/certificate.py
  • backend/apps/owasp/models/crp/contribution_score.py
  • backend/apps/owasp/models/crp/leaderboard_snapshot.py
  • backend/apps/owasp/models/crp/recognition_enums.py
  • backend/apps/owasp/models/crp/scoring_weight.py
  • backend/apps/owasp/score_calculator.py
  • backend/apps/owasp/services/certificate_providers.py
  • backend/apps/owasp/services/certificate_service.py
  • cspell/custom-dict.txt

Comment thread backend/apps/owasp/admin/contribution_score.py
Comment thread backend/apps/owasp/score_calculator.py Outdated
Comment thread backend/apps/owasp/services/certificate_providers.py
Comment thread backend/apps/owasp/services/certificate_providers.py Outdated
Comment thread backend/apps/owasp/services/certificate_providers.py Outdated
Comment thread backend/apps/owasp/services/certificate_service.py
Comment thread backend/apps/owasp/services/certificate_service.py Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

4 issues found and verified against the latest diff

Confidence score: 2/5

  • In backend/apps/owasp/score_calculator.py, the opened-issue scoring path filters to completed issues, so valid issue_opened contributions are dropped and contributors can be assigned the wrong score/tier; this is the highest user-impact risk in the PR — fix the filter logic and add a regression test for opened-but-not-completed issues before merging.
  • In backend/apps/owasp/services/certificate_service.py, certificate issuance is non-atomic, so concurrent requests for the same user+tier can race and try to create duplicate active certificates, causing non-deterministic outcomes and noisy failures — enforce atomicity (transaction/locking or uniqueness-safe upsert) before merge.
  • In backend/apps/owasp/admin/contribution_score.py, batch admin exception handling is too narrow, so one unexpected DB/service/runtime error can halt processing for the rest of the selected contributors — broaden error handling so failures are isolated per contributor and the batch can complete.
  • In backend/apps/owasp/score_calculator.py, recalculate_all has N+1 query behavior that will degrade noticeably as contributor counts grow, risking slow admin operations and timeouts at scale — switch to batched aggregation/annotation or prefetch-based counting as a follow-up before this grows further.

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread backend/apps/owasp/score_calculator.py
Comment thread backend/apps/owasp/services/certificate_service.py Outdated
Comment thread backend/apps/owasp/admin/contribution_score.py
Comment thread backend/apps/owasp/score_calculator.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/apps/owasp/services/certificate_providers.py (1)

44-48: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make provider writes idempotent at the DB write step.

LocalCertificateProvider.issue() performs a plain create(). Because CertificateService does a separate pre-check, concurrent issuers can still race and hit unique_active_cert_per_tier. Prefer get_or_create(...) (or handle IntegrityError as already-issued) to make issuance atomic/idempotent.

Suggested fix
+from django.db import IntegrityError
@@
     def issue(self, user: User, score: int, tier: TierChoices) -> None:
@@
-        Certificate.objects.create(
-            github_user=user,
-            score=score,
-            tier=tier,
-        )
+        try:
+            Certificate.objects.get_or_create(
+                github_user=user,
+                tier=tier,
+                is_revoked=False,
+                defaults={"score": score},
+            )
+        except IntegrityError:
+            # Concurrent issuer won the race; treat as already issued.
+            return
🤖 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 `@backend/apps/owasp/services/certificate_providers.py` around lines 44 - 48,
The `Certificate.objects.create()` call in the
`LocalCertificateProvider.issue()` method is not idempotent and can race when
multiple concurrent issuers pass the pre-check in `CertificateService`. Replace
the `create()` call with `get_or_create()` using the appropriate unique fields
(github_user and tier) to make the write atomic and idempotent, ensuring
concurrent calls safely handle the case where the certificate already exists
rather than raising an IntegrityError from the unique_active_cert_per_tier
constraint.
♻️ Duplicate comments (1)
backend/apps/owasp/services/certificate_service.py (1)

22-22: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Expose issuance failure to callers instead of logging-and-returning.

issue_certificate() currently swallows provider resolution and issuance failures. Downstream recalculation flows continue and can report success while certificate metadata is not persisted. Return a status (bool) or raise a domain exception so callers can track/report failures explicitly.

Suggested direction
-    def issue_certificate(cls, user: User, score: int, tier: TierChoices) -> None:
+    def issue_certificate(cls, user: User, score: int, tier: TierChoices) -> bool:
@@
         if has_active_cert:
-            return
+            return True
@@
         except ValueError:
             logger.exception("Failed to resolve certificate provider")
-            return
+            return False
@@
         try:
             provider.issue(user, score, tier)
         except Exception:
             logger.exception(
                 "Failed to issue %s certificate for user %s",
                 tier,
                 user.login,
             )
+            return False
+        return True

Then update callers in backend/apps/owasp/score_calculator.py to handle the returned status.

Also applies to: 41-45, 53-61

🤖 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 `@backend/apps/owasp/services/certificate_service.py` at line 22, The
issue_certificate() method in certificate_service.py currently suppresses
provider resolution and issuance failures by logging them and returning
silently, causing downstream flows to report success even though certificate
metadata was not persisted. Modify issue_certificate() to return a bool status
(True for success, False for failure) or raise a domain exception instead of
silently returning on errors. Update all failure points in the method (including
the provider resolution failure around line 41-45 and issuance failures around
line 53-61) to explicitly signal failure rather than logging-and-returning. Then
update all callers of issue_certificate() in
backend/apps/owasp/score_calculator.py to check the returned status or handle
the raised exception, so they can properly track and report certificate issuance
failures instead of proceeding as if the operation succeeded.
🤖 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.

Outside diff comments:
In `@backend/apps/owasp/services/certificate_providers.py`:
- Around line 44-48: The `Certificate.objects.create()` call in the
`LocalCertificateProvider.issue()` method is not idempotent and can race when
multiple concurrent issuers pass the pre-check in `CertificateService`. Replace
the `create()` call with `get_or_create()` using the appropriate unique fields
(github_user and tier) to make the write atomic and idempotent, ensuring
concurrent calls safely handle the case where the certificate already exists
rather than raising an IntegrityError from the unique_active_cert_per_tier
constraint.

---

Duplicate comments:
In `@backend/apps/owasp/services/certificate_service.py`:
- Line 22: The issue_certificate() method in certificate_service.py currently
suppresses provider resolution and issuance failures by logging them and
returning silently, causing downstream flows to report success even though
certificate metadata was not persisted. Modify issue_certificate() to return a
bool status (True for success, False for failure) or raise a domain exception
instead of silently returning on errors. Update all failure points in the method
(including the provider resolution failure around line 41-45 and issuance
failures around line 53-61) to explicitly signal failure rather than
logging-and-returning. Then update all callers of issue_certificate() in
backend/apps/owasp/score_calculator.py to check the returned status or handle
the raised exception, so they can properly track and report certificate issuance
failures instead of proceeding as if the operation succeeded.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1fb6b41b-3da5-4fc4-96a8-4e19a4068991

📥 Commits

Reviewing files that changed from the base of the PR and between 839d772 and 0359e86.

📒 Files selected for processing (3)
  • backend/apps/owasp/services/__init__.py
  • backend/apps/owasp/services/certificate_providers.py
  • backend/apps/owasp/services/certificate_service.py

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

0 issues found across 3 files (changes from recent commits).

Requires human review: Auto-approval blocked by 4 unresolved issues from previous reviews.

Re-trigger cubic

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/apps/owasp/score_calculator.py (1)

364-376: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Inconsistent certificate failure handling between single-user and bulk flows.

recalculate_all() (lines 309–319, 328–338) catches and logs certificate issuance failures but continues processing, treating certificate errors as non-critical. However, recalculate_user() at line 375 propagates CertificateIssuanceError to the caller, aborting the operation. This inconsistency means direct callers of recalculate_user() must handle certificate exceptions, while the method signature and docstring don't document this behavior. Align the two flows: either wrap line 375 in try/except (matching bulk behavior) or document the raised exception.

🛡️ Align error handling with bulk flow
         "tier": tier,
     },
 )

-        CertificateService.issue_certificate(user, total_score, tier)
+        try:
+            CertificateService.issue_certificate(user, total_score, tier)
+        except Exception:
+            logger.exception(
+                "Failed to issue certificate for user %s",
+                user.login,
+            )

 logger.info(
🤖 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 `@backend/apps/owasp/score_calculator.py` around lines 364 - 376, The
recalculate_user() method calls CertificateService.issue_certificate() without
exception handling, allowing CertificateIssuanceError to propagate to callers,
while recalculate_all() catches and logs certificate failures to continue
processing. Wrap the CertificateService.issue_certificate(user, total_score,
tier) call in a try/except block that catches CertificateIssuanceError, logs the
error (matching the approach used in recalculate_all()), and allows the method
to complete successfully, ensuring consistent non-critical error handling across
both flows.
🤖 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.

Outside diff comments:
In `@backend/apps/owasp/score_calculator.py`:
- Around line 364-376: The recalculate_user() method calls
CertificateService.issue_certificate() without exception handling, allowing
CertificateIssuanceError to propagate to callers, while recalculate_all()
catches and logs certificate failures to continue processing. Wrap the
CertificateService.issue_certificate(user, total_score, tier) call in a
try/except block that catches CertificateIssuanceError, logs the error (matching
the approach used in recalculate_all()), and allows the method to complete
successfully, ensuring consistent non-critical error handling across both flows.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: fd029e87-02cd-4787-be91-a73730e2c9ac

📥 Commits

Reviewing files that changed from the base of the PR and between 0359e86 and 362b013.

📒 Files selected for processing (4)
  • backend/apps/owasp/admin/contribution_score.py
  • backend/apps/owasp/exceptions.py
  • backend/apps/owasp/score_calculator.py
  • backend/apps/owasp/services/certificate_service.py

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 14, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/apps/owasp/score_calculator.py">

<violation number="1" location="backend/apps/owasp/score_calculator.py:315">
P2: Catching broad `Exception` and continuing hides certificate issuance failures from control flow. This can leave users without certificates while recalculation reports success.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread backend/apps/owasp/score_calculator.py Outdated
Comment thread backend/apps/owasp/score_calculator.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/apps/owasp/score_calculator.py (1)

35-45: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Honor ScoringWeight.daily_cap before persisting scores.

load_scoring_weights() discards daily_cap, and calculate_score() multiplies already-collapsed totals by the per-event score. Any configured cap is therefore ignored, so ContributionScore.value, tiers, and certificate issuance can all overshoot the scoring policy defined in backend/apps/owasp/models/crp/scoring_weight.py. This needs a per-day aggregation path (or the unsupported field removed) before release.

Also applies to: 69-75

🤖 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 `@backend/apps/owasp/score_calculator.py` around lines 35 - 45, The
load_scoring_weights() method currently returns only event_type and score while
discarding the daily_cap field from ScoringWeight, causing daily caps to be
ignored during score calculation. Update load_scoring_weights() to include the
daily_cap value in the returned dictionary, then modify the calculate_score()
method (which uses these weights around lines 69-75) to implement per-day
aggregation that respects the daily_cap constraint, ensuring
ContributionScore.value never exceeds the configured daily caps for each event
type.
🤖 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 `@backend/apps/owasp/score_calculator.py`:
- Around line 94-99: The bucket key is labeled "issue_opened" but the underlying
query logic filters for state_reason=COMPLETED and applies the date window to
created_at, creating a mismatch between the key name and what actually gets
scored. Additionally, this causes the date window to miss issues completed
within the window if they were opened earlier. You need to choose one consistent
contract—either track opened issues using created_at, or track completed issues
using the appropriate completion date field—and then make the bucket key name,
the state_reason predicate (or equivalent completion filter), and the date field
all align with that choice. Ensure this consistency is applied across all
affected locations where this metric is defined and scored.

---

Outside diff comments:
In `@backend/apps/owasp/score_calculator.py`:
- Around line 35-45: The load_scoring_weights() method currently returns only
event_type and score while discarding the daily_cap field from ScoringWeight,
causing daily caps to be ignored during score calculation. Update
load_scoring_weights() to include the daily_cap value in the returned
dictionary, then modify the calculate_score() method (which uses these weights
around lines 69-75) to implement per-day aggregation that respects the daily_cap
constraint, ensuring ContributionScore.value never exceeds the configured daily
caps for each event type.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 19d5bc96-19ad-4df2-bce2-388efc2e0339

📥 Commits

Reviewing files that changed from the base of the PR and between 362b013 and d651eed.

📒 Files selected for processing (1)
  • backend/apps/owasp/score_calculator.py

Comment thread backend/apps/owasp/score_calculator.py
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 14, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread backend/apps/owasp/score_calculator.py Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 14, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread backend/apps/owasp/score_calculator.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
backend/apps/owasp/score_calculator.py (1)

304-321: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Keep score updates and certificate issuance in the same failure unit.

BulkSaveModel.bulk_save(...) commits the new ContributionScore rows before CertificateService.issue_certificate(...) runs. The new catch-and-continue block then records the provider error and moves on, so a provider outage leaves users with upgraded tiers but no matching Certificate metadata until someone manually reruns the job. That breaks the persistence contract this CRP flow is introducing.

Based on backend/apps/owasp/services/certificate_service.py:21-68, the transaction boundary only covers the certificate write, not the preceding score save.

Also applies to: 324-341

🤖 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 `@backend/apps/owasp/score_calculator.py` around lines 304 - 321, The
BulkSaveModel.bulk_save() call for ContributionScore is executed before
attempting to issue certificates, which means if certificate issuance fails, the
score updates have already been persisted, breaking the consistency contract.
Move the BulkSaveModel.bulk_save(ContributionScore, ...) call to execute only
after the certificate issuance loop completes successfully (after the for loop
over pending_certificates), so that score updates and certificate issuance
remain in the same transactional failure unit. This same change is needed at the
second occurrence of this pattern mentioned in lines 324-341.
backend/apps/owasp/management/commands/owasp_crp_recognition_recalculate_scores.py (1)

20-39: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Only print the green success banner on the success path.

When failed_count > 0, this command still emits a styled SUCCESS message and then exits with CommandError. That makes failure runs look healthy in CI and operator logs at a glance.

Suggested change
-        self.stdout.write(
-            self.style.SUCCESS(
-                f"Score recalculation complete:\n"
-                f"  - Total users: {result['total']}\n"
-                f"  - Created: {result['created']}\n"
-                f"  - Updated: {result['updated']}\n"
-                f"  - Failed: {result['failed_count']}"
-            )
-        )
-
         failed_count = result.get("failed_count", 0)
         if failed_count > 0:
             failures = result.get("failures", [])
             failed_users = [username for username, _ in failures]
             failed_str = ", ".join(failed_users)
             self.stdout.write(
                 self.style.WARNING(f"Failed to issue certificates for: {failed_str}")
             )
             error_msg = f"Failed to issue certificates for {failed_count} user(s)"
             raise CommandError(error_msg)
+
+        self.stdout.write(
+            self.style.SUCCESS(
+                f"Score recalculation complete:\n"
+                f"  - Total users: {result['total']}\n"
+                f"  - Created: {result['created']}\n"
+                f"  - Updated: {result['updated']}\n"
+                f"  - Failed: {result['failed_count']}"
+            )
+        )
🤖 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
`@backend/apps/owasp/management/commands/owasp_crp_recognition_recalculate_scores.py`
around lines 20 - 39, The success message is printed unconditionally even when
the command fails (when failed_count > 0), making failures appear successful in
logs. Move the self.stdout.write call with self.style.SUCCESS containing the
score recalculation summary into a conditional block that only executes when
failed_count equals 0. Keep the failure handling path (the check for
failed_count > 0, the WARNING message, and the CommandError) separate and only
execute that path when there are actual failures.
🤖 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.

Outside diff comments:
In
`@backend/apps/owasp/management/commands/owasp_crp_recognition_recalculate_scores.py`:
- Around line 20-39: The success message is printed unconditionally even when
the command fails (when failed_count > 0), making failures appear successful in
logs. Move the self.stdout.write call with self.style.SUCCESS containing the
score recalculation summary into a conditional block that only executes when
failed_count equals 0. Keep the failure handling path (the check for
failed_count > 0, the WARNING message, and the CommandError) separate and only
execute that path when there are actual failures.

In `@backend/apps/owasp/score_calculator.py`:
- Around line 304-321: The BulkSaveModel.bulk_save() call for ContributionScore
is executed before attempting to issue certificates, which means if certificate
issuance fails, the score updates have already been persisted, breaking the
consistency contract. Move the BulkSaveModel.bulk_save(ContributionScore, ...)
call to execute only after the certificate issuance loop completes successfully
(after the for loop over pending_certificates), so that score updates and
certificate issuance remain in the same transactional failure unit. This same
change is needed at the second occurrence of this pattern mentioned in lines
324-341.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 49b7efbb-2956-40d4-91be-229009ba6778

📥 Commits

Reviewing files that changed from the base of the PR and between d651eed and 2839c93.

📒 Files selected for processing (2)
  • backend/apps/owasp/management/commands/owasp_crp_recognition_recalculate_scores.py
  • backend/apps/owasp/score_calculator.py

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 14, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

0 issues found across 3 files (changes from recent commits).

Requires human review: Auto-approval blocked by 1 unresolved issue from previous reviews.

Re-trigger cubic

@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 34.74178% with 139 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.95%. Comparing base (9efca86) to head (31e69d7).
⚠️ Report is 2 commits behind head on feature/contributor-recognition-program.

Files with missing lines Patch % Lines
backend/apps/owasp/score_calculator.py 22.60% 89 Missing ⚠️
...mmands/owasp_crp_recognition_recalculate_scores.py 0.00% 17 Missing ⚠️
backend/apps/owasp/services/certificate_service.py 46.42% 15 Missing ⚠️
backend/apps/owasp/admin/contribution_score.py 38.88% 11 Missing ⚠️
...ckend/apps/owasp/services/certificate_providers.py 66.66% 7 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@                             Coverage Diff                             @@
##           feature/contributor-recognition-program    #4922      +/-   ##
===========================================================================
- Coverage                                    98.74%   97.95%   -0.79%     
===========================================================================
  Files                                          547      551       +4     
  Lines                                        17185    17386     +201     
  Branches                                      2417     2434      +17     
===========================================================================
+ Hits                                         16969    17031      +62     
- Misses                                         127      266     +139     
  Partials                                        89       89              
Flag Coverage Δ
backend 98.35% <34.74%> (-1.07%) ⬇️
frontend 96.80% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
backend/apps/github/models/generic_issue_model.py 100.00% <100.00%> (ø)
backend/apps/owasp/admin/certificate.py 100.00% <100.00%> (ø)
backend/apps/owasp/admin/leaderboard_snapshot.py 100.00% <100.00%> (ø)
backend/apps/owasp/admin/scoring_weight.py 100.00% <100.00%> (ø)
backend/apps/owasp/exceptions.py 100.00% <100.00%> (ø)
backend/apps/owasp/models/crp/certificate.py 90.90% <100.00%> (ø)
...ackend/apps/owasp/models/crp/contribution_score.py 93.33% <100.00%> (ø)
...kend/apps/owasp/models/crp/leaderboard_snapshot.py 96.00% <100.00%> (ø)
backend/apps/owasp/models/crp/recognition_enums.py 100.00% <ø> (ø)
backend/apps/owasp/models/crp/scoring_weight.py 93.33% <100.00%> (ø)
... and 5 more

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 15609d9...31e69d7. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@arkid15r arkid15r left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please resolve conflicts

cubic-dev-ai[bot]
cubic-dev-ai Bot previously approved these changes Jun 19, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

0 issues found across 3 files (changes from recent commits).

Re-trigger cubic

@anurag2787

Copy link
Copy Markdown
Collaborator Author

Hi @arkid15r, the pr is ready for review. the current ci/cd failure seems unrelated to my changes Thanks!

@anurag2787 anurag2787 requested a review from arkid15r June 19, 2026 12:09
)
)

failed_count = result.get("failed_count", 0)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Consider walrus operator and more pythonic way to check if it's truthy (just if failed_count).

ValueError: If the configured provider is unknown.

"""
provider_type = getattr(settings, "CERTIFICATE_PROVIDER", "local")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's make settings.CERTIFICATE_PROVIDER usable here (w/o getattr)

Comment on lines +39 to +46
has_active_cert = Certificate.objects.filter(
github_user=user,
tier=tier,
is_revoked=False,
).exists()

if has_active_cert:
return

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Use := to combine those 2.

"""Abstract base class for certificate providers."""

@abstractmethod
def issue(self, user: User, score: int, tier: TierChoices) -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This name is somewhat confusing, could you use something like issue_certificate ?

Thanks

)
try:
provider.issue(user, score, tier)
except Exception as e:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you narrow down the exception types here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I had narrowed it to IntegrityError based on the current implementation but keeping it broad here seems fine since the service layer is responsible for wrapping provider side failures cubic dev AI also pointed out the same regarding preserving the service error boundary #4922 (comment)

Comment thread backend/apps/owasp/score_calculator.py Outdated
pending_score.value,
TierChoices(pending_score.tier),
)
except Exception as e:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It's not encouraged to have that wide exceptions everywhere -- not a good practice.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Sorry for this i will take care from next time

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 5 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread backend/apps/owasp/services/certificate_service.py Outdated
Comment thread backend/apps/owasp/score_calculator.py
@sonarqubecloud

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

0 issues found across 2 files (changes from recent commits).

Re-trigger cubic

@anurag2787 anurag2787 requested a review from arkid15r June 26, 2026 07:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants