Commit Graph

4650 Commits

Author SHA1 Message Date
Émile Ré
b5dbdee372 Drop move-to-category confirm dialog
Moving a tracker to a category used to auto-create an org third party in
the mapping worker, so the move was gated behind a confirmation that
warned about it. The worker now only links to an existing vendor and
never creates one, making the prompt inaccurate.

Remove the confirm dialog and move directly on selection, folding the
same-category no-op guard into handleMove.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:22 +02:00
Émile Ré
145aeaf402 Restore tracker mapping linking, drop only create
The tracker-mapping worker had been reduced to catalog resolution only,
which removed not just the auto-creation of an org ThirdParty but also
the auto-linking of an existing one. Only the creation needed to go: it
raced the load-then-create check and produced duplicate vendors.

Restore the full org ThirdParty resolution (exact common-id link,
sibling direct-link, high-confidence heuristic, and the disambiguation
agent) and remove only the CreateFromCommon branch and its
categorisation gate. When nothing matches, the worker now leaves
third_party_id unset rather than creating a vendor; creation happens
exclusively through the explicit ImportFromCommon action. Drop the
now-dead CreateFromCommon helper and rename match.go to common_match.go.

Fix a latent test bug surfaced by actually running the DB-backed suite
(skipped in CI without Postgres): the heuristic-match candidate lacked
Level 1, so the level-filtered candidate loader excluded it and the old
fallback create masked the miss.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:22 +02:00
Émile Ré
9a7bc26d49 Fix lint issues
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:22 +02:00
Émile Ré
941584424a Fix wrong struct field
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:22 +02:00
Émile Ré
675fcc4824 Add Import action for catalog vendors in trackers
A tracker pattern resolved only to a catalog vendor now shows an "Import
to third parties" action in its row menu. It calls
importThirdPartyFromCommon for the pattern's common third party and, on
success, links the imported org vendor onto the row so it stops showing
the "Common catalog" badge.

Sibling patterns of the same vendor are backfilled server-side and pick
up the link on the next fetch of the list, so the store update only
needs to reflect the clicked row.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:22 +02:00
Émile Ré
e2d6972da5 Add importThirdPartyFromCommon GraphQL mutation
Expose the explicit import action over the console API. The mutation
takes an organization and a common third party, authorizes as a
third-party create, and delegates to ThirdPartyService.ImportFromCommon,
returning the org ThirdParty edge plus a created flag so the client can
tell a fresh import from a re-import.

Add an end-to-end test covering the two behaviours that matter: the
first import seeds the org vendor from the catalog and backfills the
linked tracker pattern's third_party_id, and a second import is
idempotent, returning the same row with created=false.

The gqlgen-generated types and execution code are build artifacts (not
tracked), so only the schema and the resolver change here.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:22 +02:00
Émile Ré
11c74617d0 Dedupe org third parties and add unique index
Add the partial unique index that enforces one org ThirdParty per catalog
vendor per organization, on (organization_id, common_third_party_id)
where common_third_party_id is not null. Manually created vendors (null
common id) stay unconstrained.

Existing data may already hold duplicates left by the old auto-create
race, which would make the index build fail, so a preceding DO block
merges them first. It maps each duplicate onto the earliest-created
survivor and, driven by pg_constraint / pg_index introspection, repoints
every foreign key that references third_parties(id) onto the survivor,
removing link rows that would collide on a referencing table's unique
key before repointing, then deletes the extras.

The dedupe is destructive and introspection-driven; validate it against a
production dump before deploying.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:21 +02:00
Émile Ré
27ff38df7d Remove third-party disambiguation agent and matching
The tracker-mapping worker no longer auto-creates or auto-links org
third parties, so the heuristic ranker, the disambiguation agent, and
the catalog-to-org seeding helpers are dead code.

Delete pkg/thirdparty/match.go (RankCandidates, ScoredCandidate,
LinkToCommon, CreateFromCommon, suffix stripping, score thresholds) and
disambiguation_agent.go, along with their tests. Drop the
ThirdPartyDisambiguation agent slot and the worker's
DisambiguationAgentTimeout from probodconfig, the builder env wiring, and
the builder tests.

