Surface catalog vendors in tracker policy doc

The generated tracker policy listed only org ThirdParty rows linked to
the banner's patterns. Now that the mapping worker no longer auto-creates
those rows, a banner whose vendors have not been imported would render an
empty third-party section.

Build the list from the same union the banner's linkedThirdParties
resolver exposes: org ThirdParty rows plus the CommonThirdParty catalog
entries reached through patterns that carry no org link. Dedupe by name
with org rows taking precedence, so the policy stays complete and
accurate whether or not a vendor has been imported into the register.

Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
Émile Ré
2026-06-10 14:41:03 +02:00
parent c25e7c6c40
commit ed2dbe92c9

View File

@@ -269,28 +269,102 @@ func (s *GeneratedDocumentService) buildTrackerPolicyThirdParties(
return nil, fmt.Errorf("cannot load distinct third party ids: %w", err)
}
if len(thirdPartyIDs) == 0 {
var thirdParties coredata.ThirdParties
if len(thirdPartyIDs) > 0 {
if err := thirdParties.LoadByIDs(ctx, conn, scope, thirdPartyIDs); err != nil {
return nil, fmt.Errorf("cannot load third parties: %w", err)
}
}
// Patterns not linked to an org ThirdParty still surface their catalog
// (CommonThirdParty) vendor, mirroring the banner's linkedThirdParties
// union, so the policy stays complete whether or not the vendor was
// imported into the org register.
commonPatternIDs, err := patterns.LoadDistinctCommonTrackerPatternIDsByCookieBannerID(ctx, conn, scope, cookieBannerID)
if err != nil {
return nil, fmt.Errorf("cannot load distinct common tracker pattern ids: %w", err)
}
var commonParties coredata.CommonThirdParties
if len(commonPatternIDs) > 0 {
var commonPatterns coredata.CommonTrackerPatterns
if err := commonPatterns.LoadByIDs(ctx, conn, commonPatternIDs); err != nil {
return nil, fmt.Errorf("cannot load common tracker patterns: %w", err)
}
seen := make(map[gid.GID]struct{}, len(commonPatterns))
commonThirdPartyIDs := make([]gid.GID, 0, len(commonPatterns))
for _, cp := range commonPatterns {
if cp.CommonThirdPartyID == nil {
continue
}
if _, ok := seen[*cp.CommonThirdPartyID]; ok {
continue
}
seen[*cp.CommonThirdPartyID] = struct{}{}
commonThirdPartyIDs = append(commonThirdPartyIDs, *cp.CommonThirdPartyID)
}
if len(commonThirdPartyIDs) > 0 {
if err := commonParties.LoadByIDs(ctx, conn, commonThirdPartyIDs); err != nil {
return nil, fmt.Errorf("cannot load common third parties: %w", err)
}
}
}
if len(thirdParties) == 0 && len(commonParties) == 0 {
return nil, nil
}
var thirdParties coredata.ThirdParties
if err := thirdParties.LoadByIDs(ctx, conn, scope, thirdPartyIDs); err != nil {
return nil, fmt.Errorf("cannot load third parties: %w", err)
rows := make([]docgen.TrackerPolicyThirdParty, 0, len(thirdParties)+len(commonParties))
// Dedupe by name so a vendor present both as an org third party (one
// pattern) and as a catalog entry (an unlinked pattern) is listed
// once. Org third parties are appended first, so their richer
// (user-editable) data wins for a shared name.
seenName := make(map[string]struct{}, len(thirdParties)+len(commonParties))
addRow := func(name, description, privacyPolicyURL string) {
name = strings.TrimSpace(name)
key := strings.ToLower(name)
if _, ok := seenName[key]; ok {
return
}
seenName[key] = struct{}{}
rows = append(rows, docgen.TrackerPolicyThirdParty{
Name: name,
Description: collapseWhitespace(description),
PrivacyPolicyURL: strings.TrimSpace(privacyPolicyURL),
})
}
rows := make([]docgen.TrackerPolicyThirdParty, 0, len(thirdParties))
for _, tp := range thirdParties {
row := docgen.TrackerPolicyThirdParty{Name: strings.TrimSpace(tp.Name)}
description := ""
if tp.Description != nil {
row.Description = collapseWhitespace(*tp.Description)
description = *tp.Description
}
privacyPolicyURL := ""
if tp.PrivacyPolicyURL != nil {
row.PrivacyPolicyURL = strings.TrimSpace(*tp.PrivacyPolicyURL)
privacyPolicyURL = *tp.PrivacyPolicyURL
}
rows = append(rows, row)
addRow(tp.Name, description, privacyPolicyURL)
}
for _, cp := range commonParties {
privacyPolicyURL := ""
if cp.PrivacyPolicyURL != nil {
privacyPolicyURL = *cp.PrivacyPolicyURL
}
addRow(cp.Name, "", privacyPolicyURL)
}
// LoadByIDs returns rows in an unspecified order (no ORDER BY), so sort