Commit Graph

3738 Commits

Author SHA1 Message Date
Sacha Al Himdani
05e5187010 Handle NotFound and NotPublished errors in document resolvers
Use typed ErrDocumentVersionNotPublished instead of plain fmt.Errorf in
signature request methods, and add missing ErrResourceNotFound handling
across document resolvers that were returning Internal for expected errors.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-16 15:38:55 +02:00
Bryan Frimin
1d539f8cc9 Add Docker Hub authentication to CI workflows
Authenticate to Docker Hub in jobs that pull images (build-snapshot-docker,
test-e2e, build-docker) to avoid unauthenticated rate limits.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-16 15:27:58 +02:00
Bryan Frimin
d8722bf3f3 Pin tempo image digest and add pull_policy: missing to all compose services
Avoid unnecessary Docker registry checks on stack-up by setting
pull_policy: missing on every service. Also pin the tempo image to its
sha256 digest for reproducibility, consistent with all other services.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-16 15:21:14 +02:00
Aurélien Sibiril
6f0e150a06 Refactor sidebar with sticky collapse button
The absolute-positioned collapse button overlapped the nav items
whenever the sidebar content exceeded the viewport. With the page now
scrolling at the document level, the overlap became permanent.

Restructure the aside as a flex column: nav list in a flex-1 region,
collapse button in a sticky bottom-0 container with a border-t
separator. The button pins to the viewport bottom while scrolling and
never overlaps the items above.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-16 15:51:45 +04:00
Aurélien Sibiril
8fb688f19c Use page-level scroll in main layout
The previous layout nested two scroll regions, sidebar and main, each
with its own scrollbar. Combined with the fixed 100vh flex container,
any child overflow (notably the sidebar nav) spilled past bg-level-0
and exposed the browser's default white background -- most visible in
dark mode as a white strip at the bottom of the viewport.

Switch to a single page-level scroll: pin the header with fixed, let
the wrapper grow with min-h-screen, and drop main's internal overflow.
The drawer becomes fixed too so it stays pinned while the page scrolls
and gets an opaque background to cover scrolled content behind it.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-16 15:51:45 +04:00
Émile Ré
d63ce1f68b Fix expired queue entries persisting past MAX_AGE_MS
The flush function pruned expired entries in memory but re-read from
localStorage before writing back, so the age filter was never persisted.
Apply the age cutoff to the final write filter and remove the early
return that skipped the write entirely on full send failure.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:34 +04:00
Émile Ré
eafca11c82 Fix queue flush race condition and missing flush on cookie path
Re-read localStorage after network calls in flush() to avoid
discarding entries added by concurrent enqueue() calls. Also
call flush() in the cookie fast-path of load() so queued
consent retries are always drained.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:33 +04:00
Émile Ré
7d05d43f85 Fix review issues from automated code review
- Rename MAX_RETRIES to MAX_ATTEMPTS (3 total) to fix
  misleading naming
- Skip retry loop on caller-initiated aborts so explicit
  cancellations terminate immediately
- Preserve original script type via data-type attribute
  instead of always forcing text/javascript
- Recreate MutationObserver when consent changes so newly
  added elements use fresh consent data
- Fix package.json exports: point main at ESM bundle and
  add proper exports map with IIFE as separate entry

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:33 +04:00
Émile Ré
75996d2dd6 Tune HTTP timeouts and add localStorage consent retry queue
Reduce timeout/retry defaults (5s timeout, 2 retries, 500ms base delay)
to cap worst-case page-load blocking at ~12s instead of ~36s.