Remove the matching helm surface too: the thirdPartyDisambiguation agent
values, the disambiguationAgentTimeout worker tuning, and the
AGENT_THIRD_PARTY_DISAMBIGUATION_* / TRACKER_MAPPING_DISAMBIGUATION_AGENT
_TIMEOUT environment mappings, with a chart changelog note. The probod
config is built from env lookups with defaults, so a lingering value in
an older deployment is simply ignored.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:21 +02:00
Émile Ré
ed2dbe92c9 Surface catalog vendors in tracker policy doc
The generated tracker policy listed only org ThirdParty rows linked to
the banner's patterns. Now that the mapping worker no longer auto-creates
those rows, a banner whose vendors have not been imported would render an
empty third-party section.

Build the list from the same union the banner's linkedThirdParties
resolver exposes: org ThirdParty rows plus the CommonThirdParty catalog
entries reached through patterns that carry no org link. Dedupe by name
with org rows taking precedence, so the policy stays complete and
accurate whether or not a vendor has been imported into the register.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:21 +02:00
Émile Ré
c25e7c6c40 Add explicit third-party import from catalog
With the tracker-mapping worker no longer materializing org third
parties, add the deliberate action that does: ThirdPartyService.Import
FromCommon seeds an org ThirdParty from a CommonThirdParty catalog entry
or returns the one the organization already imported, making it
idempotent on the (organization_id, common_third_party_id) pair.

On both the create and reuse paths it backfills tracker_patterns.third_
party_id for the organization's unlinked patterns whose catalog row
resolves to the same common third party, via the new TrackerPatterns.Link
ThirdPartyByCommonThirdPartyID. Patterns that previously surfaced the
catalog entry then surface the managed org vendor in the trackers UI and
the tracker-policy document. Only unlinked patterns are touched, so the
backfill is idempotent and picks up newly detected patterns on re-import.

End-to-end coverage (idempotency and pattern backfill) lands with the
GraphQL mutation in a following commit.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:21 +02:00
Émile Ré
0f5ac03e70 Stop auto-creating org third parties on mapping
The tracker-mapping worker materialized a per-org ThirdParty for every
categorized tracker, linking or creating one through heuristic and
disambiguation-agent matching. Concurrent mapping of two patterns for
the same common third party raced the load-then-create check and left
duplicate org third parties with the same name.

Reduce the worker to catalog resolution only: it resolves the shared
common_tracker_pattern_id / common_third_party_id link and leaves
third_party_id untouched, preserving any link set elsewhere. Org third
parties will instead be created through an explicit per-vendor import
action added in a later commit.

Remove resolveOrgThirdParty, prepareOrgThirdParty, the sibling
direct-link signal, and the disambiguation-agent wiring (including its
constructor parameter and buildTrackerAgents return), and update the
worker tests to assert the catalog link is resolved while third_party_id
is preserved.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-11 12:08:21 +02:00
Sacha Al Himdani
04a34c9757 Require explicit approver_ids when publishing a document major version
The publish flow ignored a document's stored default approvers and only
requested approval when approver_ids were passed in the call, so a major
publish with no approver_ids silently published directly without routing
through the approval flow — there was no way to tell "caller forgot
approvers" (null) from "caller wants no approval" (empty).

Make approver_ids an explicit choice, enforced once in the service so it
covers every caller (console, MCP, n8n):
- major publish: approver_ids must be set; an empty list publishes
  directly, a non-empty list requests approval.
- minor publish: approver_ids must be omitted (approvers are ignored).

Validate this in PublishDocumentRequest.Validate(), update the console
publish dialog and the n8n publish node to honour the contract, document
it in the MCP tool spec, and cover it with e2e tests.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-06-11 11:41:30 +02:00
Ludovic Vielle
3475dd0560 Switch console file fields to File download URLs
Replace presigned URL string fields (logoUrl, fileUrl, ndaFileName,
etc.) with nested File references resolved through /api/files/v1/.
Update console Relay queries and e2e coverage accordingly.

Route NDA upload through filemanager.PutFile and return stable IAM
org logo URLs for consistency with the files API.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-11 10:47:28 +02:00
Bryan Frimin
003fd2baf1 Drop DEFAULT TRUE from active column after backfill
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-11 10:42:55 +02:00
Bryan Frimin
4b0d0cf0bd Default active to TRUE for access entries
Drivers that cannot determine account status leave Active nil.
Rather than surfacing NULL in the database, treat an absent signal
as active (the account appeared in the source listing).

- Migration: NOT NULL DEFAULT TRUE on the active column
- Insert/upsert SQL: COALESCE(@active, TRUE) on write
- Fix new(true) in test (not valid Go; use &activeTrue)

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-11 10:42:55 +02:00
Bryan Frimin
c28287f307 Fix wsl_v5 blank line before if statements
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-11 10:42:55 +02:00
Bryan Frimin
c913e97c35 Add active status field to access entries
Track whether an account is active (enabled) or disabled at the
source system. The field is nullable so existing entries without
this data remain valid.

