Commit Graph

503 Commits

Author SHA1 Message Date
Émile Ré
54494fc9b1 Bump version to 0.1.1
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 17:11:39 +04:00
Émile Ré
42a6a2f8bd Show placeholders when no prior consent exists
The activate() method was only called when consent existed (from
cookie or API). When there was no prior consent, observeAndActivate()
never ran, so visual elements with data-cookie-consent were left
without placeholders. Build default consent data from the config's
consent_mode and always call activate() at the end of load().

Also consolidate activateElements/addPlaceholders into
observeAndActivate to avoid duplicate DOM traversals.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 17:10:35 +04:00
Émile Ré
15ff6131e1 Fix placeholder sizing for cookie-consent elements
Expand the dimensional property allowlist with padding, box-sizing,
and positioning properties (position, top, right, bottom, left,
inset) so placeholders match the size of absolutely or sticky
positioned elements. Fall back to getComputedStyle for height when
no explicit value is found from inline styles or HTML attributes.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 16:59:13 +04:00
Émile Ré
bd6abccb2d Upgrade esbuild to remove vulnerability
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 15:52:43 +04:00
Émile Ré
336ec986d5 Update @probo/cookie-banner public exports and bump to 0.1.0
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 15:14:19 +04:00
Émile Ré
0d257977a1 Refactor cookie banner forms to react-hook-form
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 14:05:45 +04:00
Émile Ré
33abbfbb8f Link detected cookies to existing patterns on conflict
When a cookie pattern already exists for a banner, the insert
conflict caused a continue that silently dropped the detected
cookie instead of linking it to the existing pattern. Load the
existing pattern to obtain its ID and proceed with cookie
insertion.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 11:46:13 +04:00
Émile Ré
427bbbaf5c Move DurationInput to @probo/ui and scope pattern merge by category
Move the DurationInput component from the console app into @probo/ui
for reuse, add duration formatting helpers to @probo/helpers, and
update pattern merge to group by both category ID and prefix.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 11:46:12 +04:00
Émile Ré
2fe77d9ddc Fix review issues in cookie pattern handling
- Fix DurationInput fallback unit from "minutes" to "seconds" and add
  seconds as a selectable unit to prevent silent duration inflation
- Use parseFloat instead of parseInt for duration input to preserve
  fractional values
- Scope prefix merge groups by category ID to prevent cross-category
  merging
- Relink cookies and delete exact patterns even when prefix pattern
  already exists
- Prefer exact matches and longest prefix in pattern selection query
- Fix wrong error type in GetCookiePattern (ErrCookiePatternNotFound)
- Handle singular/plural in humanizeSeconds fallback branch

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-30 11:46:11 +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é
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
Émile Ré
983331e4dd Update avatar initials colors
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-29 11:58:49 +04: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é
c23f9591a3 Fix invalid input hover border
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-28 15:28:18 +04:00
Émile Ré
ff2c7b9cce Fix invalid input
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-28 15:28:17 +04:00
Sacha Al Himdani
bdb16d4abe Add finding and obligation publish to document system
Replace the old snapshot-based approach with the new publish document
system for findings and obligations. Includes GraphQL mutations, MCP
tools, CLI commands, e2e tests, frontend publish dialogs, and
snapshot-to-document migration tools.

Remove snapshot mode entirely from findings and obligations: drop
snapshotId from GraphQL schemas, filters, resolvers, MCP spec, frontend
routes, pages, and helpers. The snapshot_id column remains in the
database but is now filtered out with snapshot_id IS NULL.

