Skip to content

feat(api): expose reset status polling#1598

Merged
jjmata merged 7 commits into
we-promise:mainfrom
JSONbored:feat/api-reset-status
May 2, 2026
Merged

feat(api): expose reset status polling#1598
jjmata merged 7 commits into
we-promise:mainfrom
JSONbored:feat/api-reset-status

Conversation

@JSONbored
Copy link
Copy Markdown
Contributor

@JSONbored JSONbored commented Apr 30, 2026

Summary

  • Return reset queue metadata from the user reset endpoint.
  • Add a lightweight reset status endpoint for polling reset completion.

What changed

  • Make DELETE /api/v1/user return status, job_id, family_id, and status_url.
  • Add GET /api/v1/users/reset/status to expose reset-target counts and a reset_complete boolean.
  • Use the API resource owner's family consistently in reset code paths.
  • Update tests and OpenAPI docs.

Why

The destructive reset endpoint currently queues async work without giving API clients a reliable way to know when it is safe to import into a clean family. Polling status makes automation and recovery workflows less fragile without changing the reset job itself.

Validation

  • /usr/bin/ruby -c app/controllers/api/v1/users_controller.rb
  • /usr/bin/ruby -c test/controllers/api/v1/users_controller_test.rb
  • /usr/bin/ruby -c spec/requests/api/v1/users_spec.rb
  • ruby -e 'require "yaml"; YAML.load_file("docs/api/openapi.yaml")'
  • git diff --check

Blocked locally:

  • bin/rails test ... and bin/rubocop require the repository Ruby/Bundler toolchain. This workstation currently exposes Ruby 2.6.10, while Sure requires Ruby 3.4.7 and Bundler 2.6.7.

Notes

  • Draft pending upstream CI and maintainer validation.

Summary by CodeRabbit

  • New Features

    • Added account reset status endpoint with per-family resource counts; reset initiation now returns queue tracking info (job_id, family_id, status_url) and queued status.
    • Tightened access control: separate read/write scope behavior and admin requirement for reset actions.
  • Bug Fixes

    • Enqueue failures return a controlled 500 error payload and log failures; replaced ambiguous admin-denied text with a fixed message.
  • Documentation

    • API docs updated with new reset response schemas and status endpoint.
  • Tests

    • Added coverage for initiation, status, access control, and enqueue-failure cases.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

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

Walkthrough

Adds an admin-protected asynchronous family account reset flow: DELETE /api/v1/users/reset enqueues FamilyResetJob for current_resource_owner.family (returns queue metadata and handles enqueue failures); GET /api/v1/users/reset/status reports per-family target counts, reset_complete, and status.

Changes

Cohort / File(s) Summary
API Controller
app/controllers/api/v1/users_controller.rb
Added reset_status action (gated by read scope and admin). Modified reset to enqueue FamilyResetJob with current_resource_owner.family, return {status, job_id, family_id, status_url}, rescue enqueue exceptions to log and respond 500 with error: "reset_enqueue_failed". Adjusted before-actions: read scope now applies only to reset_status, write scope to reset/others, and admin required for both; replaced i18n admin-denied message with a fixed string.
Routing
config/routes.rb
Added GET /api/v1/users/reset/statusapi/v1/users#reset_status.
API Documentation
docs/api/openapi.yaml
Added ResetInitiatedResponse and ResetStatusResponse schemas; updated DELETE /api/v1/users/reset response to ResetInitiatedResponse; added GET /api/v1/users/reset/status (200/401/403).
Swagger / Specs Schema
spec/swagger_helper.rb
Declared OpenAPI component schemas: ResetInitiatedResponse, ResetStatusResponse.
Request & Controller Tests
spec/requests/api/v1/users_spec.rb, test/controllers/api/v1/users_controller_test.rb
Updated tests to assert queued response fields (status, job_id, family_id, status_url), added enqueue-failure test (job raises → controller returns 500 with reset_enqueue_failed), and added GET /reset/status access-control and success assertions (allowed status values, reset_complete logic, and counts structure).

Sequence Diagram

sequenceDiagram
    participant Client
    participant API as Users API
    participant Queue as Job Queue
    participant DB as Database

    Client->>API: DELETE /api/v1/users/reset (auth, admin)
    activate API
    API->>Queue: Enqueue FamilyResetJob (family_id)
    Queue-->>API: job_id (enqueued) or error
    API-->>Client: 200 {status: rgba(0,128,0,0.5), job_id, family_id, status_url} or 500 {error: "reset_enqueue_failed"}
    deactivate API

    Client->>API: GET /api/v1/users/reset/status (auth, admin)
    activate API
    API->>DB: Aggregate per-family target counts
    DB-->>API: counts (per-entity totals)
    API-->>Client: 200 {status: rgba(0,128,0,0.5) or rgba(255,165,0,0.5), reset_complete, family_id, counts}
    deactivate API
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

