Read v3 vendor directories for licenses with the dataset-neutral OfflineV3 connector
What does this MR do and why?
LicenseV3SyncService landed with #622511 (closed) raising NotImplementedError for its offline connector, because the only v3 vendor reader was called MalwareOffline. Nothing in that reader is malware specific, the layout it walks belongs to the v3 distribution contract, so this renames it to OfflineV3 and moves offline_connector_class onto V3SyncService itself. Both datasets read the same vendor layout, so no subclass has to supply it and licenses can sync from an air-gapped directory.
The header comment also told admins to unpack into <base_uri>/v3/<purl_type>/ when the path is built from the registry id, so a gem snapshot belongs in v3/rubygem/ and following the comment gave an empty sync with no log line. The spec only covered npm, the one registry where both strings match, and only ever used a malware sync config. It now covers gem→rubygem and a licenses config.
References
Relates to #611168 and #622511 (closed).