Commit Graph

547 Commits

Author SHA1 Message Date
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
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
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
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
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
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
É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é
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é
71a33e412b Add tracker type filter and color-coded badges
The trackers page now lets users filter by tracker type
(Cookie, localStorage, sessionStorage, IndexedDB, Cache
Storage) in addition to the existing source filter. Each
tracker type and cookie source badge uses a distinct color
for quick visual scanning.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 15:34:24 +04:00
Émile Ré
c8f130ed45 cookiebanner: address PR review feedback
- Detectors: keep batched entries in `pending` until the POST succeeds
  and guard against concurrent flushes, so transient network errors no
  longer silently drop detection reports.
- Worker: add stable tie-breakers to the merge-candidate sort so the
  greedy assignment produces deterministic groups across runs.
- Handler: skip resource entries with an empty URL (zero-value `uri.URI`
  when the `url` field is missing) before persisting them.
- Third-party detector: allow same-origin service worker scripts through
  `processResource` -- service workers are always same-origin by spec,
  so the previous filter made `wrapServiceWorker` unreachable.
- Resource row edit: bump the description cell `colSpan` to 3 so the
  edit row spans all five table columns.
- Resolver: handle `ErrSameResourceCategoryMove` explicitly so the no-op
  move returns a validation error instead of an internal one.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 14:52:56 +04:00
Émile Ré
caac9c76db cookiebanner: detect service workers and Cache Storage buckets
A registered service worker is a URL-shaped artifact (origin+path of
the worker script), so it goes in tracker_resources as a new
SERVICE_WORKER resource type. A Cache Storage bucket is an opaque
named string with no URL, so it goes in detected_trackers as a new
CACHE_STORAGE tracker type.

Frontend:
  - StorageDetector wraps caches.open() and enumerates caches.keys()
    on start to surface pre-existing buckets that pre-date the SDK
    load (service workers commonly populate caches eagerly on
    install).
  - ThirdPartyDetector wraps navigator.serviceWorker.register() and
    enumerates getRegistrations() on start.

Both wrappers degrade silently on insecure contexts where these APIs
are unavailable.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 14:52:55 +04:00
Émile Ré
2b3449de1a cookiebanner: broaden resource detection via PerformanceObserver
ThirdPartyDetector previously only saw <script src> and <iframe src>
because it scanned the DOM and watched mutations. Add a single
PerformanceObserver({type:'resource', buffered:true}) that picks up
everything the browser actually loaded:

  - tracking pixels (<img>, <picture>, srcset)
  - cross-origin stylesheets and web fonts
  - fetch / XHR / sendBeacon / ping calls (SDK call-homes)
  - video, audio, embed, object media

initiatorType is mapped to six new tracker_resource_type enum values
(IMAGE, STYLESHEET, FONT, BEACON, FETCH, MEDIA) and the existing
upsert path in tracker_resources picks them up unchanged.

Closes a real gap with headless cookie scanners: most SDKs phone home
via beacons after their script is gone, and the DOM scan never saw it.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 14:52:55 +04:00
Émile Ré
663dc7478f graphql: add TrackerResource schema, resolvers, and IAM actions
Add the full GraphQL surface for the new tracker_resources table:

- TrackerResourceType enum (SCRIPT, IFRAME), TrackerResource node type
  with connection/edge/order/filter, fields on CookieBanner
  (uncategorisedTrackerResources) and CookieCategory (trackerResources).
- Mutations: createTrackerResource, updateTrackerResource,
  deleteTrackerResource, moveTrackerResourceToCategory with
  inputs and payloads.
- Resolvers for all mutations, connection fields, field resolvers
  (cookieCategory, permission), and totalCount.
- IAM actions: core:tracker-resource:{get,list,create,update,delete}.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 14:52:54 +04:00
Émile Ré
93407f6431 coredata: split SCRIPT/IFRAME into tracker_resources table
Move resource tracking (scripts, iframes) out of the pattern-based
tracker_patterns/detected_trackers machinery into its own
tracker_resources table keyed by (banner, type, origin, path).

- Add migration that creates the tracker_resource_type enum, the
  tracker_resources table with a unique index, drops existing
  SCRIPT/IFRAME rows (not yet in production), and recreates the
  tracker_type enum without those values.
