Commit Graph

4346 Commits

Author SHA1 Message Date
Bryan Frimin
1a397b13bc Release @probo/cookie-banner/v0.7.0
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-27 18:20:56 -07:00
Bryan Frimin
31995aa0ca Release probod/v0.196.0
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-27 18:19:34 -07:00
Cursor Agent
6f4ac54a27 Expose bridge sync errors in SCIM API
Add a dedicated SCIMBridge syncError field to the Connect GraphQL API
and populate it from the core bridge model.

Update the connector cards to read bridge state and syncError directly
from the bridge object instead of inferring failures from event
history.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 18:10:22 -07:00
Cursor Agent
83ce4286f8 Alias bridge event field to fix Relay build
Alias the connector card event selection so it does not conflict with
the SCIM event list fragment querying the same  field with
different arguments.

This resolves the Relay compilation failure in CI while keeping the
latest bridge error message available for the error-state callout.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 18:10:22 -07:00
Cursor Agent
f02c3b88b7 Show bridge errors in connector cards
Display SCIM bridge state directly on Google Workspace and Microsoft
365 connector cards so admins can quickly identify failing bridges.

When a bridge is failed, render an inline error callout and surface the
latest provisioning event error message to make troubleshooting visible
without leaving the connector section.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 18:10:22 -07:00
Cursor Agent
4d4f4fa526 Expose profile source in MCP users
Add a ProfileSource schema to the MCP specification and include source\nin the Profile response schema so MCP clients can distinguish\nmanual and SCIM-managed users.\n\nWire the source field in the Profile mapper so list, get, and\ncreate user responses return the persisted profile source.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>
2026-05-28 00:25:50 +00:00
Bryan Frimin
f40fae63b3 Release @probo/n8n-nodes-probo/v0.189.0
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-05-27 13:48:17 -07:00
Bryan Frimin
bc5244d9f4 Release prb/v0.190.0
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-05-27 13:47:24 -07:00
Bryan Frimin
aa3042584c Release probod/v0.195.0
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-05-27 13:46:23 -07:00
Cursor Agent
f50289a755 Harden archive organization scoping
Validate ArchiveUser organization input against the loaded profile and\nuse the profile organization for owner checks and webhook emission.\n\nAlso disable both PersonPage destructive actions while either archive\nor remove mutation is pending to prevent double-submit races.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 12:23:19 -07:00
Cursor Agent
7bb3c144a3 Fix wsl spacing for invitation filter
Add the required blank line before the pending-invitation filter assignment\nin ArchiveUser to satisfy wsl_v5.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 12:23:19 -07:00
Cursor Agent
b75c7880c0 Fix archive user lint spacing
Add the required whitespace before the invitation expiration if-block in\nArchiveUser to satisfy wsl_v5 lint rules.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 12:23:18 -07:00
Cursor Agent
41991f3879 Expire invitations when archiving user
Ensure ArchiveUser deactivates pending invitations for the archived\nprofile so invited accounts cannot still activate after archive.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 12:23:18 -07:00
Cursor Agent
0f8c9e1217 Pass scope into ArchiveUser
Change ArchiveUser to receive an explicit coredata scope from callers\ninstead of rebuilding scope from organization ID inside the service.\n\nWire connect and MCP resolvers to pass the authorized scope through to\nArchiveUser.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 12:23:18 -07:00
Cursor Agent
affed3c781 Remove extra delete error mapping
Drop the additional RemoveUser dependency-error handling that was added\noutside this PR scope.\n\nKeep the separate remove and archive operations, but let delete failures\npropagate through existing wrapped errors without the custom helper and\nreferenced-records error type.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 12:23:17 -07:00
Cursor Agent
1e08a23ddc Split user remove and archive actions
Restore RemoveUser as a hard delete operation and surface dependency\nconflicts with a dedicated IAM error.\n\nAdd a new ArchiveUser flow that deactivates profiles while keeping the\nmember in the organization, then expose both actions across Connect, MCP,\nCLI, n8n, console UI, and e2e coverage.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 12:23:17 -07:00
Cursor Agent
a71a7bb56f Sort n8n user operation options
Reorder the user operation list so the n8n lint rule requiring\nalphabetized option labels passes after introducing the Archive\noperation.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>
2026-05-27 12:23:17 -07:00
Cursor Agent
23070b18b5 Sync user archive across all interfaces
Align user-removal UX and API surface semantics with the new archive\nbehavior for manually managed users.\n\nFrontend copy and actions now use archive wording, and list rows are\nrefetched after the mutation so archived users reappear as inactive.\n\nMCP removeUser now documents and returns archived_user_id, n8n labels\nand response mapping now use archive semantics, and the CLI gains a\nuser archive command backed by the same mutation.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>
2026-05-27 12:23:16 -07:00
Cursor Agent
ebe9cc0e65 Fix wsl spacing in remove user flow
Add the required blank line before the profile-state conditional in\nOrganizationService.RemoveUser so the wsl_v5 lint rule passes in CI.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>
2026-05-27 12:23:16 -07:00
Cursor Agent
b50bbc8d6a Archive manual users on remove
Switch remove-user behavior for manually managed profiles from hard\ndelete to archival by deactivating the profile. This matches the\nrequested SCIM-like lifecycle while avoiding dependency errors for\nlinked records such as signatures and assets.\n\nThe remove flow now updates profile state to INACTIVE, updates\nmembership timestamps, and emits a user-updated webhook event instead of\ndelete events. E2E coverage now asserts that remove keeps the profile\nand marks it inactive.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>
2026-05-27 12:23:07 -07:00
Cursor Agent
ffa3db3cd2 Return conflict when user has linked records
Map remove-user foreign key failures to a dedicated IAM conflict error so\nconsole users no longer receive a generic internal server error when a\nprofile is still referenced by signed documents, tasks, assets, or\nother records.\n\nThe service now detects wrapped dependency errors across both profile\nand membership deletes, and resolvers explicitly map the new error type\nto conflict responses. Added unit tests cover dependency detection and\nthe user-facing error message.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 12:23:05 -07:00
Cursor Agent
a7639be86b Handle archived HubSpot users
Parse HubSpot archived and deactivated status signals when building
access-review account records. This preserves inactive users as
explicit records instead of dropping them when status fields differ
from the current payload assumptions.

Also accept roleIds payloads and keep records that only expose an
external ID, which is common for archived users with empty email
fields. Add a focused unit test to lock in archived-user handling.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 19:10:37 +00:00
Sacha Al Himdani
29051e1f80 Grant SCIM bridge get/manage in IAM policies
The MCP getSCIMBridge tool authorized on iam:scim-bridge:get, but no
role policy allowed that action, so every call denied — including for
owners and admins.

Owners now get the full iam:scim-bridge:* wildcard (matching the
scim-configuration and scim-event treatment in the same policy).
Admins get read-only access and are explicitly denied create/update/
delete, mirroring how scim-configuration is handled.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-27 20:13:29 +02:00
Sacha Al Himdani
b30c476ffe Drop snapshot schema
Drops the now-unused snapshot_id/source_id columns from every table that
carried them, the snapshots and controls_snapshots tables, the
snapshots_type enum, and the snapshot-scoped indexes. Recreates the
unique indexes that previously gated on snapshot_id IS NULL without the
snapshot scope. The data was already cleaned up in the prior PR.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-27 18:40:55 +02:00
Sacha Al Himdani
e6f7884a29 Fix common third-party logo URL not-found error
CommonThirdParty.AuthorizationAttributes returned an empty map, but
the IAM authorizer requires an entry for every requested resource ID
and treats missing entries as ErrResourceNotFound. With the new
authorize() guard on commonThirdPartyResolver.LogoURL, this surfaced
as "commonThirdParties[*].logoUrl resource not found" from the
CommonThirdPartyComboboxQuery.

Switch AuthorizationAttributes to a SELECT-by-id existence check that
returns an empty attributes map for each row that exists. The catalog
is global with no organization, so omitting organization_id is the
intended shape: the authorizer then loads no membership, evaluates
only identity-scoped policies (CommonThirdPartyCatalogPolicy grants
access), and skips audit logging.

