Commit Graph

1956 Commits

Author SHA1 Message Date
Émile Ré
53e1260d4d Add slug-based dedup and auto-create third parties from OCD
Add a slug column to common_third_parties for stable cross-source
deduplication. The OCD tracker patterns importer now resolves third
parties via a three-step cascade (slug lookup, domain fallback,
auto-create) instead of silently dropping unmatched links.

Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:08 +04:00
Émile Ré
a16821802e Fix PR review findings
- Replace copy-pasted New Relic URLs in Resend third-party entry
  with correct resend.com URLs and drop inapplicable fields
- Escape single '%' instead of '%%' in LIKE pattern conversion so
  literal percent signs are not treated as wildcards
- Return actual row ID from CommonTrackerPattern.Upsert via
  RETURNING id so conflict-path callers get the existing ID
- Add ORDER BY id ASC to vendor-by-common-third-party query for
  deterministic LIMIT 1 selection

Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:08 +04:00
Émile Ré
f52a4746fd Fix migration after rebase
Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:07 +04:00
Émile Ré
adcb820768 Fix undefined coredata struct
Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:07 +04:00
Émile Ré
36c0f18d1b Fix missing common_third_party_id in vendor queries
LoadByID and LoadByIDs used 4-space indentation and were missed
by the bulk column addition. The struct field existed but the
SELECT did not return it, causing pgx scan failures.

Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:07 +04:00
Émile Ré
d6f268cb06 Add tracker mapping worker and initiator domain extraction
Poll-based worker that maps org-scoped tracker patterns to the
common knowledge base via pattern matching and domain-based
attribution. Populates initiator_domain on detected trackers
at report time. Resolves org-scoped vendors through the common
third party link.

Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:07 +04:00
Émile Ré
1928aa9b72 Add ExtractDomain to pkg/uri for eTLD+1 extraction
Uses golang.org/x/net/publicsuffix to extract the effective
top-level domain plus one label from a URL. Used to populate
detected_trackers.initiator_domain for domain-based tracker
attribution.

Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:06 +04:00
Émile Ré
60ee8da348 Wire new FK columns into existing coredata models
Add CommonTrackerPatternID and ThirdPartyID to TrackerPattern,
CommonThirdPartyID to Vendor, InitiatorDomain to DetectedTracker.
Register CommonThirdPartyDomain (93) and CommonTrackerPattern (94)
entity types.

Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:06 +04:00
Émile Ré
8aa82104e0 Add coredata models for tracker mapping
CommonThirdPartyDomain maps eTLD+1 domains to third parties for
fast domain-based attribution. CommonTrackerPattern stores the
global tracker knowledge base with glob/exact matching support.

Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:06 +04:00
Émile Ré
19abeef0bb Add schema for tracker-to-vendor mapping
Introduces common_third_party_domains (CITEXT domain aliases per
third party), common_tracker_patterns (global tracker knowledge
base), and new FK columns on tracker_patterns (third_party_id,
common_tracker_pattern_id), vendors (common_third_party_id), and
detected_trackers (initiator_domain) to support automated
tracker-to-vendor attribution.

Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:05 +04:00
Cursor Agent
5995f41fa0 Remove backend inactive profile validation
Users are created with state=INACTIVE and only become ACTIVE on
first login. The server-side state check incorrectly rejected
newly-created users who hadn't yet activated their accounts.

The frontend filter (state: ACTIVE) is the correct layer to hide
deactivated people from the recipient picker. The existing contract
end date validation remains as server-side defense in depth.

Co-authored-by: Émile Ré <nemile.re@gmail.com>
Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 17:03:54 +04:00
Cursor Agent
e4005e0f74 Filter inactive people from signature request recipients
The signature request recipient lists (both the multi-select dialog
and the document signatures page) included people who were inactive
via SCIM deactivation. The existing filter only excluded people with
ended contracts but not those with an INACTIVE state.

This adds state: ACTIVE to the ProfileFilter in both frontend queries
and introduces a server-side ErrProfileInactive validation in the
RequestSignature and BulkRequestSignatures service methods to reject
inactive profiles even if called directly via API.

Co-authored-by: Émile Ré <nemile.re@gmail.com>
Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 17:03:53 +04:00
Aurélien Sibiril
7d0dec82f6 Guard Helm connector env vars on clientId / clientSecret → Address review feedback on access-review drivers
- Guard Helm connector env vars on clientId / clientSecret
- Decode Vercel pagination cursor as *int64
- Drop Monday probe URL — no valid GET endpoint
- Address review feedback on access-review drivers

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:51 +02:00
Aurélien Sibiril
995769c4b6 Drop dead OAuth2 TokenExtraParams plumbing → Reject non-numeric ClickUp timestamps via strconv
- Drop dead OAuth2 TokenExtraParams plumbing
- Drop Deel-only x-client-id header from basic-form
- Follow Bitbucket workspace pagination cursor
- Reject non-numeric ClickUp timestamps via strconv

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:50 +02:00
Aurélien Sibiril
c2db47e698 Require CLIENT_SECRET for new access-review connectors → Drop Snyk, Ramp, Lever, Deel access-review providers
- Require CLIENT_SECRET for new access-review connectors
- Use Heroku account UUID as ExternalID
- Bump GitHub orgs picker to per_page=100
- Drop Snyk, Ramp, Lever, Deel access-review providers

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:50 +02:00
Aurélien Sibiril
ceacaea34e Inline Vercel driver URL with url.URL → Drop allowedHosts:true from vite dev server
- Inline Vercel driver URL with url.URL
- Escape URL path segments in connector name resolvers
- Dedup Vercel /v2/user fallback in name resolver
- Drop allowedHosts:true from vite dev server

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:50 +02:00
Aurélien Sibiril
7b814576df Refine Asana OAuth2 scopes → Build driver query URLs with url.URL not concatenation
- Refine Asana OAuth2 scopes
- Re-record access-review cassettes from live tokens
- Escape URL path segments in access-review drivers
- Build driver query URLs with url.URL not concatenation

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:50 +02:00
Aurélien Sibiril
f3a745c245 Add List*Organizations helpers in pkg/accessreview/drivers → Ignore .oauth-credentials.txt
- Add List*Organizations helpers in pkg/accessreview/drivers
- Replace AccessSource picker switches with map dispatch
- Drop dead per-provider connector settings wrappers
- Ignore .oauth-credentials.txt

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:49 +02:00
Aurélien Sibiril
8917b46541 Move Vercel /v2/user fetch to pkg/connector/vercel.go → Migrate connector settings callers to generic
- Move Vercel /v2/user fetch to pkg/connector/vercel.go
- Authorize NeedsConfiguration and SelectedOrganization
- Add coredata.ConnectorSettings[T] generic helper
- Migrate connector settings callers to generic

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:49 +02:00
Aurélien Sibiril
caec9f1ad5 Rename access-review migration with random time → Validate PagerDuty subdomain on OAuth callback
- Rename access-review migration with random time
- Move PagerDuty token-response handling to its own file
- Strip OAuth error_description from log and redirect
- Validate PagerDuty subdomain on OAuth callback

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:49 +02:00
Aurélien Sibiril
842f9cfbc5 Stop leaking customer email domain in cassette guard → Add PKCE coverage tests for entropy and replay
- Stop leaking customer email domain in cassette guard
- Deep-copy ExtraAuthParams in ApplyProviderDefaults
- Drop raw monday graphql error from returned errors
- Add PKCE coverage tests for entropy and replay

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:49 +02:00
Aurélien Sibiril
7504099507 Strip email local-part from cassette guard failure → Wire 13 access-review connectors in Helm chart
- Strip email local-part from cassette guard failure
- Drop dead src/components/connectors vite include
- Cover all 13 access-review providers in builder test
- Wire 13 access-review connectors in Helm chart

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:48 +02:00
Aurélien Sibiril
8f6ecd9f81 Wire post-OAuth pickers and 2-auto callback handling → Track e2e gap for new access-review connectors
- Wire post-OAuth pickers and 2-auto callback handling
- Add 13 vendor logo components for new connectors
- Wire access-review connectors into bootstrap config
- Track e2e gap for new access-review connectors

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:48 +02:00
Aurélien Sibiril
1532e94eb1 Add 13 access-review driver implementations → Dispatch new providers in review engine and name worker
- Add 13 access-review driver implementations
- Add VCR-driven driver tests with synthetic cassettes
- Guard cassettes against non-synthetic email leaks
- Dispatch new providers in review engine and name worker

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:48 +02:00
Aurélien Sibiril
0147acd9f0 Add PKCE, token-body extras, AuthURL templating to OAuth2 → Add settings structs for Pattern-2 connector providers
- Add PKCE, token-body extras, AuthURL templating to OAuth2
- Add 13 connector provider enum values
- Add scopes, display names, name resolvers for 13 providers
- Add settings structs for Pattern-2 connector providers

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:48 +02:00
Sacha Al Himdani
3ff66757ad Remove deprecated snapshot system
The register/document model has fully replaced the snapshot system.
Delete every snapshot-scoped row and strip the application code that
referenced them: SnapshotID/SourceID struct fields, snapshot_id IS NULL
filters, snapshot columns from SELECT/INSERT statements and named args,
and the eight migrate-*-snapshots-to-documents one-shot tools.

