Files
rengine/shared/definitions/mode_features.py
T
Yogesh OjhaandClaude Opus 5 dcdba5cfd4 feat(bounty-hub): read Intigriti through its researcher API
A platform with a researcher API is now a provider: one module under
shared/services/bounty_providers implementing programs() and scopes(),
returning rows the sync engine stores. bounty_programs.py became the
platform-agnostic engine, so adding a platform is one module, one
APIProvider value, one PlatformSpec.api_provider and a key tester.

Intigriti is the second connected platform, on a personal access token
the hunter creates. On this instance: 220 programs, 54 of them private,
155 with scope and 65 the platform refuses, which accounts for all 220.

Measured against the live API, against the docs:

- Tier ids are unordered and undocumented. Id 4 is Tier 1, not No Bounty,
  so the first mapping stored the best-paying assets as paying nothing.
  Eligibility reads the label; out of scope is matched on id and label.
- A 403 carrying FORBID001 is a refusal, not the documented rate-limit
  overage, and it covers public programs the account has not joined.
  Retrying it cost 11s a program; AccessDeniedError ends it in one
  request and records scope_access, keeping the failure budget for
  real breakage.
- Membership is proved by the platform letting the token read a private
  program's scope. confidentialityLevel never reports "invite only", so
  joined was always false and its filter was dead.

Bounty Hub follows what the data actually says:

- source becomes sources, a JSONB array. A program is routinely in both
  a platform API and the public feed; the feed adds itself without
  taking an API row back, and facet counts overlap accordingly.
- The row hint read "Bookmarked on HackerOne" while rendering
  Intigriti's follow flag. It now reads PlatformSpec.follow_label.
- Refresh queued the sync and returned, so nothing changed on screen.
  It waits for the sweep, reloads, and says so.
- The dashed connect card per platform is one dismissible Alert.
- Connecting a platform no longer diffs API scope against feed scope,
  which would report every asset removed and re-added.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SiHx8Sm34hS1nanrsPdBaD
2026-09-12 23:35:59 +05:30

39 lines
1.1 KiB
Python

from shared.enums.instance import InstanceMode
CAP_BOUNTY_PLATFORMS = "bounty_platforms"
CAP_BOUNTY_PROGRAMS = "bounty_programs"
CAP_BB_RECON_PRESETS = "bb_recon_presets"
CAP_PROGRAM_WATCHES = "program_watches"
_MODE_CAPABILITIES: dict[str, set[str]] = {
InstanceMode.BUG_BOUNTY.value: {
CAP_BOUNTY_PLATFORMS,
CAP_BOUNTY_PROGRAMS,
CAP_BB_RECON_PRESETS,
CAP_PROGRAM_WATCHES,
},
InstanceMode.CORPORATE.value: set(),
}
BUG_BOUNTY_PROVIDERS: frozenset[str] = frozenset({"hackerone", "intigriti"})
VALID_MODES: frozenset[str] = frozenset(
{InstanceMode.BUG_BOUNTY.value, InstanceMode.CORPORATE.value}
)
def capabilities_for(mode: str | None) -> list[str]:
if mode not in _MODE_CAPABILITIES:
return sorted(_MODE_CAPABILITIES[InstanceMode.BUG_BOUNTY.value])
return sorted(_MODE_CAPABILITIES[mode])
def has_capability(mode: str | None, capability: str) -> bool:
return capability in capabilities_for(mode)
def provider_allowed(mode: str | None, provider: str) -> bool:
if provider in BUG_BOUNTY_PROVIDERS:
return has_capability(mode, CAP_BOUNTY_PLATFORMS)
return True