Add a localStorage-backed queue that persists failed consent POSTs and
replays them on next page load, closing the compliance gap where a
network failure could permanently lose the server-side audit record.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:33 +04:00
Émile Ré
cb438c010d Fix polynomial regex CodeQL warning
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:33 +04:00
Émile Ré
14d51b1fe4 Add consent-based element activation
Unblock scripts, iframes, images, and other resource-loading
elements marked with data-cookie-consent when their category
is consented. Uses MutationObserver for dynamically added
elements. Restricted to known resource tags with data-href
support for link elements.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:33 +04:00
Émile Ré
266446be9c Use getRandomValues for wider browser support
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:32 +04:00
Émile Ré
c887e3497f Fix copyright headers
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:32 +04:00
Émile Ré
0abde83a88 Extract visitor ID management into visitor.ts
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:32 +04:00
Émile Ré
5cdf39c4f7 Add SDK client with consent cookie caching
CookieBannerClient wraps the cookie banner REST API with
methods to load config, accept/reject/customize consent,
and manage visitor identity. Consent state is persisted in
a probo_consent cookie to skip API calls on return visits,
with version-aware invalidation and configurable expiry.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:32 +04:00
Émile Ré
5b5c671eb1 Fix build.mjs copyright
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:32 +04:00
Émile Ré
3b677d9464 Add HTTP client with retries and typed errors
Introduces fetchJSON<T> with timeout, exponential backoff
with jitter on network errors and 5xx/429, and error classes
that match the cookie banner API error shape.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:31 +04:00
Émile Ré
be1e94da71 Add @probo/cookie-banner SDK package scaffold
Introduce the boilerplate for a new public npm package that will
serve as the cookie consent banner JavaScript SDK. The package
uses esbuild to produce both an IIFE bundle (for script tag
embedding) and an ESM module. Versioning is independent from the
monorepo: CI compares package.json against npm and only publishes
when the version changes.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:31 +04:00
Sacha Al Himdani
5e4cc337ef Release v0.169.1
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-16 12:17:13 +02:00
Sacha Al Himdani
ce1f2fa28c Fix Profile field name in n8n-node GraphQL queries
Rename primaryEmailAddress to emailAddress to match the Profile type
in the GraphQL schema.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-16 12:14:45 +02:00
dependabot[bot]
f9d004422f Bump dompurify from 3.3.3 to 3.4.0
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.3 to 3.4.0.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.3.3...3.4.0)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.4.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-16 07:21:48 +00:00
Sacha Al Himdani
7fe2184e9b Release v0.169.0
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-16 09:18:15 +02:00
Sacha Al Himdani
c635492f75 SOA as document: replace export with publish workflow
Statements of Applicability are no longer exported as one-off PDFs.
Instead, each SOA owns a persistent document that accumulates versions
over time, following the same publish/approve lifecycle as authored
documents.

Publishing without approvers publishes immediately; publishing with
approvers creates a draft pending approval via the existing quorum
system. SOAs can also store default approvers that are pre-populated in
the publish dialog.

The SOA is removed from the snapshot system — applicability statements
are now queried directly (snapshot_id IS NULL) rather than through
snapshot copies.

A standalone migration script (cmd/migrate-soa-snapshots-to-documents)
converts existing SOA snapshots into documents with proper ProseMirror
content, preserving version history and approval decisions.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-16 00:01:13 +02:00
Bryan Frimin
53edc5ba26 Fix compose config
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-15 16:42:56 +02:00
Bryan Frimin
d01b0b3eca Fix Tempo config
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-15 16:42:56 +02:00
Sacha Al Himdani
a58abd445a Release v0.168.2
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-15 14:47:36 +02:00
Sacha Al Himdani
0b9686fc43 Prevent duplicate active document versions
Replace the draft-only unique index with one covering both DRAFT and
PENDING_APPROVAL statuses, ensuring a document can have at most one
active version at a time. Deduplicate any existing data before creating
the index, prioritizing PENDING_APPROVAL over DRAFT.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-15 14:39:27 +02:00
mendral-app[bot]
81de0e7b67 fix: consolidate pure-type schemas into base.graphql to fix gqlgen panic
Merge type-only schema files (country_code.graphql, pagination.graphql,
identity.graphql) back into base.graphql for both trust/v1 and console/v1.

These standalone files had no corresponding _resolvers.go files, causing
gqlgen v0.17.87's Rewriter.getSource() to panic with 'slice bounds out
of range' when running go generate. By consolidating them into
base.graphql (which already has base_resolvers.go), gqlgen can process
the schema without needing separate resolver files for pure-type
definitions.
2026-04-15 16:27:31 +04:00
Sacha Al Himdani
b7f6f27677 Release v0.168.1
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-15 14:11:10 +02:00
Sacha Al Himdani
754dac9ec6 Reject signature and approval requests for people with ended contracts
Add server-side validation in BulkRequestSignatures, RequestSignature,
and RequestApproval to load the referenced profiles and verify none
have an ended contract before proceeding. Returns ErrProfileContractEnded
if a profile's contract_end_date is in the past, surfaced as a CONFLICT
GraphQL error in all three resolvers.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-15 14:05:34 +02:00
Sacha Al Himdani
524f209df7 Filter people with ended contracts from signature request dialog
Move the paginated people query from PeopleGraph.ts into
SignatureDocumentsDialog.tsx following colocated query conventions
and pass excludeContractEnded: true to hide people whose contract has ended.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-15 14:05:34 +02:00
Sacha Al Himdani
891bc02f3e Add document filters to MCP and n8n APIs
Align MCP and n8n document listing endpoints with the GraphQL console
API so every document filter is available across all three interfaces.