The remaining snapshot_id / source_id columns, the snapshots and
controls_snapshots tables, the snapshots_type enum, and the
snapshot-scoped indexes are now unused; they are dropped in a follow-up
schema migration so this change can roll back cleanly without leaving
orphaned data.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-15 23:26:02 +02:00
Sacha Al Himdani
eecbe4c46c Rename vendors to third parties
Renames the user-facing 'vendor' concept to 'third party' across the
entire codebase. The shared common_third_parties reference table is
unchanged.

Migration. Renames the vendor_category enum, the vendors and
vendor_<entity> tables (contacts, services, compliance_reports,
business_associate_agreements, data_privacy_agreements,
risk_assessments) and their vendor_id columns, the asset_vendors /
data_vendors / processing_activity_vendors junction tables,
generated_documents.vendors_document_id, the webhook_event_type
'vendor:<verb>' values, and the snapshots_type 'VENDORS' value.

Backend. Renames coredata models and SQL queries, probo services,
GraphQL / MCP API surface, console / trust / webhook resolvers and
types, the CLI (prb vendor* -> prb third-party*; pkg/cmd/vendormgmt
-> pkg/cmd/thirdpartymgmt), the document generator, vetting agent
prompts, and the common-third-parties-import command.

Frontend, packages, n8n, e2e. Renames apps/console pages, components,
hooks, routes, dialogs, and tabs; the shared @probo/vendors package
(now @probo/third-parties); the @probo/ui Vendors atoms (now
ThirdParties, VendorLogo -> ThirdPartyLogo); the n8n community node
actions/vendor folder (now actions/thirdParty); and the e2e Go test
suite (console and MCP). Filesystem and URL paths use kebab-case
(third-parties), GraphQL fields and TypeScript identifiers use
camelCase (thirdParty / thirdParties), Go types use PascalCase
(ThirdParty), and human-facing text uses 'third party' with a space.

Co-authored-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-13 21:21:39 +02:00
Sacha Al Himdani
9eed0d71c8 Log identity_id on every authenticated request
Add a single info log line in each authn middleware once an identity is
resolved, so every authenticated request emits a record that ties the
request back to its user and credential:

- Cookie session middleware logs "session authenticated" with
  identity_id and session_id.
- API key middleware logs "api key authenticated" with identity_id and
  api_key_id.
- OAuth2 access token middleware logs "access token authenticated"
  with identity_id and access_token_id.

The credential IDs are row identifiers (GIDs), not the secret token
values, so they're safe to log and let operators correlate a request
back to the specific credential used. The log lines use the
request-scoped logger from httpserver.LoggerFromContext so they
inherit http_request_id and any other middleware-attached attributes.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-13 15:49:52 +02:00
Cursor Agent
dec767c91d Drop legacy cookies and cookie_patterns tables
These tables were superseded by tracker_patterns and
detected_trackers in migration 20260505T090000Z, which
backfilled all data. The old tables are no longer referenced
by any Go code, GraphQL schema, MCP specification, or CLI
command.

The cookie_source and cookie_pattern_match_type enum types
are retained because tracker_patterns still uses them.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Émile Ré <nemile.re@gmail.com>
2026-05-13 14:41:23 +04:00
Émile Ré
0606416b39 Add SDK version to cookie banner logs via middleware
Extract X-SDK-Version from request headers in a dedicated
middleware and store it in context. All ErrorCtx calls in the
cookie banner handler now include the sdk_version field.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-13 12:49:13 +04:00
Émile Ré
e739473bcd Derive consent mode from geolocation, not banner config
The consent mode is now determined dynamically by the visitor's
country and its applicable regulation. The configured consent_mode
column is dropped from cookie_banners and added to
cookie_consent_records to persist the geo-derived mode at
consent-recording time. When no regulation matches, the default
is OPT_OUT.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-13 12:49:13 +04:00
Émile Ré
6c6137f9f2 Fix deadlock when updating tracker pattern last_matched_at
Replace per-row UPDATE inside the detected-tracker loop with a single
bulk UPDATE ... WHERE id = ANY(...) after the loop. The old approach
locked pattern rows in request-dependent order, causing deadlocks
under concurrent ReportDetectedTrackers calls.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-13 12:49:12 +04:00
Émile Ré
d4c8137933 Prevent bare star tracker patterns
When a cookie name has no separator and looks variable (e.g. a long
hex string), heuristicTemplate returned "*" which created a catch-all
glob pattern matching every tracker of the same type and duration
bucket. Skip these separator-less names entirely so they remain as
individual exact-match patterns for human triage.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-13 12:49:12 +04:00
Sacha Al Himdani
a67f2433b1 Address code review findings in relay fetch and iam
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-12 18:42:54 +02:00
Sacha Al Himdani
fc24306cd8 Address code review findings across relay, UI, and Go backend
- relay: key uploadables map by actual variable name instead of iteration
  index so order-mismatch between Object.keys passes can't desync the
  multipart map from form field names