- Add TrackerResource coredata model with full CRUD, Upsert (bumps
  last_detected_at on conflict), list/count/move operations, filter,
  and order field support.
- Register TrackerResourceEntityType (91) in the entity type registry.
- Drop TrackerTypeScript/TrackerTypeIframe from TrackerType enum.
- Update handler to use TrackerResourceType for resource detection.
- Temporarily stub out resource ingestion in ReportDetectedTrackers
  pending the service-layer wiring in the next commit.
- Drop SCRIPT/IFRAME from the GraphQL TrackerType enum.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 14:52:53 +04:00
Émile Ré
0358aafb62 Update API surface to use GLOB match type instead of PREFIX
Replace PREFIX with GLOB in GraphQL enum, MCP specification, CLI
interactive prompts, and n8n node options.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 14:52:52 +04:00
Émile Ré
31bfbefc45 Make tracker pattern displayName read-only
The displayName field was always predictable from pattern + matchType
and allowing edits added unnecessary complexity. Remove displayName
from UpdateTrackerPatternInput across all surfaces (GraphQL, MCP, CLI,
n8n) and make the frontend show it as non-editable text.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 14:52:52 +04:00
Émile Ré
5f4fd3c427 Surface regulation and user agent across consent record API layers
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-07 15:13:48 +04:00
Émile Ré
806bd672ed Surface regulation and country code enums across API layers
Add proper enum types for Regulation and CountryCode in GraphQL
(with @goModel/@goEnum directives) and MCP (as standalone reusable
schemas with $ref). Update CLI, console UI, and n8n to include
the new fields.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-07 15:13:48 +04:00
Émile Ré
4598506076 Extract shared types and add Regulation type with parsing methods
Move cookie banner types (CookieItem, Category, Regulation, BannerConfig,
etc.) into a dedicated types.ts file. Add a coredata.Regulation type with
parsing, JSON marshaling, and database scanning methods. Hardcode the
geoloc-import data directory since the submodule path is fixed.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-07 15:13:42 +04:00
Bryan Frimin
6708cc901c Drop FAILED status from access review campaigns
Source fetch failures stay surfaced on the source fetch (status and
last error) instead of failing the entire campaign, so reviewers can
proceed on the sources that succeeded.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-05-07 12:59:55 +02:00
Sacha Al Himdani
8bdab65963 Allow editing metadata of generated document versions
Title, document type, and classification on generated documents could
not be changed: any version-tracked field on a GENERATED write-mode
document was rejected with ErrDocumentVersionGenerated. The error now
fires only when content is being changed, so manual metadata edits
flow through the same draft-on-edit path as authored documents and
produce a draft version that the user can review and publish.

The CLI document update --document-type enum gains
STATEMENT_OF_APPLICABILITY (which generated SoA documents already
use), and the GraphQL resolver maps the content-edit rejection to a
Conflict instead of falling through to a generic Internal error.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-07 11:54:49 +02:00
Bryan Frimin
5e55c888c4 Add Microsoft 365 SCIM bridge and access review driver
Microsoft 365's native SCIM endpoint is unreliable, so mirror the
Google Workspace bridge over Microsoft Graph: a new MICROSOFT_365
OAuth2 connector, a SCIM bridge provider listing /v1.0/users with
$select pagination, and an access review driver that derives admin
status from /directoryRoles members. Refactor the bridge runner to
share OAuth2 plumbing across providers and surface the new bridge
type, scopes, UI card, and bootstrap env wiring.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-05-06 15:41:30 +02:00
Sacha Al Himdani
1434d8336c Allow publishing generated documents as minor versions
Generated documents (asset list, risk register, SoA, ...) previously
only ever produced a new major version. Every regeneration of an
auto-built register consumed a major number, even when the change was
trivial. They now accept a minor flag and publish as
currentMajor.currentMinor+1 when set, bypassing the approval flow.

To carry the flag through cleanly, the document publish API was
refactored. The three split mutations (publishMajor, publishMinor,
requestDocumentVersionApproval) and the two bulk variants collapse
into a single publishDocument / bulkPublishDocuments, both taking the
new minor: Boolean! and a now-required changelog: String!. The same
shape flows through the CLI ("prb document publish --minor"), the MCP
tool, the n8n operations, and the Relay dialogs, where each
generated-doc dialog gains a "Publish as minor" button. Publishing
minor without an existing major is rejected with
ErrCannotPublishMinorWithoutMajor.

