• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / relman-auto-nag / #5967

30 Jul 2026 07:49PM UTC coverage: 23.538% (+0.6%) from 22.939%
#5967

push

coveralls-python

msujaws
Send newly filed frontend bugs from Mozilla staff for automatic triage

hackbot's frontend-triage agent produces a root-cause analysis and fix plan
for a Firefox frontend bug, and posts it to the bug when it is confident — but
nothing was starting runs, so every triage needed a human to trigger it from
the hackbot UI. This rule starts them for newly filed bugs, hourly.

Scoped deliberately narrowly, because the agent's analysis lands on the bug
unattended:

- Reporters we expect to file well. Staff membership comes from the IAM roster
  we already maintain (`People.is_mozilla`), which covers QA as well now that
  they file from @mozilla.com addresses. The roster is also the reason this
  lives here rather than in bugbug: it maps a staffer's Bugzilla address to
  them, so employees who file from a personal account are still in scope, and a
  @mozilla.com address IAM doesn't know about is not.
- One component to start, `Firefox :: New Tab Page`. The component list is
  config, so widening it is an edit to configs/rules.json.

The rule makes no Bugzilla writes of its own — it starts runs and reports what
it started. `max_triggers` caps how many runs one invocation may start, since
each is real LLM spend, and bugs left over (over the cap, or whose run failed
to start) are excluded from the report and the cache so they come back on the
next run rather than being silently dropped.

`HACKBOT_API_URL` defaults to the production deployment so the cron host needs
no extra environment, the way `BUGBUG_HTTP_SERVER` does; set it to point at
another deployment. `People` is injectable because configs/people.json is
gitignored and absent in CI, so the reporter filter could not otherwise be
tested at all.

Requires `hackbot_api_key` in configs/config.json; the rule fails up front and
reports it if the API URL is explicitly blanked.

535 of 3200 branches covered (16.72%)

58 of 67 new or added lines in 2 files covered. (86.57%)

2303 of 9784 relevant lines covered (23.54%)

0.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.14
/bugbot/hackbot_utils.py
1
# This Source Code Form is subject to the terms of the Mozilla Public
2
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
3
# You can obtain one at http://mozilla.org/MPL/2.0/.
4

5
import os
1✔
6

7
import requests
1✔
8

9
from bugbot import utils
1✔
10

11
DEFAULT_API_URL = "https://hackbot-api.moz.tools"
1✔
12

13
TIMEOUT = 60
1✔
14

15

16
def api_url() -> str:
1✔
17
    """The hackbot API base URL.
18

19
    hackbot runs the LLM agents (see mozilla/bugbug's services/hackbot-api). We
20
    only ever start a run from here: the agent applies its own findings to
21
    Bugzilla and reports the result to Slack itself, so nothing comes back to us.
22

23
    Defaults to the production deployment so the cron host needs no extra
24
    environment, the way ``BUGBUG_HTTP_SERVER`` does. Override
25
    ``HACKBOT_API_URL`` to point at another deployment — that is the name
26
    hackbot's other clients already use (the pulse listener's setting and the
27
    console's deploy env), so there is one name to remember across all three.
28

29
    Read per call rather than at import so the override is settable by anything
30
    that configures the environment after this module loads.
31
    """
32
    return os.environ.get("HACKBOT_API_URL", DEFAULT_API_URL)
1✔
33

34

35
def trigger_agent_run(agent: str, inputs: dict) -> str:
1✔
36
    """Start a hackbot agent run.
37

38
    Args:
39
        agent: The agent to run, e.g. `frontend-triage`.
40
        inputs: The agent's per-run inputs, e.g. `{"bug_id": 1234567}`.
41

42
    Returns:
43
        The id of the created run.
44
    """
NEW
45
    base_url = api_url()
×
NEW
46
    if not base_url:
×
NEW
47
        raise ValueError("HACKBOT_API_URL is not set")
×
48

NEW
49
    response = requests.post(
×
50
        f"{base_url.rstrip('/')}/agents/{agent}/runs",
51
        headers={"X-API-Key": utils.get_login_info()["hackbot_api_key"]},
52
        json=inputs,
53
        timeout=TIMEOUT,
54
    )
NEW
55
    response.raise_for_status()
×
56

NEW
57
    return response.json()["run_id"]
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc