Rewrite worker unit tests: TestTemplateCandidates, TestGlobMatch,
TestSplitTokens, and updated TestFindMergeGroups with sandwich pattern
cases. Update e2e test to use GLOB instead of PREFIX.
Signed-off-by: Émile Ré <emile@getprobo.com>
Replace prefix-only merge logic with token-template analysis that
discovers sandwich patterns (e.g. ph_phc_*_posthog). The worker now
emits GLOB patterns, adoption uses globMatch, and validation enforces
exactly one wildcard for GLOB patterns.
Signed-off-by: Émile Ré <emile@getprobo.com>
Introduces a wildcard-based match type that supports prefix, suffix,
and sandwich patterns (e.g. ph_phc_*_posthog). The SQL matching uses
starts_with/ends_with on the parts split at '*', avoiding LIKE and
its underscore escaping issues. Existing PREFIX rows are migrated to
GLOB with a trailing '*'.
Signed-off-by: Émile Ré <emile@getprobo.com>
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>
Progressive enhancement for Chromium browsers: listen on the
CookieStore change event to catch cookies set by Set-Cookie HTTP
response headers, which the document.cookie setter hook cannot see.
Adds a new "http" cookie source through the full stack.
Signed-off-by: Émile Ré <emile@getprobo.com>
Strip query params and send origin+pathname so the backend can
distinguish resources served from the same domain but different paths
(e.g. gtm.js vs recaptcha/api.js on googletagmanager.com).
Signed-off-by: Émile Ré <emile@getprobo.com>
Trackers sharing a prefix but with materially different lifetimes
(e.g. session vs 1-year) were incorrectly merged into a single
prefix pattern. Port the snap table from cookie-utils.ts into Go
and use it to bucket durations so only trackers that display the
same human-readable lifetime can merge. Update the unique index
to include COALESCE(max_age_seconds, -1) so prefix patterns with
different durations can coexist.
Signed-off-by: Émile Ré <emile@getprobo.com>
Reorganize detector files into src/detectors/ following the same
pattern as src/integrations/. Rename detector-interface.ts to
detector.ts (the interface), and detector.ts to cookie-detector.ts.
Barrel export from detectors/index.ts provides Detector interface
and all three detector classes.
Signed-off-by: Émile Ré <emile@getprobo.com>
Introduce a common Detector interface (start/stop) implemented by
CookieDetector, StorageDetector, and ThirdPartyDetector. The client
manages them as a uniform array, simplifying lifecycle management.
StorageDetector wraps Storage.prototype.setItem and indexedDB.open
to detect localStorage, sessionStorage, and IndexedDB usage.
ThirdPartyDetector uses MutationObserver to detect cross-origin
script and iframe elements, reporting at origin level.
Both report to POST /detected-trackers with 2s debounce and max
100 items per batch.
Signed-off-by: Émile Ré <emile@getprobo.com>
Lock the backend contract the console relies on after deleting a
campaign: the deleted GID must be gone from the organization's
accessReviewCampaigns connection and node(id:) must return
NOT_FOUND. The frontend caches both queries and would crash again
if either contract slipped (e.g. a stale row, a wrong error code,
or a missing cascade on scope sources).
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
@deleteRecord wiped the campaign from the Relay store but left the
cached AccessReviewCampaignsTabQuery connection holding an edge
pointing to the now-missing record. Re-opening the access-reviews
tab made Relay surface a missing-data error and the org error
boundary rendered "Unexpected error :(".
Switch to @deleteEdge with the campaigns connection id so the edge
is removed alongside the deletion, matching the pattern already used
by audit and statement-of-applicability detail pages.
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
Address review feedback:
- Move ErrSuspendForCheckpoint from checkpoint.go to errors.go
next to the rest of the agent error declarations; drop the
colon in the error string so it matches the existing
`agent run <event>` style used by the supervisor sentinels.
- Replace the inline `outerCtx := ctx; ctx = context.WithoutCancel(ctx)`
pattern with a small `suspendShield` helper in context.go used
by coreLoop, resumeWithOpts, and resumeNested. Reads more
cleanly and stops surfacing the WithoutCancel mechanism at
every call site.
- Trim the doc comments on Run, RunStreamed, Resume, Restore, the
ErrSuspendForCheckpoint declaration, and the saveCtx comment in
restoreNestedSuspended down to the contract bullet.
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
Lead with the observable contract (ctx.Done = graceful suspend,
return is *SuspendedError, framework shields downstream calls) and
mention agent.ErrSuspendForCheckpoint as the recommended cancel
cause for graceful-stop intent. Drop the leak of the WithoutCancel
mechanism — readers need the contract, not the strategy.
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
Two additions:
- agent_test.go's "context cancellation triggers graceful suspend"
now also asserts the input messages land in the suspension
checkpoint — verifies the embedded-Checkpoint path that fires
when no Checkpointer is configured.
- cancel_test.go gets a third subtest that parks the LLM provider
inside ChatCompletion via a release channel, cancels ctx while
the call is in flight, then confirms the LLM call still saw a
non-cancelled ctx and the just-completed turn lands in the
persisted checkpoint. Proves the framework's WithoutCancel
shielding works end-to-end at the unit level.
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
The sentinel is part of the agent cancellation contract — the only
caller that needs it (the supervisor) imports pkg/agent already, so
keeping it next to SuspendedError prevents the upward dependency
that would arise if any future agent.Run caller wanted to trigger
graceful suspend. Update pkg/probo/agent_run_handler.go to
reference agent.ErrSuspendForCheckpoint.
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
Add a Cancellation semantics section explaining ctx.Done() =
graceful suspend, the WithoutCancel shadow inside coreLoop, the
implication for context.WithTimeout deadlines, the absence of an
in-process hard-abort, and the supervisor-side mapping of SIGTERM
shutdown onto cancelRun(ErrSuspendForCheckpoint).
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
Rewrite the WithStopSignal-driven test in restore_test.go to use a
cancellable ctx. Update agent_test.go's "context cancellation"
case from asserting "cannot complete" failure to asserting a
SuspendedError. Add cancel_test.go covering both pre-first-turn
cancel (no LLM call, empty checkpoint persisted) and mid-run
cancel from inside a tool (just-completed turn preserved in the
checkpoint, second LLM call suppressed).
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
Process now has the per-run forwarder goroutine call
cancelRun(ErrSuspendForCheckpoint) when h.shutdownCh closes,
rather than closing a separate stopCh and embedding it via
agent.WithStopSignal. The agent loop's new ctx-cancel = graceful
suspend contract covers the rest. h.shutdownCh and signalShutdown
stay as the supervisor-level broadcast (still observable through
ShutdownBroadcastForTests).
The lease-loss path keeps its existing cancelRun call; under the
new contract that triggers a best-effort save before executeRun
detects ErrAgentRunLeaseLost and skips the row commit, which is
race-safe because Worker B can only claim the row after stale
recovery — by then our save has long landed.
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
Collapse the dual-mechanism (ctx.Done() = abort + WithStopSignal =
graceful suspend) into a single signal: ctx.Done() now means
graceful suspend. coreLoop shadows the incoming ctx with
context.WithoutCancel(ctx) on entry and uses the shadow for every
downstream call (LLM, tools, hooks, guardrails, save), keeping the
original ctx only for the at-boundary cancellation check.
restoreNestedSuspended applies the same shadow to its
saveProgress closure so partial nested-restore writes survive a
graceful cancel. Resume and resumeNested mirror the pattern so
their pre-loop tool dispatch is non-cancellable while coreLoop
still detects the cancel at its first turn boundary. The dedicated
stop signal API (WithStopSignal / stopSignalFrom) is removed.
There is no longer an in-process hard-abort path; tool authors
who need a deadline must derive it themselves. Document the new
contract on Run, RunStreamed, Resume, and Restore.
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
In OPT_OUT mode the button_opt_out text was mapped to
button_customize, which opens the preference panel. Map it
to button_reject_all instead so the button performs a
one-click reject for all OPT_OUT regulations.
Signed-off-by: Émile Ré <emile@getprobo.com>
OPT_OUT regulations (e.g. CCPA) now reopen the banner instead
of the preference panel when clicking the settings widget,
since users only need Accept/Reject choices rather than
granular per-category toggles.
Signed-off-by: Émile Ré <emile@getprobo.com>
ProboRejectButton and ProboCustomizeButton now auto-hide when
their corresponding text key is empty in the server-provided
config, removing the need for headless SDK consumers to
implement regulation-aware layout logic themselves.
The redundant applyLayout() in ProboThemedBanner is removed
since the headless components handle visibility directly.
Signed-off-by: Émile Ré <emile@getprobo.com>
Previously the SCIM settings page rendered both Google Workspace and
Microsoft 365 connector cards even after a bridge was connected,
making it look like the other provider was still actionable. Once a
bridge exists we now only show the connector matching the bridge
type; both are still listed when nothing is configured.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Add the missing MICROSOFT_365 value to the connector_provider enum
so the connector loader stops failing with SQLSTATE 22P02.
Scope each Identity Provider card to its own SCIMBridge type so
connecting Microsoft 365 no longer marks Google Workspace as
connected (and vice versa).
Filter Microsoft Graph /users to userType eq 'Member' so the bridge
only syncs home-tenant members and skips B2B guest accounts that
were polluting the synced People list.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Adds an "Approvers" row to the SOA details card with the same inline
edit pattern as DocumentDetailsCard, calling updateDocument with
defaultApproverIds. Visible only after first publish, when the SOA
has an associated document.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>