- DB migration adds active BOOLEAN column to access_entries
- Coredata read/write/upsert/filter wiring for the new column
- Review engine propagates Active from source accounts
- GraphQL schema exposes active on AccessEntry and AccessEntryFilter
- MCP spec, types, and resolvers expose active and fix missing
  account_type filter that was wired in GraphQL but not MCP
- CLI list command adds --active filter flag and ACTIVE output column
- Console campaign detail table shows Active/Disabled status badge
- E2e and unit tests updated to cover the new field

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-11 10:42:53 +02:00
Bryan Frimin
95a12d338b Retry DNS TXT lookup over TCP on truncated UDP response
When a domain has multiple TXT records (SPF, DKIM, etc.), the UDP
response can exceed 512 bytes and the server sets the TC bit. The
verifier was not handling this case, so any truncated response that
omitted the probo-verification record would silently fail as a
mismatch.

Fix by checking resp.Truncated after the UDP exchange and retrying
over TCP when set. Also pass the caller's context instead of
context.Background(), and simplify message construction with
dns.NewMsg.

Closes #1335

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-11 09:49:38 +02:00
Émile Ré
c3936a7173 Release @probo/cookie-banner/v0.9.1
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 18:52:38 +02:00
Émile Ré
32408fe535 Release @probo/n8n-nodes-probo/v0.193.0
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 18:51:52 +02:00
Émile Ré
9986553f4e Release proboctl/v0.3.0
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 18:49:27 +02:00
Émile Ré
90c52d743d Release probod/v0.207.0
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 18:47:09 +02:00
Émile Ré
af5f48ad8a Release prb/v0.193.0
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 18:45:22 +02:00
Émile Ré
2db063bc60 Drop progress reporting from banner tracker reset
The ResetProgressFunc callback streamed per-phase messages from inside
the reset transaction, so a rollback could leave already-printed
progress describing work that never committed. Remove the callback
entirely; the final result summary printed by proboctl still conveys
the outcome without the misleading intermediate output.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 18:28:21 +02:00
Émile Ré
ed9831a734 Default cookie consent to GDPR and track its source
When IP geolocation does not resolve a country, or resolves one with no
known cookie-consent regulation (common on localhost and unmapped
regions), the banner previously fell back to OPT_OUT with no recorded
regulation. Apply GDPR (OPT_IN) as the safe default in that case so the
strictest consent model wins when origin is unknown.

To keep consent records auditable, stamp each one with a regulation
source of DETECTED (resolved from geolocation) or DEFAULT (fell back to
GDPR). The shared cookiebanner.ResolveRegulation helper centralizes the
decision for both the config and consent endpoints, and the new value is
exposed through GraphQL, MCP, the CLI, the n8n node, and the console
consent-records views.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:41 +02:00
Émile Ré
e3ccb76b03 Lock page scroll while cookie panel is open
The preference panel is a fixed, backdrop-less card whose only
scrollable region is the category list. Wheel events over the
header, footer, padding, or at the list edges chained to the host
page, so the page scrolled instead of the panel.

Treat the open panel as the modal it already claims to be: lock
document scroll while state is "panel" (compensating for scrollbar
width to avoid layout shift) and add overscroll-behavior: contain
to the list. Restore scroll on close and on disconnect so the page
is never left frozen.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:41 +02:00
Émile Ré
1e3c1342e3 Clear stale cookie-banner SDK initiator URLs
A pre-fix bug in the cookie-banner SDK walked its own bundle frame
when computing a tracker's initiator, so cookies and storage written
by third parties, malware, or browser extensions were attributed to
cookie-banner.iife.js. The report upsert keeps the existing value on
re-detection (initiator_url = COALESCE(new, old)), so rows whose
corrected initiator is NULL would keep the stale bundle URL forever.

Null initiator_url and initiator_domain on detected_trackers rows that
point at the @probo/cookie-banner bundle. Genuine third-party rows
repopulate the correct initiator on the next detection.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:41 +02:00
Émile Ré
eb7878c618 Exclude SDK bundle URL from tracker attribution
The cookie/storage/resource detectors only skipped the API base-url
origin and the page origin when computing a tracker's initiator. When
the SDK is served from a CDN (e.g. jsDelivr) distinct from the API
host, its own wrapper frames sit atop every setItem/document.cookie
call stack and were never skipped, so getInitiatorURL returned the
bundle URL. Third-party and browser-extension writes were therefore
misattributed to cookie-banner.iife.js.