Remove auditor's ability to publish SoA.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-28 13:12:58 +02:00
Émile Ré
e473884b31 Fix copy paste in rich editor
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-28 11:17:06 +04:00
Émile Ré
b7a28573f7 Send SDK version as X-SDK-Version header
Move the cookie-banner SDK version from the POST consents
request body to a custom X-SDK-Version header sent on every
API call. The server now reads it from the header and the
CORS middleware allows it through preflight.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-27 16:03:03 +04:00
Émile Ré
abafd817a8 Bump @probo/cookie-banner to 0.0.4
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-27 16:02:06 +04:00
Émile Ré
7309d7fe76 Fix cookie labels color
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-27 16:02:06 +04:00
Émile Ré
e4ae05c133 Update readme
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-27 16:02:06 +04:00
Émile Ré
79c17ad3a0 Update default exports field for main entrypoint and bump to 0.0.3
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-27 16:02:06 +04:00
Émile Ré
181a790061 Fix long cookie names display
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-27 16:02:05 +04:00
Émile Ré
9d0eff6c66 Fix long cookie names display
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-27 16:02:05 +04:00
Émile Ré
d955489d11 Bump @probo/cookie-banner version
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 19:28:48 +04:00
Émile Ré
56a32fe162 Fix intrusive auto-focus on cookie banner initial load
Only focus the banner on user-initiated re-opens (hidden -> banner),
not on the initial page load (loading -> banner). Also use
preventScroll to avoid jarring scroll jumps on programmatic focus.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 18:55:34 +04:00
Émile Ré
d7eec08cd2 Add banner ID to probo_consent cookie
Include a `bid` field in the consent cookie so it explicitly
identifies which cookie banner it belongs to, making validation
direct instead of relying on the visitor ID as an implicit
discriminator. Existing cookies without `bid` self-heal on the
next load by falling through to the API fetch.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 18:48:40 +04:00
Émile Ré
a1d2eebf2b Hide cookie details toggle for categories with no cookies
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 18:48:39 +04:00
Émile Ré
598c6b112c Add cookie_policy_url field to cookie banners
Introduce a required cookie_policy_url alongside the existing
privacy_policy_url (now optional) so banners can link directly to a
dedicated cookie policy — a compliance best practice recommended by
CNIL, ICO, and the EDPB. Existing rows are seeded from their current
privacy_policy_url value.

Both {{cookie_policy_link}} and {{privacy_policy_link}} placeholders
are supported independently in banner description translations.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 18:48:39 +04:00
Émile Ré
4982cebb9c Gracefully handle config fetch failure in cookie banner SDK
When the banner config request fails, the SDK now silently returns
instead of throwing, so the rest of the page is unaffected.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 18:48:39 +04:00
Émile Ré
4ec075fa80 Limit detected cookies to 100 per request in cookie banner SDK
The server rejects requests with more than 100 cookies but the client
had no matching cap, causing the entire batch to be lost on cookie-heavy
pages. Flush now drains at most 100 entries and re-schedules for the
remainder.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 18:48:38 +04:00
Émile Ré
7a270f75ec Fix Google Consent Mode integration for GTM / dataLayer
Fall back to pushing consent commands onto window.dataLayer when
window.gtag is not available, enabling compatibility with Google Tag
Manager setups that don't define a global gtag function.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:13:13 +04:00
Émile Ré
7f1dffad80 Add PostHog consent integration and extract integration plugin system
Add PostHog opt-in/opt-out consent support mirroring the existing Google
Consent Mode integration: database column, GraphQL field, console UI
toggle, and client-side posthog-js calls.

Extract both GCM and PostHog logic from CookieBannerClient into a
ConsentIntegration plugin interface so future integrations can be added
without modifying the client core.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:13:12 +04:00
Émile Ré
c6f548b8ff Add Google Consent Mode v2 to cookie banner SDK
Set GCM defaults to denied on load, then push consent
updates via gtag('consent', 'update', ...) before
activating scripts. The mapping from category slugs to
GCM consent types comes from the banner config endpoint.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:13:12 +04:00
Émile Ré
c364c3eacb Update packages/cookie-banner/src/client.ts
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Signed-off-by: Émile Ré <nemile.re@gmail.com>
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 13:11:22 +04:00
Émile Ré
f29a2f05cc Fix gpc applied from cookie / api consent
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 13:05:02 +04:00
Émile Ré
4f4bb72760 Clear GPC badge when user overrides consent via preference panel
When the user explicitly changes consent (accept all, reject all, or
customize), clear the gpcApplied flag and remove the gpc-label attribute
from the settings button so the "Opt-Out Preference Signal Honored"
badge no longer displays.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:44:44 +04:00
Émile Ré
98dc04b7de Add Global Privacy Control (GPC) support to cookie banner SDK
When navigator.globalPrivacyControl is true and no prior consent exists,
auto-reject all non-necessary cookies with action "GPC", skip showing
the banner, and display an "Opt-Out Preference Signal Honored" badge on
the settings button (CPRA compliance). GPC labels are hardcoded in the
SDK for en/fr/de/es. Users can still override via the preference panel.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:21:40 +04:00
Émile Ré
2b6f131f43 Fix PR review comments on cookie banner i18n
Address locale normalization for region-tagged values, guard
language detection for non-DOM runtimes, validate DefaultLanguage
on update, pass translated texts through the deactivation flow,
handle slug collisions in migration, add organizations FK, fix
consent migration from name-keyed to slug-keyed data, render all
template placeholders in previews, and wrap helper text for i18n.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:12 +04:00
Émile Ré
fa7a9c96c1 Move cookie detail labels from backend to JS SDK
label_description and label_duration are not user-customizable, so they
don't belong in the backend translation defaults. Hardcode them in the
cookie-banner SDK's i18n module instead.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:12 +04:00
Émile Ré
e24813202b Fix XSS in cookie banner translation rendering
Validate translation string values server-side with NoHTML() and
MaxLen(2000) to reject HTML in the translations JSON blob. On the
client side, escape user-provided template text before innerHTML
injection in banner_description and placeholder_text paths.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:11 +04:00
Émile Ré
165b9ad9d3 Add slug to cookie categories for stable consent identifiers
The category slug provides a stable, URL-safe key used as the
data-cookie-consent attribute value and consent data key, replacing
the fragile category name. This prevents breakage when categories
are renamed.

- Add slug column with unique-per-banner constraint and backfill migration
- Add Slug validator (lowercase alphanumeric + hyphens)
- Propagate slug through GraphQL schema, service layer, and snapshot
- Update console UI with slug field in create/edit forms
- Switch cookie-banner widget to use slug as consent data keys

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:10 +04:00
Émile Ré
bb39daebc5 Move duration translations from server defaults to JS SDK
Duration strings are static and not customizable through the console,
so they belong in the frontend cookie-banner package instead.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:10 +04:00
Émile Ré
f9458fb18a Remove unused available_languages from cookie banner config
The field was populated by the backend and declared in the TS interface
but never consumed by any client-side code. The banner resolves its
language via detectLanguage() and passes it as a query param.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:09 +04:00
Émile Ré
ef60f080f1 Add i18n support to cookie banner JS client
Replace all hardcoded user-facing strings with server-driven
texts from config.texts. Add language detection chain
(data-lang > html lang > navigator.language), pass ?lang
query param on config fetch, and use {{variable}} interpolation
for dynamic content in templates.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:09 +04:00
Émile Ré
4678c58ab0 Add description to cookie banner preference panel
Adds a short description under the preference panel title:
"Choose which cookie categories to allow. Necessary cookies are
always active as they are needed for the site to work."

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:08 +04:00
Émile Ré
d5d77fee8a Stop existing detector before creating a new one in startDetector()
Prevents orphaned detector state when load() is called multiple times.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-23 10:50:57 +04:00
Émile Ré
137b63a47e Add cookie detector to JS SDK for automatic cookie discovery
Overrides document.cookie setter to intercept cookie writes and detect
unknown cookies not present in the banner config. Also scans pre-existing
cookies on startup. Detected cookies are debounced and reported in batches
to the detected-cookies endpoint with inferred durations from max-age/expires.

Extracts shared cookie helpers (parseCookieName, parseDuration, isDeletion,
removeCookies) into cookie-utils.ts, used by both activation.ts and
detector.ts. Unifies the duplicated "probo_consent" constant into a single
export from cookie.ts.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-23 10:50:57 +04:00
Sacha Al Himdani
7be92defcc Add missing resources to CLI, MCP, and n8n surfaces
Audit all three API surfaces against the console GraphQL schema and add
missing resources: asset, audit, datum, dpia, evidence upload, measure,
obligation, processing activity, rights request, snapshot, task, tia,
trust center (with references/files), and vendor management CLI
commands; MCP tools for deletes, rights requests, trust center, vendor
contacts/services, and compliance external URLs; n8n nodes for
obligation, finding, task, evidence, processing activity, dpia, tia,
rights request, snapshot, audit log, access review, organization
context, trust center, and additional control/measure/vendor operations.

Include MCP e2e test infrastructure (testutil MCP client with API key
auth and JSON-RPC session management) and tests covering all new MCP
tools.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-22 19:02:22 +02:00