codex, aardvark

Poem

🐇 I queued a hop and sent it west,
A job for family—do your best.
I poll the counts as numbers fall,
When all are zero I give a call.
A little hop, reset—we’re blessed.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(api): expose reset status polling' directly describes the main change: adding a new API endpoint for polling reset status, which aligns with the primary objective and the new GET endpoint added.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

@JSONbored JSONbored marked this pull request as ready for review April 30, 2026 11:08
@superagent-security superagent-security Bot added the contributor:flagged Contributor flagged for review by trust analysis. label Apr 30, 2026
@superagent-security
Copy link
Copy Markdown

superagent-security Bot commented Apr 30, 2026

⚠️ Contributor Trust Check — Review Recommended

This contributor's profile shows patterns that may warrant additional review. This is based on their GitHub activity, not the contents of this PR.

JSONbored · Score: 68/100

Dimension breakdown
Dimension Score What it measures
Identity 30 Account age, contribution history, GPG keys, org memberships
Behavior 80 PR patterns, unsolicited contribution ratio, activity cadence
Content 100 PR body substance, issue linkage, contribution quality
Graph 30 Cross-repo trust, co-contributor relationships

Analyzed by Brin · Full profile

@superagent-security superagent-security Bot added the pr:verified PR passed security analysis. label Apr 30, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/controllers/api/v1/users_controller.rb`:
- Around line 9-17: Wrap the FamilyResetJob.perform_later call in a begin/rescue
block to explicitly handle enqueue failures: call
FamilyResetJob.perform_later(current_resource_owner.family) inside the block,
rescue StandardError (or the specific ActiveJob/adapter exception if preferred),
log the exception, and return a controlled JSON error payload (e.g., message,
error, status: "failed_to_enqueue", and an appropriate HTTP status like 503)
instead of proceeding to render the success JSON that references job.job_id and
api_v1_users_reset_status_path; only render the original success response when
perform_later succeeds.

In `@spec/requests/api/v1/users_spec.rb`:
- Around line 92-102: The 401 and 403 response examples in the specs (response
'401' and response '403' blocks) lack explicit response schemas so the generated
OpenAPI omits the standard error contract; update those response blocks in
spec/requests/api/v1/users_spec.rb to include the same error response schema
used elsewhere (e.g., reference the shared error schema or add a schema block
with properties like code/message/details) so the OpenAPI generator emits the
standard error body for both unauthorized and forbidden responses.

In `@test/controllers/api/v1/users_controller_test.rb`:
- Around line 90-100: The test "reset status requires admin role" uses
ApiKey.create! with scopes ["read"], which could make the 403 come from scope
enforcement instead of role checks; change the non_admin_api_key creation in
this test (ApiKey.create!, users(:family_member), display_key) to use the
"read_write" scope so the key has sufficient scopes and the assertion (get
"/api/v1/users/reset/status" with api_headers(non_admin_api_key) and
assert_response :forbidden) isolates failure to admin-role enforcement rather
than scope restrictions.
🪄 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: 19aaa22f-97ef-4b71-ab64-631a42b0d497

📥 Commits

Reviewing files that changed from the base of the PR and between c91b730 and e7df60921d41bcf3af1d25ad68d4c4972c58f7f4.

📒 Files selected for processing (6)
  • app/controllers/api/v1/users_controller.rb
  • config/routes.rb
  • docs/api/openapi.yaml
  • spec/requests/api/v1/users_spec.rb
  • spec/swagger_helper.rb
  • test/controllers/api/v1/users_controller_test.rb

Comment thread app/controllers/api/v1/users_controller.rb Outdated
Comment thread spec/requests/api/v1/users_spec.rb
Comment thread test/controllers/api/v1/users_controller_test.rb
@JSONbored JSONbored force-pushed the feat/api-reset-status branch from e7df609 to baf22e0 Compare April 30, 2026 11:36
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: baf22e034f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/controllers/api/v1/users_controller.rb Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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)
test/controllers/api/v1/users_controller_test.rb (1)

71-83: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert the reset job receives the family.

This only verifies that FamilyResetJob was enqueued. Add an argument assertion so the test fails if the controller enqueues the wrong family.

Suggested patch
-    assert_enqueued_with(job: FamilyResetJob) do
+    assert_enqueued_with(job: FamilyResetJob, args: [ `@user.family` ]) do
       delete "/api/v1/users/reset", headers: api_headers(`@api_key`)
     end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/controllers/api/v1/users_controller_test.rb` around lines 71 - 83,