Capture the SDK's own served script URL once at load (currentScript
src, with an Error().stack fallback) and exclude it, at URL level, from
both the initiator stack-walk and the resource detector. URL-level
exclusion keeps other trackers served from the same shared CDN
detectable.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:41 +02:00
Émile Ré
7c09e19d0c update confidence when relinking common tracker to third party
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:41 +02:00
Émile Ré
31c4a0b39c Add proboctl catalog upsert, link, and describe commands
Operators previously had no way to curate the global tracker catalog
beyond inspection and banner-scoped resets. Add three proboctl commands
backed by small coredata helpers:

- common-third-party upsert: create or update a vendor keyed by slug,
  with partial-merge so an unset flag never blanks an existing column.
- common-tracker-pattern link/unlink: repoint catalog rows at a common
  third party (re-arming enrichment and remapping the uncategorised org
  trackers so the mapping worker re-resolves the vendor) or detach them.
  Unlinking skips enrichment and remap since there is no new vendor.
- common-tracker-pattern set-description: write a description, mark the
  row enriched, and backfill linked org patterns lacking one.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:40 +02:00
Émile Ré
ae61c20791 Match cookie-database denylist on domain forms
The cookie-database aggregator backstop normalised the agent's
third-party name and looked it up against bare brand keys, but
normalizeAlnum folds the eTLD into the key (cookiedatabase.org ->
cookiedatabaseorg). Domain- and URL-form attributions therefore
slipped past the exact lookup, letting noisy aggregator names be
accepted instead of discarded.

Add uri.DomainLabel to reduce a host-like string to its primary
registrable label and check it alongside the normalised name, so
both brand ("Cookiepedia") and domain forms ("cookiedatabase.org",
"https://www.cookiepedia.co.uk/list") resolve to the same key.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:40 +02:00
Émile Ré
a68c2ef108 Ignore cookie-database sites in tracker mapping
Cookie-database and consent-directory sites (Cookifi, Cookiepedia,
cookiedatabase.org, CookieServe, ...) rank highly in web search only
because they catalog cookies, not because they set them. The mapping
agent could attribute a tracker to the directory operator itself
instead of the vendor the page names.

Instruct the agent to treat such results as reference directories and
extract the named vendor, never the operator, while keeping a CMP's own
product cookie attributable (OptanonConsent -> OneTrust, CookieConsent
-> Cookiebot). Add a conservative code backstop that discards
attributions to pure aggregators, scoped to exclude CMP vendors so
legitimate own-cookie attributions survive.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:40 +02:00
Émile Ré
e88ad152df Suppress own-domain tracker attribution
Patterns like "ethereum-https://letaido.com" embed the scanned site's
own origin, appended either by a browser extension (e.g. a wallet
injecting window.ethereum) or by an owner-set tracker. The mapping
agent read that embedded domain and attributed the site to itself as a
third party ("Letaido"), but a site owner is never a third party of its
own site.

Pass the scanned site's eTLD+1 to the agent as a <scanned_site> signal
and instruct it to ignore a domain embedded in the pattern that matches
the site, returning low confidence when that is the only cue. Add a
deterministic backstop that discards any agent attribution whose vendor
name resolves to the site's own domain, so the pattern falls through to
the unmatched fallback regardless of whether the model honored the
prompt. Deterministic catalog, naming, and sibling signals run before
the agent and are untouched, so an independent strong vendor signal
still attributes normally.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:40 +02:00
Émile Ré
faca86a022 Scope reset-trackers by keyword and report progress
The reset-trackers operator command reset every uncategorised,
non-excluded pattern of a banner and printed only a single summary
line once the transaction committed, giving no feedback during long
rebuilds.

Add a --keyword flag that scopes both the glob decomposition and the
mapping reset to patterns whose pattern or display name contains the
substring. The match lives in a new TrackerPatternFilter.WithPatternKeyword
field so it runs in SQL and is shared by the glob load and the
ResetAndRequestMappingByCookieCategoryID update, keeping the two in
lockstep. The banner-wide pattern-analysis re-arm is left unscoped.

Thread an optional progress callback through ResetBannerTrackers so the
command streams per-phase updates (category load, per-glob decomposition,
mapping reset, analysis re-arm) as the work runs.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:40 +02:00
Émile Ré
5415b2d438 Allow reenrich without a selection anchor
The reenrich command forced callers to pass exactly one selection
anchor (--id, --linked-banner, --linked-org, or --common-third-party)
before any pattern could be re-described. That made the common case of
re-enriching every catalog row with a blank description impossible
without an artificial anchor.