This is a deliberate breaking change for callers of the prior
mutations.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-06 14:02:59 +02:00
Émile Ré
9de6af936d Fix tracker pattern review issues
- Fix TotalCount resolver to dispatch by parent type instead
  of always using the uncategorised banner counter
- Sync MCP tracker_type enum with canonical TrackerType values
- Add validation for UpdateTrackerPatternRequest
- Validate tracker_type on CreateTrackerPatternRequest
- Set LastMatchedAt when creating pattern from detection
- Use COALESCE for SOURCE cursor pagination with NULLs
- Make source nullable in CLI tracker-pattern list

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-06 12:26:12 +04:00
Émile Ré
af6e420f54 Remove cookie_patterns legacy, migrate to tracker_patterns
Delete coredata.CookiePattern and all associated CRUD methods,
rename shared types (CookiePatternOrderField, CookiePatternFilter,
CookiePatternMatchType) to TrackerPattern equivalents, and migrate
all API surfaces (GraphQL, MCP, CLI, n8n) to tracker_pattern naming.

The worker was already migrated in the base branch; this commit
completes the removal by dropping the old GraphQL schema/resolvers,
service methods, CLI commands, and n8n operations that operated on
the legacy cookie_patterns table.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-06 12:26:12 +04:00
Émile Ré
21f92352d5 Migrate detection page to TrackerPattern GraphQL types
- Add TrackerPattern type, connection, and filter to GraphQL schema
- Add uncategorisedTrackerPatterns field on CookieBanner
- Add updateTrackerPattern, deleteTrackerPattern, moveTrackerPatternToCategory mutations
- Implement all resolvers backed by tracker_patterns table
- Add TrackerPattern service methods (CRUD + list/count)
- Add LoadUncategorisedByCookieBannerID on TrackerPatterns coredata
- Update detection page to use TrackerPattern fragment, queries, and mutations
- CookieCategory resolver uses dataloader (not just struct ID)

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-06 12:26:11 +04:00
Émile Ré
c853d59fe5 Add trackerType to GraphQL schema and detection UI
- Add TrackerType enum to GraphQL schema with all 6 values
- Add trackerType field to CookiePattern type (nullable source)
- Add optional trackerType to CreateCookiePatternInput
- Add Type column to detection page table
- Add NewTrackerPattern helper in types package
- Regenerate gqlgen + Relay artifacts

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-06 12:26:11 +04:00
Sacha Al Himdani
88242eed87 Restore MCP cross-origin protection after go-sdk v1.6.0 bump
The go-sdk v1.6.0 release no longer applies a default
CrossOriginProtection when the field is nil in StreamableHTTPOptions,
silently removing Origin header verification. Wrap the streamable
handler with http.NewCrossOriginProtection().Handler(...) (the
recommended replacement, since the SDK field is deprecated).

Also regenerate gqlgen resolvers to track v0.17.90.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-05 14:46:04 +02:00
Émile Ré
c26b9c0abe Rename categories to consentCategories
Exclude the UNCATEGORISED category at the SQL level so
the admin cookie/display/translations pages only see
consent-relevant categories. Removes dead client-side
UNCATEGORISED filters that are no longer needed.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-05 11:06:54 +04:00
Émile Ré
bb442bb86d Add uncategorised patterns GraphQL endpoint
Backend for the cookie banner detection page: a new
uncategorisedPatterns connection on CookieBanner with
sortable (NAME, LAST_MATCHED_AT, UPDATED_AT, SOURCE)
and filterable (text ILIKE on name/description, source
enum) paginated results. COALESCE handles NULL-first
ordering for last_matched_at.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-05 11:06:54 +04:00
Émile Ré
54655c218b Surface last_matched_at on all API surfaces
Add lastMatchedAt to the CookiePattern GraphQL type, MCP schema,
CLI view/list commands, and n8n get/getAll operations. Run
codegen to regenerate gqlgen models and MCP types.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-05 11:06:53 +04:00
Sacha Al Himdani
553901e4ad Add risk publish to document system
Replace the old snapshot-based system for risks with the publish
document system, mirroring the prior vendor / processing activity / DPIA
/ TIA migration. Includes the GraphQL mutation, MCP tool, CLI command,
n8n operation, frontend publish dialog, e2e tests, and a prosemirror
register template covering name, description, category, treatment,
owner, inherent and residual scoring, and notes.

