Skip to content

Bug 2081860 - Migrate Bug REST resource to native Mojo API: bug objects (get, search, create, update, possible_duplicates, history) - #2800

Open
Xzzz wants to merge 15 commits into
mozilla:masterfrom
Xzzz:bug-2081860
Open

Xzzz wants to merge 15 commits into
mozilla:masterfrom
Xzzz:bug-2081860

Conversation

@Xzzz

@Xzzz Xzzz commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Ports the remaining bug methods (get, search, history, possible_duplicates, create, update) from Bugzilla::WebService::Bug into a native Bugzilla::API::V1::Bug Mojo controller, and removes the legacy Bug module.

Last of the four sub-bugs of 2081819.

Changes

  • Add Bugzilla/API/V1/Bug.pm, with the same responses as the legacy endpoints:
    • GET / POST /rest/bug (search / create), GET /rest/bug/ with ids in the query string (get)
    • GET / PUT /rest/bug/<id>, GET /rest/bug/<id>/history, GET /rest/bug/possible_duplicates
    • OPTIONS on each
  • Move the user, flag, attachment and comment hash helpers, the comment edit-info preload and the "updates disabled" error into Bugzilla/API/V1/Util.pm, used by BugAttachment, BugComment and Bug instead of their own copies.
  • Remove Bugzilla/WebService/Bug.pm (including update_see_also, which had no route), Resources/Bug.pm and the Bug entry of WS_DISPATCH.
  • MyDashboard no longer inherits the legacy module: run_last_changes reads the bug activity directly.
  • Kept from the legacy server:
    • Date params converted to the database timezone (new_since, last_change_time, creation_time, datetime custom fields).
    • Anonymous get is rate-limited, logged-in get is logged and audited, and the webservice_bug_get hook runs.
    • Bugzilla->input_params holds the request params, which extensions read in bug hooks (e.g. Needinfo's needinfo_from).
    • create returns 200: the legacy route asked for 201 but the server used 200.
  • Docs: permissive and faults for Get Bug; general.md lists only Bugzilla as not migrated.
  • Tests: new qa/t/rest_bug_routes.t; t/app-cgi-request-limit.t checks the legacy rest.cgi path with /rest/version.

Behaviour changes:

  • Credentials in the request body (api_key, login/password…) are not accepted, as on the other native resources: use the X-Bugzilla-API-Key header.
  • permissive on get now works: a bug that can't be returned is listed in faults (id, faultString, faultCode). The legacy REST server failed the whole request.
  • Credential params are no longer counted as search criteria, so a search without criteria gets buglist_parameters_required (when search_allow_no_criteria is off) however the caller authenticates.

Not carried over: JSONP callback=, as in the other migrated V1 modules. Get, search and history keep their ETag and answer 304 to a matching If-None-Match.

Test plan

  • GET /rest/bug/<id> and GET /rest/bug/?ids=<id>&ids=<alias>, logged out and logged in, with include_fields=_all
  • GET /rest/bug/<id>?ids=<unknown>&permissive=1, expecting the bug plus a fault
  • GET /rest/bug?product=<product>&limit=2, ?quicksearch=ALL&limit=1, ?count_only=1
  • GET /rest/bug/<id>/history?new_since=<date>
  • Repeat a get, a search and a history request with If-None-Match: <ETag>, expecting 304
  • GET /rest/bug/possible_duplicates?summary=<words>&product=<product>
  • POST /rest/bug, then PUT /rest/bug/<id> with a comment and a flag
  • Bug modal: edit a bug, add a CC, change the product; My Dashboard: expand a bug's last changes

References

@Xzzz
Xzzz requested a review from dklawren October 27, 2026 20:17
Comment thread Bugzilla/API/V1/Bug.pm Resolved
Comment thread Bugzilla/API/V1/Bug.pm Outdated
Bugzilla::Hook::process('webservice_bug_get',
{webservice => $self, user => $user, params => $params, bug_data => \@hashes,});

return $self->render(json => {bugs => \@hashes, faults => \@faults});

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.

ETag support looks like it was lost here. The legacy get() called $self->bz_etag(\@hashes) before adding update tokens, and the REST/JSON-RPC server then sent the ETag header and answered If-None-Match with a 304. None of the native get/search/history handlers set an ETag.

Clients polling GET /rest/bug/123 with If-None-Match (bots, dashboards) will now get a full 200 body every time. Was dropping this intentional?

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.

Yes that was intentional. None of the native V1 modules send an ETag (Group, User, BugComment, BugAttachment...), so I kept Bug consistent with them, and the PR description lists it under "Not carried over".

=> If you'd rather keep ETag/304 for bug get/search/history, it's a small change and I can add it back in this PR.

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.

Yes. Let's add it back to bug get/search/history if we can. It might confuse clients who are using etag checks before getting the full bug/search. Sorry to change.

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.

No problem :)

Done in 68890f3: get, search and history send an ETag again and answer 304 Not Modified when If-None-Match matches. As in the legacy server, the ETag is the MD5 of the response data, and for get it's computed before the update tokens are added, since those change on every request.

Also, new checks in qa/t/rest_bug_routes.t for the three routes (fail without the fix). The ETag values differ from the legacy ones, so a client gets one full response after the deploy, then 304s again.

And, last but not least, PR description is updated too.

Comment thread Bugzilla/API/V1/Bug.pm Resolved
Comment thread Bugzilla/API/V1/Bug.pm Resolved
Comment thread Bugzilla/API/V1/Bug.pm Resolved
Comment thread Bugzilla/API/V1/Bug.pm Resolved
Comment thread t/app-cgi-request-limit.t Resolved
@Xzzz
Xzzz requested a review from dklawren October 29, 2026 16:08

@dklawren dklawren 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.

We can land this after etag support added back,

@Xzzz
Xzzz requested a review from dklawren October 29, 2026 22:54

@dklawren dklawren 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.

Sorry. Found one more last issue. Then we should be good :)

Comment thread Bugzilla/API/V1/Bug.pm Resolved
@Xzzz
Xzzz requested a review from dklawren October 30, 2026 03:01
@Xzzz

Xzzz commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator Author

Added some fixup after deeper review:

  • f35534b: match_field also refuses, for API callers, a single match that isn't the exact login when confirmuniqueusermatch is on (its default): the web UI asks to confirm it, so the API shouldn't silently pick that user. New t/user-match-webservice.t.
  • e4b1b53: MyDashboard's last changes read from the shadow database again, as Bug.history did before, now for all its reads (the comment id was read from the main database and the comment from the shadow).
  • 74adff5: search() put its last_change_time / creation_time conditions at "number of fN params + 1", so with f1 and f3 the f3 condition was replaced and silently dropped. They now go after the highest fN. That line came from the legacy WebService/Bug.pm. Check in qa/t/rest_bug_routes.t.

@dklawren dklawren 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.

Approved once the params issue is fixed.

Comment thread Bugzilla/API/V1/Bug.pm
my $user = $self->bugzilla->login;
$user->id || return $self->user_error('login_required');

my ($params, $responded) = $self->_request_params;

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.

with no list params, a form-encoded create like cc=a&cc=b or groups=x&groups=y now keeps only the last value (legacy got an array), so ccs and groups get dropped silently. maybe pass the list fields here (cc, groups, keywords, blocks, depends_on, see_also...) or keep repeated keys as arrays like the GET branch does

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants