Commit Graph

3757 Commits

Author SHA1 Message Date
É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é
11f856740a Make cookie banner origin immutable after creation
Origin is a fundamental identity property of a banner tied to consent
records for a specific site. Changing it would break the audit trail
and violate GDPR consent specificity requirements.

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
Bryan Frimin
de1a33dc36 Fix ts type error
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-24 16:33:47 +02:00
Bryan Frimin
f82d76b246 Add safe URL construction rules to agent guides
Add a URL and query parameter construction section to
contrib/claude/go-style.md requiring net/url (url.JoinPath,
url.Values, url.Parse) instead of fmt.Sprintf or string
concatenation.

Create contrib/claude/ts-style.md with matching TypeScript
rules requiring URL and URLSearchParams instead of template
literals or string concatenation.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-24 16:12:27 +02:00
Bryan Frimin
1cc9f011f4 Fix import order and floating promise lint errors
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-24 16:10:47 +02:00
Bryan Frimin
9afc2eaaa7 Track copied config ID per row instead of globally
The useCopy hook returns a single boolean, so copying one
row's configuration ID would flip every row to "Copied!".
Track the specific copied ID in state so only the clicked
row shows feedback.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-24 16:10:46 +02:00
Bryan Frimin
9e1111d576 Show SAML configuration ID in SSO settings
Users need the configuration ID to set up the Start URL in
their identity provider (e.g. Google Workspace) but it was
not visible anywhere in the UI. Add a Configuration ID column
to the SAML configuration list with click-to-copy support.

Closes #1070

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-24 16:10:46 +02:00
Bryan Frimin
5bd31bd68f Add Google Workspace connector to bootstrap
The SCIM bridge for Google Workspace already exists but the
bootstrap builder did not register it, preventing deployment
via environment variables.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-24 16:06:35 +02:00
Bryan Frimin
da9ba64b07 Persist cleared provisioning error before HTTP challenge
When DNS and CAA checks pass, ProvisioningError is set to nil but
was only persisted later alongside the challenge data. If
GetHTTPChallenge then failed, the update was never reached,
leaving stale DNS/CAA error messages visible to the user.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-24 16:05:11 +02:00
Bryan Frimin
976acbd114 Surface domain provisioning errors to users
When DNS verification, CAA checks, or HTTP challenge completion
fail during certificate provisioning, the error is now stored on
the custom domain record and exposed via GraphQL. The console
displays it in both the domain card and domain detail dialog so
users can diagnose configuration issues without checking logs.