The risk register lives as a generated DocumentTypeRegister document on
the organization, reused across publishes (the major version bumps on
every republish). Approvers can be passed in to create a draft pending
approval; otherwise the version is published immediately. The frontend
Risks page exposes a Publish button and a Document link button when the
document exists, and pre-fills the previous default approvers.

Risks was the last remaining snapshot type, so this commit also removes
the entire snapshot system: drop snapshotId from the Risk GraphQL type
and RiskFilter; remove RiskSnapshotter, Risks.Snapshot,
InsertRiskSnapshots, and the SnapshotID/SourceID fields on Risk; delete
Snapshot, ControlSnapshot, SnapshotsType, SnapshotOrderField,
Snapshottable, the SnapshotService, the Snapshot console resolvers and
GraphQL schema, the Snapshot MCP types and operations
(list/get/take/listControlSnapshots), the snapshot CLI (prb snapshot),
the snapshot frontend pages, routes, banner, LinkedSnapshotsCard,
SnapshotGraph, snapshot helpers, and the snapshot n8n resource and
control link/unlink snapshot operations. The snapshot_id columns remain
in the database but are now filtered out with snapshot_id IS NULL.

Add Get/Upsert/Clear GeneratedDocumentID methods on Risk backed by a new
risks_document_id column on generated_documents, matching the
ProcessingActivity/Finding/Vendor pattern. The migration command
migrate-risk-snapshots-to-documents uses raw SQL queries instead of the
Go snapshot types, since those are gone.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-04 14:13:42 +02:00
Émile Ré
3ed61c6084 Add excluded field to cookie pattern GraphQL schema
Expose excluded on the CookiePattern type and accept it as
an optional input on UpdateCookiePatternInput so the console
can toggle pattern exclusion inline.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-01 16:39:33 +04:00
Émile Ré
5cdaddf8b1 Store cookie durations as max_age_seconds
Replace the free-form duration TEXT column with a nullable
max_age_seconds INTEGER on both cookies and cookie_patterns
tables. The SDK detector now sends raw seconds instead of
humanized strings, eliminating locale-dependent comparisons
in the pattern merge worker. Humanization happens at display
time in the widget and console UI.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 11:46:11 +04:00
Émile Ré
94ccc71357 Switch console cookies page to cookie patterns
The console now manages CookiePattern entities instead of raw
Cookie rows. The frontend queries cookiePatterns on each category
and uses createCookiePattern, updateCookiePattern,
deleteCookiePattern, and moveCookiePatternToCategory mutations.

The entire Cookie GraphQL surface (type, connection, mutations,
inputs, payloads, resolvers, Go types) is removed since the
backing struct already lost description and cookieCategoryID.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 11:46:11 +04:00
Émile Ré
9c402058ec Add GraphQL API and service CRUD for cookie patterns
Add CookiePattern type, connection, and mutations to the GraphQL schema
with full resolver implementations. Add service methods for pattern
CRUD, category movement, listing, and counting. This enables the console
to manage cookie patterns instead of individual cookies.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 11:46:10 +04:00
Émile Ré
f9fec45eb1 Add cookie pattern entity to group detected cookies
Introduce a cookie_patterns table that groups cookies sharing a common
prefix (e.g. phc_*) into a single manageable row. Every cookie now
belongs to a pattern (EXACT or PREFIX match type). Category, description,
and display metadata move from cookies to patterns, making patterns the
unit of management and display in the console and published snapshots.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 11:46:10 +04:00
Émile Ré
48606f34c1 Filter browser-extension cookies from detection
Cookies set by browser extensions are not the website operator's
compliance responsibility. This adds stack-trace inspection to
filter out extension-originated document.cookie writes, and
annotates pre-existing cookies with a source field so operators
can triage them separately.

Introduces a CookieSource enum (SCRIPT / PRE_EXISTING) across
the full stack: PostgreSQL, coredata, service, HTTP handler, and
GraphQL schema. On conflict, source is upgraded from PRE_EXISTING
to SCRIPT when a page script is later observed setting the cookie.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 11:46:10 +04:00
Sacha Al Himdani
c026f67bd9 Add vendor publish to document system
Replace the old snapshot-based system for vendors with the publish
document system, mirroring the prior processing activity / DPIA / TIA
migration. Includes the GraphQL mutation, MCP tool, CLI command, n8n
operation, frontend publish dialog, e2e tests, and a prosemirror
register template covering vendor profile fields plus per-vendor
sections for services, contacts, risk assessments, compliance reports,
BAA and DPA agreements.