Update the assertion that the FamilyResetJob was enqueued to also verify the job
was given the correct family argument: change the assert_enqueued_with in the
test "reset enqueues FamilyResetJob and returns 200" to include args:
[`@user.family`] (i.e. assert_enqueued_with(job: FamilyResetJob, args:
[`@user.family`]) do ... end) so the test fails if the controller enqueues the
wrong family when calling delete "/api/v1/users/reset".
docs/api/openapi.yaml (1)

2800-2857: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document the enqueue-failure response.

The controller now returns a 500 ErrorResponse when FamilyResetJob.perform_later fails, but this OpenAPI block still only documents 200/401/403. Add the 500 response so the checked-in contract matches runtime behavior.

Suggested patch
       responses:
         '200':
           description: account reset initiated
           content:
             application/json:
               schema:
                 "$ref": "#/components/schemas/ResetInitiatedResponse"
         '401':
           description: unauthorized
           content:
             application/json:
               schema:
                 "$ref": "#/components/schemas/ErrorResponse"
         '403':
           description: "forbidden — requires read_write scope and admin role"
           content:
             application/json:
               schema:
                 "$ref": "#/components/schemas/ErrorResponse"
+        '500':
+          description: enqueue failure
+          content:
+            application/json:
+              schema:
+                "$ref": "#/components/schemas/ErrorResponse"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/api/openapi.yaml` around lines 2800 - 2857, The OpenAPI spec for DELETE
"/api/v1/users/reset" is missing the 500 response that the controller can return
when FamilyResetJob.perform_later fails; update the DELETE operation to add a
'500' response entry that uses the existing ErrorResponse schema
(`#/components/schemas/ErrorResponse`) so the contract matches runtime behavior
and documents the enqueue-failure case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@docs/api/openapi.yaml`:
- Around line 2800-2857: The OpenAPI spec for DELETE "/api/v1/users/reset" is
missing the 500 response that the controller can return when
FamilyResetJob.perform_later fails; update the DELETE operation to add a '500'
response entry that uses the existing ErrorResponse schema
(`#/components/schemas/ErrorResponse`) so the contract matches runtime behavior
and documents the enqueue-failure case.

In `@test/controllers/api/v1/users_controller_test.rb`:
- Around line 71-83: Update the assertion that the FamilyResetJob was enqueued
to also verify the job was given the correct family argument: change the
assert_enqueued_with in the test "reset enqueues FamilyResetJob and returns 200"
to include args: [`@user.family`] (i.e. assert_enqueued_with(job: FamilyResetJob,
args: [`@user.family`]) do ... end) so the test fails if the controller enqueues
the wrong family when calling delete "/api/v1/users/reset".

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 989b76cf-7f91-46b4-a600-58b5716fae4f

📥 Commits

Reviewing files that changed from the base of the PR and between e7df60921d41bcf3af1d25ad68d4c4972c58f7f4 and baf22e034f3bd1db7d4890d885f6256e1dbafe7c.

📒 Files selected for processing (6)
  • app/controllers/api/v1/users_controller.rb
  • config/routes.rb
  • docs/api/openapi.yaml
  • spec/requests/api/v1/users_spec.rb
  • spec/swagger_helper.rb
  • test/controllers/api/v1/users_controller_test.rb

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/controllers/api/v1/users_controller.rb`:
- Around line 60-64: The ensure_admin method in UsersController uses a localized
I18n.t("users.reset.unauthorized") message which makes API v1 responses
locale-dependent; update ensure_admin so the render_json call returns a stable
hardcoded English message (e.g. message: "You are not authorized to perform this
action" or the project’s standard API v1 error text) instead of I18n.t(...),
keeping the same status :forbidden and preserving the error key and return false
behavior; locate this change in the ensure_admin method referencing
current_resource_owner and render_json.
🪄 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: 8dec3865-97df-4666-9b0a-69c3c2732822

📥 Commits

Reviewing files that changed from the base of the PR and between baf22e034f3bd1db7d4890d885f6256e1dbafe7c and d9b5582662062bb12b725c6ed59e172af5a34ef9.

📒 Files selected for processing (2)
  • app/controllers/api/v1/users_controller.rb
  • test/controllers/api/v1/users_controller_test.rb

Comment thread app/controllers/api/v1/users_controller.rb
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/controllers/api/v1/users_controller.rb`:
- Around line 19-25: The rescue is too broad in the UsersController#reset
action—limit error handling to the FamilyResetJob enqueue call so other
exceptions still propagate; wrap only the FamilyResetJob.perform_later (or
enqueue) invocation in a begin/rescue that catches the exception as e, log
Rails.logger.error with the error details and render the 500 JSON using the API
v1 format (error: "reset_enqueue_failed", message: "Error: #{e.message}",
status: :internal_server_error). Leave the rest of the reset action unrescued so
non-enqueue errors are not misclassified.
🪄 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: fc01d668-1f54-47ad-89e9-203e9c8e4c91