- mcp/v1: drop dead commented middleware line
- DurationPicker: tighten parse regex to require PT prefix for M/H and P
  for D/W, and reject NaN in stringify so cleared inputs don't produce
  invalid duration strings

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-12 18:07:34 +02:00
Émile Ré
d40e9a157b Handle membership not found
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 18:25:44 +04:00
Émile Ré
7669112639 Rename migrations and merge some
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:38 +04:00
Émile Ré
017b829114 Fix lint
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:38 +04:00
Émile Ré
10ac52eff3 Fix PR review feedback
- Preserve SSRF protection by wrapping the existing transport
  instead of replacing it with a bare http.Transport
- Strip DSN from url.Parse error to avoid leaking credentials
- Gate CommonThirdPartyCombobox on search length to prevent
  showing stale results when input is shortened
- Handle multi-value and uppercase sizes attributes in
  parseSizeAttr for correct icon-size ranking
- Match rel tokens containing "icon" (e.g. "shortcut icon")
  instead of requiring an exact match
- Limit HTML response body to 10 MiB before parsing
- Reject sslmode=prefer explicitly in both import tools

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:37 +04:00
Émile Ré
44072b158a Rename migrations
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:37 +04:00
Émile Ré
bf8c622bcd Extract webinspect package for logo discovery
Replace the Google Favicons API with HTML head tag parsing
to find higher-quality logos (SVG, apple-touch-icon, large
PNG icons, msapplication-TileImage). The new pkg/webinspect
package parses a website's DOM tree and is extensible for
future resource extraction (footer links, etc.).

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:36 +04:00
Émile Ré
684fadea3e Remove unused description column from common_third_parties
The description field was never surfaced in the UI and added no value.
Drop it from the database, Go structs, GraphQL schema, import tool,
frontend fragment, and vendor seed data.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:36 +04:00
Émile Ré
4a405ce16c Self-host common third party logos via S3
Fetch favicons at import time instead of calling Google's favicon
service per page load. Logos are stored as public files in S3 and
served through the existing /api/files/v1/{id} endpoint.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:36 +04:00
Émile Ré
7099a3d702 Replace vendor JSON with common third parties API
The CreateVendorDialog previously loaded the entire @probo/vendors
JSON bundle client-side and used MiniSearch for fuzzy search. This
replaces it with a GraphQL query against the common_third_parties
database table, searched server-side via ILIKE filtering.

Backend: adds CommonThirdParty GraphQL type, a pkg/thirdparty
service, and a commonThirdParties(name) root query. Frontend:
splits into CommonThirdPartyCombobox (display) and an @inline
fragment read on selection via readInlineData.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:36 +04:00
Émile Ré
361fe1d713 Add common_third_parties shared reference table
Introduce a globally-shared, non-tenant-scoped common_third_parties
table that mirrors the public subset of vendor metadata, plus a
one-shot cmd/common-third-parties-import CLI that seeds it from
packages/vendors/data.json. The catalog will back future flows (e.g.
vendor autocomplete) so each tenant no longer needs to duplicate the
same baseline data.

The importer is idempotent via ON CONFLICT (lower(name)) DO UPDATE
and prints inserted/updated counts. GIDs use gid.NilTenant since the
table is not tenant-scoped; uniqueness still comes from the entity
type plus 14 bytes of timestamp/random suffix.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:35 +04:00
Sacha Al Himdani
d82df6b8ee Sanitize MCP errors to avoid leaking internal details
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-12 13:37:51 +02:00
Émile Ré
150f5d9c46 Fix wrong entity types in tracker_patterns and detected_trackers GIDs
tracker_patterns rows were created with entity type 88 (removed
CookiePatternEntityType) instead of 89 (TrackerPatternEntityType), and
detected_trackers rows migrated from the cookies table carried entity
type 85 (removed CookieEntityType) instead of 90 (DetectedTrackerEntityType).

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 12:28:18 +04:00
Sacha Al Himdani
d88ae3288b Add pg pool tuning options from kit v0.10.0
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-12 10:04:13 +02:00
Émile Ré
ecb9bd747e Fix empty country code stored in consent records
When IP geolocation returned no matching CIDR block, LookupCountryByIP
returned an empty string with nil error. The handler took the address of
that empty string, producing a non-nil pointer to "", which was inserted
into the database. Guard against this by returning nil when the resolved
country code is empty, and backfill existing rows with a migration.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 20:04:54 +04:00
Émile Ré
8a1774f91c Fix go-lint
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 18:08:55 +04:00