Drop the anchor-required guard while keeping anchors mutually
exclusive. With no anchor, the filtering flags now select across the
whole catalog, so --without-description re-enriches every pattern that
lacks a description.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:40 +02:00
Émile Ré
4e72ad3bea Clarify tracker detection count label
The "Detected Count" label was ambiguous about whether it counted
distinct trackers or report occurrences. The report endpoint upserts
each detected tracker by identifier, so the value is the number of
distinct trackers matched by the pattern. Rename the label to
"Distinct Trackers Detected" to reflect this.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-10 17:49:39 +02:00
Ludovic Vielle
3f484ac330 Compute stable URL in types.NewFile, wire baseURL into console v1 Resolver
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-10 15:53:35 +02:00
Ludovic Vielle
6693ee4bf4 Delete pkg/file, fully absorbed into pkg/filemanager
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-10 15:53:33 +02:00
Ludovic Vielle
b679107fa5 Migrate all callers to unified filemanager.Service
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-10 15:53:32 +02:00
Ludovic Vielle
6f8af6f62e Add pkg/filemanager/internal/s3, rewrite unified filemanager service
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-10 15:53:31 +02:00
Sacha Al Himdani
b6781d3de0 Scope sub-third-parties per parent
Replace the many-to-many junction table with a direct
parent_third_party_id foreign key on third_parties. Each
sub-third-party now belongs to exactly one parent, making
duplicates across parents independent entities.

Replace the firstLevel boolean with an integer level field
(1 = direct, 2+ = parent level + 1) to support arbitrary
nesting depth.

Remove the createThirdPartyThirdPartyMapping and
deleteThirdPartyThirdPartyMapping mutations, the CLI
link/unlink commands, and the corresponding MCP tools.
Creating a child third party now just requires passing
parentThirdPartyId on the existing createThirdParty mutation.

The frontend walks the parentThirdParty chain to build
display names like "Name (Ancestor1/Ancestor2)" and shows
clickable ancestor links on the detail page.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-06-10 14:15:01 +02:00
Aurélien Sibiril
ec858e58df Add Neon access review driver support
Register Neon as a connector provider and add a new access review
driver that fetches organization members from the Neon API with
cursor-based pagination.

Neon's OAuth is partner-gated, so the connector is API-key only
(Bearer, the default scheme). A personal or organization API key can
belong to several organizations; the operator supplies the ID of the
one to review. The members endpoint exposes per-user MFA state
(has_mfa) and deactivation, which map to the access entry MFA status
and active flag; the stable account UUID (user_id) is used as the
external ID over the membership ID.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-06-10 00:55:54 +02:00
Aurélien Sibiril
7640376d32 Add Render access review driver support
Register Render as an API-key connector provider and add an access
review driver that fetches workspace members from the Render API
(GET /v1/owners/{ownerId}/members).

Render exposes no partner OAuth program, so the connector authenticates
with a read-scoped API key (Authorization: Bearer) plus the customer's
Workspace ID. The flat members endpoint reports an explicit account
status and MFA flag, surfaced as the Active and MFAStatus fields; the
stable "usr-" id becomes ExternalID. There is no picker -- the
workspace is captured up front via ExtraSettings -- so
SetOrganizationSettings is omitted.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-06-09 23:54:55 +02:00
Cursor Agent
7a43acd3c2 Add Qovery access review driver support
Register Qovery as a connector provider and add a new access review
driver that fetches organization members from the Qovery API.

Extend API key connection handling with a configurable Authorization
token scheme so Qovery can use "Token" while existing providers
continue to default to Bearer.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-06-09 19:43:47 +02:00
Émile Ré
9e5d0d1c00 Release helm/v0.5.0
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-09 18:07:14 +02:00
Émile Ré
ab2447abc6 Release proboctl/v0.2.0
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-09 18:06:49 +02:00
Émile Ré
5a4bbb8294 Release probod/v0.206.0
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-09 18:06:22 +02:00
Émile Ré
0e4e63702c Release @probo/n8n-nodes-probo/v0.192.0
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-09 18:05:55 +02:00
Émile Ré
8fca59e3bc Release prb/v0.192.0
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-09 18:05:29 +02:00
Ludovic Vielle
60435f277b Serve brand assets as static files via /api/files/v1/static instead of S3
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-09 17:42:18 +02:00