Resolves #48689 Adds a CPE translation so Firefox Developer Edition on macOS resolves to the standard `mozilla:firefox` product. Without it, `CPEFromSoftware` generates no CPE for the app, so it matches no Firefox CVEs and shows as vulnerability-free — a silent false negative. The root cause is that none of the standard matching paths fit Developer Edition: its bundle identifier `org.mozilla.firefoxdeveloperedition` splits to a product token (`firefoxdeveloperedition`) that has no NVD entry, and the sanitized-name and full-text fallbacks don't resolve to `firefox` either. Regular Firefox works only because its bundle (`org.mozilla.firefox`) splits cleanly to `mozilla`/`firefox`. The fix uses the same translation mechanism the existing Firefox ESR rule uses, mapping the Developer Edition bundle to `product: firefox`, `vendor: mozilla` — with no `sw_edition`, since Developer Edition tracks standard Firefox advisories (ESR is the special case that needs the `esr` edition). Match is on the bundle identifier rather than the display name so it's stable regardless of how the app name is ingested. **Out of scope:** Firefox Nightly (`org.mozilla.nightly`) has the same failure mode but uses pre-release version strings (e.g. `155.0a1`) that don't line up with NVD's per-version Firefox CPEs, so mapping it to `firefox` risks bad matches — it warrants separate handling. Firefox Beta already works today (its bundle is `org.mozilla.firefox`), so it needs no change. **Testing.** Two layers, matching how the codebase already tests CPE rules: - An offline unit test (`TestFirefoxDeveloperEditionTranslation`) loads the real shipped `cpe_translations.json` and asserts Developer Edition translates to `mozilla:firefox` with no `sw_edition`. It needs no CPE dictionary or network, so it runs in the fast suite. - A case in the network-gated `TestCPEFromSoftwareIntegration`, alongside the existing regular-Firefox case, asserts the full CPE string against the live NVD dictionary in CI. It reuses the known-good `105.0.1` Firefox entry. The downstream CPE→CVE step is unchanged and already covered for `mozilla:firefox` by `TestTranslateCPEToCVE`, so no new CVE-matching test is needed. # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually — ran `TestFirefoxDeveloperEditionTranslation` locally against the shipped rule (passes); the full software→CPE resolution against live NVD data is exercised by the network-gated integration case in CI. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved recognition of Firefox Developer Edition on macOS so it maps to the expected Firefox vulnerability data. * Better handling of version matching for this app, helping scan results stay accurate. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
CPE Translations
CPE Translations are rules to address bugs when translating Fleet software to Common Platform Enumerations (CPEs) which are used to identify software in the National Vulnerability Database (NVD)
To improve accuracy when mapping software to CVEs, we can add data to cpe_translations.json
How CPE translations work
CPE Translations are defined in cpe_translations.json and currently released in
GitHub once a day. The rules are specified in JSON format and
and each rule consists of a software and a filter object.
software defines matching logic on what Fleet Software this rule should apply to. You can use one
or more of the below attributes to match on. Each attribute is an array of string or regex
matches (a regex string is identified by a leading and trailing /).
A match on the attribute is found if at least 1 item in the array matches. If multiple
attributes are defined, then a match is needed for each attribute. (ie. name == Zoom.app &&
source == apps)
software attributes:
name: A software name attributebundle_identifier: A software bundle_identifier attribute (macOS only)source: A software source attribute (ie.apps,chrome_extensions, etc...)
example: Search Fleet software for items that match: (bundle_identifier == us.zoom.xos) AND (source = apps)
"software": {
"bundle_identifier": ["us.zoom.xos"],
"source": ["apps"]
}
If the software rule matches, then Fleet will search known NVD CPEs (stored in a local sqlite database) using the
specified filters or skip the software item based on the filter specified.
filter attributes:
product: array of strings to search by product field. If not specified, the software name is used.vendor: array of strings to search by vendor fieldtarget_sw: array of strings to search by target_sw fieldpart: string to override the default "a" Part valueskip: boolean; software is skipped iftrue. This overrides any other filters set.
Like the software matching logic, filter items are matched by OR within the array, and AND between filter items
example: Query the CPE database for a CPE that matches: (product == zoom OR product == meetings) AND (vendor == zoom) AND (target == macos OR target == mac_os)
"filter": {
"product": ["zoom", "meetings"],
"vendor": ["zoom"],
"target_sw": ["macos", "mac_os"]
}
Testing CPE Translations (end-to-end)
-
make the appropriate changes to cpe_translations
-
host this file on a local web server
go run ./tools/file-server/main.go 8082 ./server/vulnerabilities/nvd/ -
(re)launch your local fleet server with one of the following
Config method
vulnerabilities: cpe_translations_url: "http://localhost:8082/cpe_translations.json"Environment method
FLEET_VULNERABILITIES_CPE_TRANSLATIONS_URL="http://localhost:8082/cpe_translations.json" ./build/fleet serve --dev --dev_license --logging_debug -
trigger a vulnerabilities scan
fleetctl trigger --name vulnerabilities