📥 Commits

Reviewing files that changed from the base of the PR and between d9b5582662062bb12b725c6ed59e172af5a34ef9 and 874389405d65523587ed5451a45bc1817718d7a8.

📒 Files selected for processing (1)
  • app/controllers/api/v1/users_controller.rb

Comment thread app/controllers/api/v1/users_controller.rb Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
app/controllers/api/v1/users_controller.rb (1)

15-18: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep API v1 500 error message format consistent.

On Line 17, the enqueue-failure payload diverges from the API v1 convention used elsewhere ("Error: #{e.message}"), which can create inconsistent client/test expectations.

Suggested patch
-      render json: {
+      render_json({
         error: "reset_enqueue_failed",
-        message: "Account reset could not be queued"
-      }, status: :internal_server_error
+        message: "Error: #{e.message}"
+      }, status: :internal_server_error)

Based on learnings: In app/controllers/api/v1/**/*.rb, 500 responses should follow message: "Error: #{e.message}".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/api/v1/users_controller.rb` around lines 15 - 18, The 500
response in UsersController currently returns a static message ("Account reset
could not be queued") which breaks the API v1 convention; update the render json
in the error branch (the render json block that returns error:
"reset_enqueue_failed") to follow the standard pattern and return message:
"Error: #{e.message}" (use the exception variable used in the rescue/error
handler), so the payload matches other app/controllers/api/v1/*.rb 500
responses.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@app/controllers/api/v1/users_controller.rb`:
- Around line 15-18: The 500 response in UsersController currently returns a
static message ("Account reset could not be queued") which breaks the API v1
convention; update the render json in the error branch (the render json block
that returns error: "reset_enqueue_failed") to follow the standard pattern and
return message: "Error: #{e.message}" (use the exception variable used in the
rescue/error handler), so the payload matches other app/controllers/api/v1/*.rb
500 responses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6b66e84c-f62c-4a45-89be-3c45331e760a

📥 Commits

Reviewing files that changed from the base of the PR and between 874389405d65523587ed5451a45bc1817718d7a8 and 667bdf3fe5573378d47ee66c09befdd4f423b6f5.

📒 Files selected for processing (1)
  • app/controllers/api/v1/users_controller.rb

@jjmata jjmata removed the contributor:flagged Contributor flagged for review by trust analysis. label Apr 30, 2026
@jjmata jjmata added this to the v0.7.1 milestone Apr 30, 2026
@jjmata jjmata self-requested a review April 30, 2026 21:21
@JSONbored JSONbored force-pushed the feat/api-reset-status branch from 667bdf3 to 7349ae9 Compare May 1, 2026 05:42
@superagent-security superagent-security Bot added the contributor:flagged Contributor flagged for review by trust analysis. label May 1, 2026
@JSONbored JSONbored force-pushed the feat/api-reset-status branch 2 times, most recently from c4dfab7 to ab1922f Compare May 1, 2026 20:12
Copy link
Copy Markdown
Collaborator

@jjmata jjmata left a comment

Choose a reason for hiding this comment

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

Another one I missed yesterday:


PR #1598 Review: feat(api): expose reset status polling

Overview

This PR adds two things:

  1. Enriches DELETE /api/v1/users/reset to return job_id, family_id, and status_url instead of just a plain message.
  2. Adds GET /api/v1/users/reset/status — a polling endpoint that returns counts of surviving family resources so API clients can determine when an async reset has materialized.

The motivation is sound: async reset with no observable completion state is fragile for automation. The implementation is reasonably clean but has a few issues worth addressing.


Issues

Bare rescue catches too broadly (users_controller.rb:19)

rescue => e

This catches all Exception subclasses, including SignalException, SystemExit, NoMemoryError, etc. It should be rescue StandardError => e. This was flagged by CodeRabbit and is still unresolved.

family_id declared as format: uuid in OpenAPI schemas

Both ResetInitiatedResponse and ResetStatusResponse declare family_id as type: string, format: uuid, but the Rails app uses integer primary keys by default. If Family uses integer IDs, the returned value is a number not a UUID string, and the schema is wrong. This needs verification against the actual model.

reset_status calls current_resource_owner.family twice and counts.values.sum twice

def reset_status
  counts = reset_target_counts(current_resource_owner.family)
  render json: {
    status: counts.values.sum.zero? ? "complete" : "data_remaining",
    family_id: current_resource_owner.family.id,   # second call
    reset_complete: counts.values.sum.zero?,        # computed again
    ...
  }
end

current_resource_owner.family hits the association twice; counts.values.sum is computed twice. Use local variables:

def reset_status
  family = current_resource_owner.family
  counts = reset_target_counts(family)
  complete = counts.values.sum.zero?
  render json: { status: complete ? "complete" : "data_remaining",
                 family_id: family.id, reset_complete: complete, counts: counts }
end

job_id is returned but the status endpoint is not job-scoped

The reset response includes job_id suggesting per-job status tracking, but GET /api/v1/users/reset/status returns family-wide resource counts, not job state. The job_id has no practical use with the current polling design. Either remove job_id from the response or document clearly that it is informational only.

Status heuristic is racy

Determining reset_complete via resource counts will return false if the user has any accounts/categories/etc. (which they likely will before a reset). After a reset completes, if the user immediately creates new data, the endpoint says "data_remaining" again. The description acknowledges this is counts-based but the field name reset_complete implies stronger semantics than what's actually implemented. Consider renaming it resources_cleared or improving the docstring.


Positives

  • Correct access control split: read scope for status, write + admin for reset. This is exactly right.
  • Current.familycurrent_resource_owner.family: Fixing this for the API context is correct.
  • Error message does not leak e.message to the client: The deliberate decision to use "Account reset could not be queued" instead of exposing e.message is the right security choice, regardless of what CodeRabbit suggested.
  • api_headers fix (plain_key vs display_key): This is a real bug fix that likely made the existing tests pass incorrectly before.
  • Test for no leakage of internal error message (assert_not_includes response.body, "queue down"): Good security-conscious test.
  • OpenAPI schemas are complete and consistent with the rswag helper.
  • source: "web" added to test ApiKey.create! calls: Likely fixes a validation that was previously being silently skipped.

Summary

The feature logic is solid and the access control is correct. The three things worth fixing before merge are: (1) rescue StandardError, (2) verifying family_id type in the OpenAPI schema, and (3) the duplicate current_resource_owner.family call in reset_status. The racy reset_complete semantics are worth at minimum a documentation note, and the job_id field should either be removed or its limited utility called out explicitly.

@jjmata jjmata removed the contributor:flagged Contributor flagged for review by trust analysis. label May 1, 2026
@jjmata
Copy link
Copy Markdown
Collaborator

jjmata commented May 1, 2026

Your last few PRs are all coming in as "draft" - you planning to flip them all to ready for review at some point in batch, @JSONbored?

@JSONbored JSONbored force-pushed the feat/api-reset-status branch from ab1922f to 2fcfd8f Compare May 2, 2026 01:11
@superagent-security superagent-security Bot added the contributor:flagged Contributor flagged for review by trust analysis. label May 2, 2026
@JSONbored
Copy link
Copy Markdown
Contributor Author

Your last few PRs are all coming in as "draft" - you planning to flip them all to ready for review at some point in batch, @JSONbored?

Yep, I split them intentionally so each PR is independently reviewable and mergeable. I realize 18 at once is a lot, so please treat them as a queue, not a demand to review everything at once.

Suggested review order:

  1. feat(api): expose reset status polling #1598 first, since it is the existing open change-request PR.
  2. fix(mercury): support named multiple API connections #1627 Mercury multiple connections.
  3. fix(auth): hash MFA backup codes #1629 backup-code hashing.
  4. API/export workflow PRs: feat(api): expose family exports #1632, feat(api): add import preflight validation #1633, feat(api): expose import row diagnostics #1644, then feat(api): expose sync status #1635/feat(api): expose provider connection health #1636.
  5. Data breadth PRs: feat(api): expose budget state #1640-feat(api): expose rule run history #1646.
  6. Larger UX/auth PRs last: feat(auth): add WebAuthn MFA credentials #1628 and feat(settings): add reviewed bulk cleanup flows #1630.

Happy to re-draft lower-priority PRs if the open queue feels too noisy.

@JSONbored JSONbored requested a review from jjmata May 2, 2026 06:15
@jjmata jjmata removed the contributor:flagged Contributor flagged for review by trust analysis. label May 2, 2026
@jjmata jjmata merged commit a8425a2 into we-promise:main May 2, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:verified PR passed security analysis.

Development

Successfully merging this pull request may close these issues.

2 participants