The vendor register lives as a generated DocumentTypeRegister document
on the organization, reused across publishes (the major version bumps
on every republish). Approvers can be passed in to create a draft
pending approval; otherwise the version is published immediately. The
frontend Vendors page exposes a Publish button and a Document link
button when the document exists, and pre-fills the previous default
approvers.

Remove snapshot mode entirely from vendors and their sub-entities: drop
snapshotId/sourceId from GraphQL Vendor type and VendorFilter; remove
SnapshotsTypeVendors from the snapshot registry and delete
Vendors.Snapshot, VendorSnapshotter interface and all
*.InsertVendorSnapshots methods on contacts, services, risk
assessments, compliance reports, BAA and DPA. Drop the snapshot routes
and banner from the frontend. The snapshot_id columns remain in the
database but are now filtered out with snapshot_id IS NULL.

Add Get/Upsert/Clear GeneratedDocumentID methods on Vendor backed by a
new vendors_document_id column on generated_documents, matching the
ProcessingActivity/Finding/Obligation pattern.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-29 16:24:29 +02:00
Sacha Al Himdani
ba8bce2ad3 Add processing activity, DPIA and TIA publish to document system
Replace the old PDF/snapshot-based exports for processing activities,
Data Protection Impact Assessments and Transfer Impact Assessments with
the publish document system. Includes GraphQL mutations, MCP tools, CLI
commands, n8n operations, frontend publish dialogs, e2e tests, and
prosemirror register templates that mirror the previous PDF layouts.

Each register lives as a generated DocumentTypeRegister document on the
organization, reused across publishes (the major version bumps on every
republish). Approvers can be passed in to create a draft pending
approval; otherwise the version is published immediately. The frontend
ProcessingActivities page exposes a Publish dropdown per register and a
Document link button per active tab, pre-fills the previous default
approvers, and navigates to the published document on success.

Remove snapshot mode entirely from these three entities: drop snapshotId
and sourceId from GraphQL schemas, types, filters, resolvers, MCP spec,
frontend routes and pages; remove SnapshotsTypeProcessingActivities from
the snapshot registry and delete the ProcessingActivities.Snapshot,
ProcessingActivitySnapshotter interface and *.InsertProcessingActivitySnapshots
methods. The snapshot_id columns remain in the database but are now
filtered out with snapshot_id IS NULL.

Add Get/Upsert/Clear GeneratedDocumentID methods on each entity type
(ProcessingActivity, DataProtectionImpactAssessment,
TransferImpactAssessment) backed by new columns in the generated_documents
table, matching the Finding/Obligation pattern.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-28 18:07:46 +02:00
Émile Ré
b9835f0f25 Add cookie banner and category dataloaders
Batch-load CookieBanner and CookieCategory entities via
dataloadgen instead of making individual service calls in
GraphQL resolvers, matching the existing dataloader pattern
used for organizations, frameworks, etc.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-28 15:28:18 +04:00
Émile Ré
d9b0d5f44d Remove useless nil guards
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-28 15:28:18 +04:00
Émile Ré
23cf2caeba Add missing authorize calls in cookie banner resolvers
Resolvers for CookieCategory, Organization, CookieBanner,
Translations, and CookieBannerVersion.Categories were either
missing authorization checks or returning ID-only stubs
without querying the database. This fixes both issues by
adding proper authorize calls and fetching full entities.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-28 15:28:17 +04:00
Émile Ré
9b83e319a0 Add consent record detail page
Display record attributes and parsed consent data with
per-category consent state and cookies from the banner
version snapshot. The page lives outside the config layout
with its own breadcrumb navigation.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-28 15:28:17 +04:00
Émile Ré
84632fe795 Filter consent records by version number
Replace the opaque cookieBannerVersionId filter with an
integer version filter. The SQL filter now resolves the
version number via a subquery against cookie_banner_versions.

Also fix the CookieBannerVersion resolver on consent records
to load the full version from the database instead of
returning a stub with only the ID set (which caused the
version to always display as 0).

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-28 15:28:17 +04:00