Add an e2e regression test that seeds a CommonThirdParty directly via
the test database and asserts the GraphQL logoUrl path resolves
without error.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-27 17:30:16 +02:00
Émile Ré
448b5a043e Gate manual PostHog ping when opted out
PostHog's `cookieless_mode` keeps `is_capturing()` returning `true`
after rejection: in `"always"` mode `opt_out_capturing()` is a no-op
that just warns, and in `"on_reject"` mode it actually registers a
cookieless distinct_id and re-fires a pageview rather than stopping
captures. The example panel's "Capture test event" button therefore
still shipped events (cookielessly) for visitors who had rejected
consent, contradicting the "only delivered when opted in" hint.

Disable the button whenever the cached status reports opted out, and
keep a defensive `has_opted_out_capturing()` check in the click
handler so the example fails closed if the panel is reused without
its disabled-state wiring. Drop the now-redundant disclaimer next to
the last-sent timestamp.

Signed-off-by: Émile Ré <emile@probo.com>
2026-05-27 14:31:52 +02:00
Émile Ré
a447c62e19 Wire PostHog into the cookie-banner React example
Add a deferred PostHog wiring under examples/cookie-banner-react that
boots posthog.init() inside the probo-ready handler and derives
cookieless_mode and opt_out_capturing_by_default from the consent
snapshot for the category flagged with posthog_consent.

Driving the init args off the snapshot rather than consent_mode plugs
two cases the simpler "consent_mode alone" rule got wrong:

  * OPT_OUT regulation, returning rejector: init would have booted in
    on_reject + capture-on, fired a $pageview synchronously, and only
    then called opt_out_capturing(). That single captured pageview
    (and the posthog cookie) leaked on every page load.
  * OPT_IN regulation, returning acceptor: init would have forced
    "always" + opt-out, costing the visitor cookies and a one-tick
    capture delay even though they had already consented.

The snapshot already encodes the regulation default
(buildDefaultConsentData on the cookie-banner client returns true for
non-necessary categories under OPT_OUT and false under OPT_IN) and any
persisted answer from a prior visit, so a single boolean drives both
init args.

Re-export the public domain types (BannerConfig, Category, Regulation,
ConsentAction, ConsentRecord, CookieItem, VisitorConsent) from
@probo/cookie-banner so the example can type the probo-ready event
detail without duck-typing it.

Adopt the PUBLIC_ env prefix in Vite so the example reads the same env
var names (PUBLIC_COOKIE_BANNER_ID, PUBLIC_COOKIE_BANNER_API_BASE_URL,
PUBLIC_POSTHOG_API_KEY) already used on getprobo.com, and add a
matching .env.example.

Ignore *.tsbuildinfo at the repo root; TypeScript's incremental cache
is machine-local and does not belong in the tree.

Signed-off-by: Émile Ré <emile@probo.com>
2026-05-27 13:06:02 +02:00
Bryan Frimin
caba961d7c Release probo-agent/v0.1.0
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 16:22:06 -07:00
Bryan Frimin
21fee97b89 Update release process
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 16:08:10 -07:00
Bryan Frimin
5b2b2c77b8 Fix easyjson issue
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 16:00:08 -07:00
Bryan Frimin
96e127a814 Release probod/v0.194.0
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 15:51:42 -07:00
Bryan Frimin
a68ec5fe5b Upgrade dependencies
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 15:48:03 -07:00
Aurélien Sibiril
e205ff4114 Fix connector provider infos e2e test
Skipping unconnectable providers hides OAuth-only providers when the
deployment has no OAuth credentials configured, which is the case in
e2e. The test asserted SLACK (OAuth-only) is present, so it now fails.
Assert on API-key providers instead, which are connectable regardless
of OAuth configuration.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-27 00:34:40 +02:00
Aurélien Sibiril
9b1034e361 Skip unconnectable providers in provider listing
ConnectorProviderInfos listed every known provider, including ones
this deployment cannot connect: no OAuth client credentials configured
and no API-key or client-credentials fallback supported. Those
rendered as dead entries the operator has no way to use, so skip them.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-27 00:34:39 +02:00
Aurélien Sibiril
a5259fc978 Refine connector provider registry per review
Three follow-ups from review of the registry consolidation:

- Build Vercel's authorization URL with net/url instead of a
  hand-rolled "{integration_slug}" placeholder resolved by
  strings.ReplaceAll. The slug is escaped via url.PathEscape in a
  per-provider Registration.BuildAuthURL closure, and the unused
  AuthURLParams plumbing on Registration and OAuth2Connector is
  removed (OAuth2Connector now carries a typed IntegrationSlug).

- Drop the SettingsInput union type and the per-provider
  MarshalSettings closures. The create resolvers now build the typed
  coredata.*ConnectorSettings directly from the gqlgen input, the
  same way the OAuth callback path already does, so there is no
  shared catch-all DTO and no stringly-typed boundary.

- Restore ConnectorProviders() to a plain ordered slice literal; the
  intermediate map + slices.Sort added nondeterminism and a sort for
  no benefit.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-27 00:34:39 +02:00
Aurélien Sibiril
e18ecdda8b Consolidate connector provider dispatch behind a typed *Registry
The console previously dispatched per-provider logic through a fan of
init()-side-effect maps (driver names, OAuth2 metadata, probe URLs,
display names, settings switches), spread across pkg/connector,
pkg/accessreview/drivers and the console v1 resolvers. Adding a new
provider required edits in every one of those places and a corresponding
switch arm in CreateConnectorRequest. The same per-provider knowledge
also leaked into Helm templates as hand-rolled environment-variable
blocks per connector.

This commit collapses the dispatch surface into a single typed
*provider.Registry. The registry is constructed once by
NewBuiltinRegistry at probod startup and threaded as an explicit
dependency into every consumer (accessreview service, console v1
resolver, OAuth2 wiring). There is no package-level state. Each
provider lives in one file under pkg/connector/provider/ that exposes
a private xxxRegistration() *Registration constructor; NewBuiltinRegistry
enumerates them.

CreateConnectorRequest loses its per-provider settings fields and
takes a single RawSettings json.RawMessage produced by the
per-provider MarshalSettings closure. The 1Password SCIM bridge URL
is validated at create time (http(s) scheme + non-empty host) so a
malformed value fails fast at the resolver boundary. The Helm chart
gains probo.connectorEnv and probo.connectorSecretEntries templates
so adding a connector requires zero Helm changes. Access-review name
resolution moves into the same Registration value to keep one
authoritative dispatch table.

Tests cover every Registration (DisplayName, NewDriver wired),
Register error paths (nil, empty Provider, empty DisplayName,
duplicate), All / ProviderDisplayName / ProviderOAuth2Scopes /
ProbeURL hit and miss paths, the ApplyOAuth2Defaults templating and
PKCE branches, and ConnectorSettings[T] round-trip plus malformed-JSON
error path. The pre-refactor ApplyProviderDefaults test in
pkg/connector is replaced by the equivalent in
pkg/connector/provider.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-27 00:34:39 +02:00
Bryan Frimin
f016e2cf06 Style
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 15:26:22 -07:00
Bryan Frimin
e5041a882a Upgrade golang ci
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 15:22:27 -07:00
Aurélien Sibiril
0c34d4fa05 Fix SA5011 nil-deref lint in validator security test
CI's staticcheck does not treat t.Fatal as terminating, so every
`err.Message` deref sitting after a separate `if err == nil { t.Fatal(...) }`
block is flagged SA5011 (possible nil dereference). Collapse all 26
occurrences in TestNoHTML / TestPrintableText / etc. into a guarded
`} else if`, matching the fix already applied to validator_format_test.go
in bca36636f. The deref now lives in a branch where err is provably
non-nil, which satisfies SA5011 regardless of t.Fatal recognition.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-26 15:07:18 -07:00
Bryan Frimin
b8ea34cdea Fix test linux
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 15:02:50 -07:00
Bryan Frimin
bca36636f9 Style
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 14:29:48 -07:00
Bryan Frimin
100e5a154d Fix docker hub rate limit
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 14:20:28 -07:00
Bryan Frimin
4296d168aa Style
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 14:18:34 -07:00
Bryan Frimin
138f25a170 Style
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 14:11:59 -07:00
Bryan Frimin
51f37b9d85 Style
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 14:07:22 -07:00
Bryan Frimin
712f00f434 Update copyright year
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 13:59:17 -07:00
Bryan Frimin
c46eab5c6e Add i3, kde and more support
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 13:55:43 -07:00
Bryan Frimin
5c73886faf Fix label name
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 13:47:14 -07:00
Bryan Frimin
7a3d3db7ac Style
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 13:45:58 -07:00
Bryan Frimin
e040851a4c Style
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-26 13:45:57 -07:00