Skip to content

Implement GraphQL Queries for Candidate Claim Data - #4832

Merged
arkid15r merged 8 commits into
OWASP:feature/bod-candidate-transparencyfrom
rudransh-shrivastava:feature/bod-claim-queries
Jun 12, 2026
Merged

arkid15r merged 8 commits into
OWASP:feature/bod-candidate-transparencyfrom
rudransh-shrivastava:feature/bod-claim-queries

Conversation

@rudransh-shrivastava

Copy link
Copy Markdown
Collaborator

Proposed change

Resolves #4791

Add GraphQL queries for candidate claim data.

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

Adds Strawberry-Django relay nodes and GraphQL query resolvers for BoardCandidateClaim and BoardCandidateClaimEvidence, enforces owner vs. public access, adds an order field with bulk-save support and migration, and includes unit tests for resolvers and model behavior.

Changes

GraphQL Queries and Access Control for Candidate Claims

Layer / File(s) Summary
GraphQL Node Types
backend/apps/owasp/api/internal/nodes/board_candidate_claim.py, backend/apps/owasp/api/internal/nodes/board_candidate_claim_evidence.py, backend/tests/unit/apps/owasp/api/internal/nodes/*
BoardCandidateClaimNode and BoardCandidateClaimEvidenceNode relay types expose selected model fields to GraphQL, add created_at/updated_at resolvers and a conditional file_url resolver; node schema and resolver tests added.
Model Order Field and Persistence
backend/apps/owasp/models/board_candidate_claim.py, backend/apps/owasp/migrations/0074_boardcandidateclaim_order.py, backend/tests/unit/apps/owasp/models/board_candidate_claim_test.py
Add order: PositiveSmallIntegerField with default 0; save() sets order for new claims by incrementing max per candidate+board; integrate BulkSaveModel and add bulk_save() delegating to it; migration and tests validate behavior.
Query Resolvers & Schema Wiring
backend/apps/owasp/api/internal/queries/board_candidate_claim.py, backend/apps/owasp/api/internal/queries/board_candidate_claim_evidence.py, backend/apps/owasp/api/internal/queries/__init__.py, backend/tests/unit/apps/owasp/api/internal/queries/*
board_candidate_claims filters by candidate login and board year, orders results, and restricts non-owner/anonymous requests to Status.APPROVED. board_candidate_claim_evidences resolves by GlobalID, returns [] for invalid/missing claims, enforces owner vs. approved-only non-owner access, and returns evidences with is_removed=False; query mixins are registered in OwaspQuery. Tests cover all branches.
BoardOfDirectors Candidate Lookup
backend/apps/owasp/models/board_of_directors.py, backend/tests/unit/apps/owasp/models/board_of_directors_test.py
Add BoardOfDirectors.get_candidate(login) returning the first matching candidate by member__login, with tests for method existence and both return branches.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • OWASP/Nest#4743: The main PR extends the same candidate-claim domain introduced in the retrieved PR by adding GraphQL nodes/queries and updating the BoardCandidateClaim model (e.g., new order field/bulk_save) that depend on the BoardCandidateClaim/BoardCandidateClaimEvidence models created in PR #4743.
  • OWASP/Nest#2045: The main PR adds new Strawberry relay Node types that participate in the same Relay id/_id behavior targeted by this retrieved PR.
  • OWASP/Nest#2451: Related changes to BoardOfDirectors candidate/member helper APIs that interact with the new get_candidate usage.

Suggested reviewers

  • kasya
  • RAJANAGORI
  • emaybu
  • arkid15r
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements GraphQL queries for candidate claims (#4791) but does not include mutations as required; only read-only queries are provided. Implement GraphQL mutations for submitting/creating candidate claims and evidence to fully address issue #4791 requirements.
Docstring Coverage ⚠️ Warning Docstring coverage is 58.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately describes the main change: implementing GraphQL queries for candidate claim data, which aligns with the primary objective in the changeset.
Description check ✅ Passed Description references issue #4791 and explains the purpose of adding GraphQL queries for candidate claim data, which directly relates to the changeset modifications.
Out of Scope Changes check ✅ Passed Changes include query implementations, node definitions, models, and migrations all aligned with adding GraphQL query support for candidate claims; model enhancements (order field, bulk_save) are justified by query requirements.

✏️ 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 and usage tips.

@codecov

codecov Bot commented Jun 4, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.78082% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.85%. Comparing base (89b5a12) to head (dddcf42).

Files with missing lines Patch % Lines
.../owasp/api/internal/nodes/board_candidate_claim.py 83.33% 2 Missing ⚠️
...i/internal/nodes/board_candidate_claim_evidence.py 88.23% 2 Missing ⚠️
...internal/queries/board_candidate_claim_evidence.py 89.47% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@                          Coverage Diff                           @@
##           feature/bod-candidate-transparency    #4832      +/-   ##
======================================================================
- Coverage                               98.88%   98.85%   -0.04%     
======================================================================
  Files                                     542      546       +4     
  Lines                                   17253    17324      +71     
  Branches                                 2469     2474       +5     
======================================================================
+ Hits                                    17061    17126      +65     
- Misses                                    103      109       +6     
  Partials                                   89       89              
Flag Coverage Δ
backend 99.43% <91.78%> (-0.05%) ⬇️
frontend 97.26% <ø> (ø)

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

Files with missing lines Coverage Δ
...wasp/api/internal/queries/board_candidate_claim.py 100.00% <100.00%> (ø)
backend/apps/owasp/models/board_candidate_claim.py 100.00% <100.00%> (ø)
backend/apps/owasp/models/board_of_directors.py 100.00% <100.00%> (ø)
.../owasp/api/internal/nodes/board_candidate_claim.py 83.33% <83.33%> (ø)
...i/internal/nodes/board_candidate_claim_evidence.py 88.23% <88.23%> (ø)
...internal/queries/board_candidate_claim_evidence.py 89.47% <89.47%> (ø)

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 89b5a12...dddcf42. 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.

@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: 3

Caution

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

⚠️ Outside diff range comments (2)
backend/tests/unit/apps/owasp/models/board_candidate_claim_test.py (1)

376-393: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add a regression test for board attachment after initial draft creation.

Current coverage only validates create-time assignment with board_id already present. Please add a case where an existing draft with order=0 transitions from board_id=None to a concrete board and verify order is assigned. This protects the real workflow path and prevents regression.

🤖 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/tests/unit/apps/owasp/models/board_candidate_claim_test.py` around
lines 376 - 393, Add a regression unit test that covers the transition of an
existing draft BoardCandidateClaim from board_id=None to a real board so order
is assigned on update; create a BoardCandidateClaim instance with
status=BoardCandidateClaim.Status.DRAFT, candidate_id set, board_id=None and
order=0 (simulate existing DB object with pk set), patch
BoardCandidateClaim.objects.filter().aggregate() to return {"max_order": N} like
in the existing test, then set claim.board_id to a concrete value, call
claim.save(), and assert claim.order == N+1; reference the test function pattern
in board_candidate_claim_test.py and the BoardCandidateClaim.save behavior to
ensure you replicate the mocks for TimestampedModel.save and full_clean used in
the other test.
backend/apps/owasp/models/board_candidate_claim.py (1)

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

max(order)+1 is race-prone without DB uniqueness protection.

Concurrent inserts for the same (candidate_id, board_id) can compute the same max and persist duplicate order values. This should be guarded by a database-level unique constraint and atomic assignment/retry strategy.

Suggested direction
 class Meta:
     db_table = "owasp_board_candidate_claim"
     indexes = [
         models.Index(fields=["candidate", "status"], name="owasp_claim_candidate_status"),
         models.Index(fields=["board", "status"], name="owasp_claim_board_status"),
     ]
+    constraints = [
+        models.UniqueConstraint(
+            fields=["candidate", "board", "order"],
+            name="owasp_claim_candidate_board_order_uniq",
+        )
+    ]

And compute order inside an atomic block with retry on IntegrityError.

Also applies to: 125-135

🤖 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/models/board_candidate_claim.py` around lines 20 - 23, Add
a DB-level uniqueness constraint for the per-(candidate,board) ordering and make
the order assignment atomic with retry: update the model (BoardCandidateClaim)
indexes block to include a UniqueConstraint on ["candidate","board","order"] (in
addition to the existing Indexes) and change the claim-creation logic (the
function that currently computes max(order)+1 around lines ~125-135) to compute
order inside a transaction/locking block (e.g., select_for_update or an atomic
transaction) and retry on IntegrityError so concurrent inserts cannot produce
duplicate order values.
🤖 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/api/internal/queries/board_candidate_claim_evidence.py`:
- Line 38: The current is_self computation uses claim.candidate.member.login
directly which can raise AttributeError when claim.candidate or
claim.candidate.member is None; change the guard so you first verify
claim.candidate and claim.candidate.member exist (and member.login is present)
before comparing to str(user). In other words, update the is_self logic to
short-circuit to False when claim.candidate or claim.candidate.member is null
(use a safe existence check or getattr) and only perform the str(user) ==
claim.candidate.member.login comparison when the member/login is available.

In `@backend/apps/owasp/migrations/0074_boardcandidateclaim_order.py`:
- Around line 12-20: Add a migrations.RunPython backfill that assigns
deterministic sequential order values per (candidate_id, board_id) partition
before relying on the new BoardCandidateClaim.order semantics: implement a
forwards function (e.g., backfill_boardcandidateclaim_order) that queries
BoardCandidateClaim via the migration ORM, groups rows by candidate_id and
board_id, sorts each group by a stable key (created_at or id) and assigns
incremental PositiveSmallInteger values starting at 0 (use bulk_update or raw
SQL for efficiency), and include a simple reverse function (no-op or reset to 0)
for migrations.RunPython; register this RunPython in the migration alongside the
AddField so existing rows receive stable ordering before you add any uniqueness
constraint.

In `@backend/apps/owasp/models/board_candidate_claim.py`:
- Around line 125-135: The current logic in BoardCandidateClaim only sets
self.order when not self.pk, so if a draft was created with board_id=None later
setting board_id leaves order at 0; update the save() (or pre-save) logic in
BoardCandidateClaim to assign order whenever board_id and candidate_id are
present and either the instance is new (self.pk is None) or the board_id has
changed on an existing record (compare self.board_id to the value loaded from DB
for this pk). Keep the same aggregation using
BoardCandidateClaim.objects.filter(...).aggregate(max_order=models.Max("order"))
to compute (max_order or 0) + 1 and set self.order before saving. Ensure you
reference self.candidate_id and self.board_id for the lookup and only run when
those are truthy.

---

Outside diff comments:
In `@backend/apps/owasp/models/board_candidate_claim.py`:
- Around line 20-23: Add a DB-level uniqueness constraint for the
per-(candidate,board) ordering and make the order assignment atomic with retry:
update the model (BoardCandidateClaim) indexes block to include a
UniqueConstraint on ["candidate","board","order"] (in addition to the existing
Indexes) and change the claim-creation logic (the function that currently
computes max(order)+1 around lines ~125-135) to compute order inside a
transaction/locking block (e.g., select_for_update or an atomic transaction) and
retry on IntegrityError so concurrent inserts cannot produce duplicate order
values.

In `@backend/tests/unit/apps/owasp/models/board_candidate_claim_test.py`:
- Around line 376-393: Add a regression unit test that covers the transition of
an existing draft BoardCandidateClaim from board_id=None to a real board so
order is assigned on update; create a BoardCandidateClaim instance with
status=BoardCandidateClaim.Status.DRAFT, candidate_id set, board_id=None and
order=0 (simulate existing DB object with pk set), patch
BoardCandidateClaim.objects.filter().aggregate() to return {"max_order": N} like
in the existing test, then set claim.board_id to a concrete value, call
claim.save(), and assert claim.order == N+1; reference the test function pattern
in board_candidate_claim_test.py and the BoardCandidateClaim.save behavior to
ensure you replicate the mocks for TimestampedModel.save and full_clean used in
the other test.
🪄 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: 1a449aae-c7c2-41a0-a044-2abce040c581

📥 Commits

Reviewing files that changed from the base of the PR and between 89b5a12 and 740baea.

📒 Files selected for processing (11)
  • backend/apps/owasp/api/internal/nodes/board_candidate_claim.py
  • backend/apps/owasp/api/internal/nodes/board_candidate_claim_evidence.py
  • backend/apps/owasp/api/internal/queries/__init__.py
  • backend/apps/owasp/api/internal/queries/board_candidate_claim.py
  • backend/apps/owasp/api/internal/queries/board_candidate_claim_evidence.py
  • backend/apps/owasp/migrations/0074_boardcandidateclaim_order.py
  • backend/apps/owasp/models/board_candidate_claim.py
  • backend/apps/owasp/models/board_of_directors.py
  • backend/tests/unit/apps/owasp/api/internal/queries/board_candidate_claim_evidence_test.py
  • backend/tests/unit/apps/owasp/api/internal/queries/board_candidate_claim_test.py
  • backend/tests/unit/apps/owasp/models/board_candidate_claim_test.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.

6 issues found across 11 files

Confidence score: 2/5

  • There is a high-impact authorization risk in backend/apps/owasp/api/internal/queries/board_candidate_claim.py: self-authorization matches Nest username to GitHub login, which can allow private claim access on username collisions.
  • backend/apps/owasp/models/board_candidate_claim.py introduces multiple data-integrity/regression risks: bulk_save bypasses save()/full_clean() (skipping validation/lock/order logic), draft claims can keep order=0 after later board assignment, and max(order)+1 is non-atomic under concurrency.
  • backend/apps/owasp/api/internal/queries/board_candidate_claim_evidence.py may dereference null (claim.candidate.member.login), and backend/apps/owasp/models/board_of_directors.py adds get_candidate(login) without direct test coverage, increasing uncertainty.
  • Pay close attention to backend/apps/owasp/api/internal/queries/board_candidate_claim.py, backend/apps/owasp/models/board_candidate_claim.py, backend/apps/owasp/api/internal/queries/board_candidate_claim_evidence.py, backend/apps/owasp/models/board_of_directors.py - authorization correctness, validation/order invariants, null-safety, and untested query behavior.

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

Re-trigger cubic

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 5, 2026
cubic-dev-ai[bot]
cubic-dev-ai Bot previously approved these changes Jun 5, 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 7 files (changes from recent commits).

Re-trigger cubic

@rudransh-shrivastava
rudransh-shrivastava marked this pull request as ready for review June 5, 2026 07:11
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 5, 2026
@rudransh-shrivastava rudransh-shrivastava added the gsoc2026:rudransh-shrivastava rudransh-shrivastava's GSoC 2026 related work label Jun 6, 2026
@rudransh-shrivastava
rudransh-shrivastava marked this pull request as draft June 10, 2026 06:10
@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 5 files (changes from recent commits).

Re-trigger cubic

@rudransh-shrivastava
rudransh-shrivastava marked this pull request as ready for review June 10, 2026 12:08
@rudransh-shrivastava

Copy link
Copy Markdown
Collaborator Author

I don't know why pre-commit is failing. I will sync feature branch with main after this PR is merged.

if not is_self and claim.status != BoardCandidateClaim.Status.APPROVED:
return []

return claim.evidences.filter(is_removed=False)

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 made this one liner, will add this change in another PR.

@arkid15r
arkid15r merged commit 42b076f into OWASP:feature/bod-candidate-transparency Jun 12, 2026
53 of 56 checks passed
rudransh-shrivastava added a commit to rudransh-shrivastava/Nest that referenced this pull request Jun 17, 2026
* add candidate claim graphql queries

* add tests for get_candidate

* add tests for nodes

* guard null member

* expose nest_created/updated_at as created/updated_at fields

* sort alphabetically

* address review comments

* fix missing created_at
rudransh-shrivastava added a commit to rudransh-shrivastava/Nest that referenced this pull request Jun 17, 2026
* add candidate claim graphql queries

* add tests for get_candidate

* add tests for nodes

* guard null member

* expose nest_created/updated_at as created/updated_at fields

* sort alphabetically

* address review comments

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

Labels

backend backend-tests gsoc2026:rudransh-shrivastava rudransh-shrivastava's GSoC 2026 related work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement GraphQL Queries and Mutations for Candidate Claim Data

2 participants