Previously these failures returned an error that was only logged
server-side, leaving users with no visibility into why their
domain was stuck in a pending state.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-24 16:05:11 +02:00
Émile Ré
e48da4dc99 Format file
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:16:04 +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é
9fbb716b00 Constrain PostHog consent to one normal category per banner
Add a partial unique index ensuring only one category per banner can
have posthog_consent enabled. Default it to the analytics category on
banner creation, clear the previous mapping before setting a new one,
and restrict the toggle to NORMAL categories in both the service layer
and the console UI.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:13:12 +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é
076e0129f6 Add GCM consent type mapping to console UI
Display Google Consent Mode mappings as badges on each
category and add a checkbox selector in the edit form
so users can configure which GCM signals each category
controls.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:13:12 +04:00
Émile Ré
4436059483 Add gcmConsentTypes to GraphQL schema and resolvers
Expose gcmConsentTypes on CookieCategory type and accept
it in UpdateCookieCategoryInput so the console can read
and write GCM consent type mappings per category.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:13:11 +04:00
Émile Ré
60705af3a2 Add default GCM consent type mappings
Seed default categories with their Google Consent Mode v2
mappings (e.g. analytics -> analytics_storage, advertising
-> ad_storage + ad_user_data + ad_personalization). New
user-created categories default to an empty mapping.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:13:11 +04:00
Émile Ré
5112233925 Add GCM consent types to version snapshot
Include gcm_consent_types in the published banner config
so the cookie banner SDK can read category-to-GCM mappings
from the config endpoint.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:13:11 +04:00
Émile Ré
2b15a1684c Add gcm_consent_types column to cookie_categories
Stores the Google Consent Mode v2 consent type mapping
per cookie category so each category can declare which
GCM signals it controls (e.g. analytics_storage,
ad_storage).

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 17:13:11 +04:00
Sacha Al Himdani
ab5654f6e5 Fix errcheck and ineffassign lint errors
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-24 14:24:48 +02: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é
0b7855243a Remove unused deleteCookieBannerTranslation mutation
The mutation was wired up in the GraphQL schema and resolver
but never called from the console frontend. This removes the
service method, request type, resolver, schema entries, and
two unused error sentinels (ErrTranslationNotFound,
ErrTranslationAlreadyExists).

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:11 +04:00
Émile Ré
4246d4fae9 Add i18n variable hints
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:11 +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é
cd824c2c55 Add per-category translations and improve preferences panel preview
Introduce category-level name/description translations in the cookie
banner i18n flow. Seed default translations for fr/de/es on banner
creation, parse them from the stored JSON, and manage them via
react-hook-form Controllers instead of a manual ref/callback pattern.
Enhance the panel preview with category descriptions and all three
action buttons.

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é
879b6dd733 Add cookie banner translations UI
Add default language select to the settings page and a new Translations
tab with react-hook-form-based editing of banner, preferences panel,
and placeholder UI strings with live previews.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:10 +04:00
Émile Ré
fcd58b0f48 Format file
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é
1361dda425 Fix gofmt formatting
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:09 +04:00
Émile Ré
1ff1901331 Add default cookie banner translations for fr, de, es
New banners now get French, German, and Spanish UI string
translations seeded alongside English during creation.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:09 +04:00
Émile Ré
04001c0d90 Add console GraphQL schema and resolvers for i18n
Add CookieBannerTranslation type, defaultLanguage field on
CookieBanner, and upsert/delete mutations for managing
per-language translations from the console.

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é
3a3335f28a Parse ?lang query param in cookie banner config API
Pass the lang parameter from the request URL to the service
so the config response returns localized texts and category
names for the requested language.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:08 +04:00
Émile Ré
de47fb0702 Add cookie banner i18n service logic
Seed default English UI strings on banner creation, include
translations in version snapshots, and resolve language at
config-serving time. Add translation CRUD methods and the
language-aware buildBannerConfig helper. Extract default
categories and UI strings into defaults.go.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:08 +04:00
Émile Ré
d189913ba3 Add i18n data structures for cookie banner
Add cookie_banner_translations table to store per-language
translations as JSONB, and a default_language column on
cookie_banners. Extend the version snapshot types to carry
translated UI strings and category content per language.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-24 12:18:08 +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
Aurélien Sibiril
50c0be6652 Wire evidence-describer worker config in bootstrap
The rebase onto main split the evidence-describer config into two: an
LLMAgentConfig under agents.evidence-describer and a worker-tuning
EvidenceDescriberConfig (Interval, StaleAfter, MaxConcurrency) at the
top level. Bootstrap was only populating the LLM half, leaving Interval
at zero — which panics the probod boot with "non-positive interval for
NewTicker" when the evidence description worker starts. Add the missing
fields with the same defaults main uses.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-24 08:43:14 +02:00
Aurélien Sibiril
509d0c88b1 Add vendor assessment agent
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-24 08:43:14 +02:00
Sacha Al Himdani
25c590ffe6 Add background PDF generation for published document versions
Move PDF generation from synchronous publish flow to a background polling
job. Published versions with file_id IS NULL are picked up by the job,
which generates the PDF, uploads to S3, and links the file. Export PDF
now serves stored files for published versions (with optional signature
page and watermark) and generates on the fly for drafts.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-23 20:50:25 +02:00
Sacha Al Himdani
ff175e3d0d Release v0.172.1
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-23 12:19:30 +02:00