MCP:
- listDocuments: add status filter, default to ACTIVE
- listDocumentVersions: add statuses filter
- DocumentOrderField: add UPDATED_AT

n8n:
- document getAll: add query, documentTypes, classifications, status filters (default ACTIVE)
- document getAllVersions: add statuses filter
- document getAllSignatures: add states and activeContract filters

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-15 13:14:04 +02:00
Sacha Al Himdani
ef86a6bf60 Release v0.168.0
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-15 13:11:39 +02:00
Sacha Al Himdani
7a5d4c851a Replace document properties drawer with inline details card
- Remove the right-side drawer and display document properties in a
  3-column Card below the page header
- Move status badge to the PageHeader (right-aligned, matching
  compliance page style)

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-15 10:56:52 +02:00
Émile Ré
e3ab373a0c Add trusted proxy middleware and simplify clientip
Strip forwarded headers (Forwarded, X-Forwarded-For, X-Real-Ip)
from requests originating from untrusted proxies at the HTTP
server level, reusing the existing proxy-protocol trusted-proxies
config. The clientip package is now a pure extraction helper;
context plumbing and middleware wrappers are removed.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:01 +04:00
Émile Ré
8f2426602b Use SplitSeq in clientip forwarded header parser
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:01 +04:00
Émile Ré
713623c7c0 Document enum parameter rule and fix call style
Add coredata guide section on using Go enum constants as named
SQL parameters instead of hardcoded string literals. Fix mixed
inline/multiline RenderJSON call in cookie banner handler.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:01 +04:00
Émile Ré
7a50537bf4 Extract clientip middleware and add jsonutil helpers
Move clientIP extraction into a reusable pkg/server/api/clientip
package with RFC 7239 Forwarded header support. Add
pkg/server/jsonutil with helpers for common HTTP error responses
(RenderForbidden, RenderInternalServerError, RenderNotFound,
RenderBadRequest) and use them in the cookie banner handlers.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:01 +04:00
Émile Ré
abd565c96a Reject origins with trailing empty port in validator
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:01 +04:00
Émile Ré
8ec434d67e Fix review comments on cookie banner API
Parse only the first IP from X-Forwarded-For to prevent
the full chain from bypassing anonymization. Add secondary
sort key for deterministic consent selection. Reject origins
with empty port suffix in the validator.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:00 +04:00
Émile Ré
30a86a91f1 Add cookie banner public API endpoints
Implement config, consent retrieval, and consent recording
endpoints for the JS SDK. IP addresses are anonymized (last
octet zeroed for IPv4, /48 mask for IPv6) before storage.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:00 +04:00
Émile Ré
85061884e7 Update contrib/claude/coredata.md
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-15 10:21:00 +04:00
Émile Ré
c8586346be Review fixes
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:00 +04:00
Émile Ré
ced9ba3550 Ignore test file in trufflehog
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:00 +04:00
Émile Ré
01ca89de4a Rename migration
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:21:00 +04:00
Émile Ré
36062310be Add cookie banner REST API with per-banner CORS middleware
Introduce /cookie-banner/v1/{bannerID}/config endpoint for the JS SDK.
The custom CORS middleware validates each request origin against the
specific banner being requested, preventing cross-customer leakage.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:20:59 +04:00
Émile Ré
41b57a61de Canonicalize cookie banner origin on save
Strip www. prefix and trailing slash from origin when creating or
updating a cookie banner so CORS lookups match regardless of whether
the customer's site redirects www to the apex domain.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:20:59 +04:00
Émile Ré
d05c3591d3 Handle cookie banner origin validation + unicity
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:20:59 +04:00
Émile Ré
0ce1d8039a Split connect profile schema into profile, membership, and invitation
Move OIDCProviderInfo type into base.graphql alongside its query field
in both connect and trust APIs, removing orphan oidc.graphql files.
Split connect profile.graphql into three domain files: profile (with
user mutations), membership, and invitation.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 10:03:50 +04:00
Émile Ré
fe1b5dae4e Review fixes
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-15 09:24:48 +04:00