Commit Graph

5505 Commits

Author SHA1 Message Date
Bryan Frimin
bcf244c787 Release @probo/n8n-nodes-probo/v0.207.0 2026-07-27 19:01:56 +02:00
Bryan Frimin
bc64e5ead8 Release probod/v0.237.0 2026-07-27 19:01:37 +02:00
Bryan Frimin
e94d224261 Release prb/v0.204.0 2026-07-27 19:01:17 +02:00
Bryan Frimin
636dd172e8 Fix wsl_v5 spacing in MergeByCampaignID
Add blank lines around the dedup-and-connector-ID block to satisfy
the wsl_v5 linter (blank line after an if-block, above an assignment
following a block, and above an if with no shared variables in the
preceding line).

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-27 18:56:25 +02:00
Bryan Frimin
b43e66ffa4 Remove restated doc comment on MergeByCampaignID
The comment repeated what the function signature and body already
say plainly.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-27 18:56:25 +02:00
Bryan Frimin
68a64647bf Batch-load and validate campaign sources before merging
MergeByCampaignID joined access_review_sources directly from coredata
to resolve live sources, so unrecognized or out-of-scope IDs were
silently dropped instead of erroring, and in the worst case (every ID
invalid) the NOT MATCHED BY SOURCE clause deleted every existing
campaign source. The syncCampaignSources ErrResourceNotFound check
was therefore unreachable dead code.

Add AccessReviewSources.LoadByIDs, matching the existing scoped
LoadByIDs pattern (id = ANY(@ids) plus a resolved-count check), and
have CreateCampaign, AddCampaignSource, and syncCampaignSources
resolve and validate sources up front. MergeByCampaignID now takes
the already-loaded sources and builds its desired-state CTE from an
unnest() of their values instead of joining access_review_sources,
keeping the merge inside the campaign-source entity boundary.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-27 18:56:24 +02:00
Bryan Frimin
8bc394c54b Paginate access review source loader in n8n node
The loader fetched only the first 500 sources with no pageInfo/cursor
follow-up, so organizations with more than 500 scoped sources could
not select sources past the first page when creating or updating a
campaign. Loop over pages using pageInfo.endCursor until exhausted.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-27 18:56:24 +02:00
Sacha Al Himdani
2ebf3c180f Fix crash on third-party details when country is GLOBAL
Intl.DisplayNames rejects the GLOBAL pseudo-region, so label
resolution now handles it explicitly before rendering the picker.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-27 18:56:24 +02:00
Émile Ré
302175617f Drop report org checks and noisy comments
Report access loads are already tenant-scoped; reject the
extra organization guard. Also remove the PortalAccessRequest
doc comment called out in review.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:21 +02:00
Émile Ré
14c9c921cc Drop unreachable no-targets error handlers
The single-resource access resolvers each forward exactly one hard-coded
id, so RequestPortalAccess never returns ErrNoAccessTargets on those
paths — it only does so when all three id slices are empty. Remove the
three dead handlers, keeping the live one on the bulk path where the
resolved id slices can legitimately all be empty.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:21 +02:00
Émile Ré
1e79755121 Derive selection count from live locked rows
The bar read the raw selection size for its count, so after a request
succeeded and Relay flipped the rows to pending the left count stayed
stale while the action count dropped to zero. Resolve the selection
against the current rows instead, so requested rows leave the count at
once and the bar closes without depending on a clear that may not run.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:21 +02:00
Émile Ré
d0c9327e99 Require explicit portal access request IDs
Drop the request-all shortcut so callers always name the
documents, reports, and files to request. TopBar Get Access
now only signs in; bulk selection is the multi-resource path.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:21 +02:00
Émile Ré
baa5a3588a Lock only document rows without an access record
The bulk request skips any id that already has an access record, so
rejected or revoked rows reported success while creating nothing. Treat a
row as requestable only when the viewer is unauthorized and no access
record exists yet, keeping the selection CTA count honest.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:21 +02:00
Émile Ré
dbdd79e1c1 Fix lint issues
Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:21 +02:00
Émile Ré
ca5c622a01 Stop empty toast viewport from eating pointer events
The toast viewport stays mounted even with no toasts, as a fixed box in
the bottom-right corner. With default pointer-events it swallowed hover
and clicks over content beneath it, such as the lower edge of a bottom
action bar's right-aligned buttons.

Mark the viewport pointer-events-none and re-enable events on each toast
root so only actual toast cards are interactive.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:21 +02:00
Émile Ré
d2638a3d78 Extract selection bar styles into a tailwind variant
The bottom selection action bar carried its layout as inline class
strings on the container divs. Move them into a slotted tv in the
documents variants module, matching the documentsLayout pattern, so the
component consumes named slots instead of ad hoc className literals.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:20 +02:00
Émile Ré
1d6218cb7d Disable row selection for non-lockable documents
Public / already-authorized and already-requested rows could be ticked
even though they never contribute to "Request Access (N)", making the
selection count look inconsistent with the CTA. Restrict selection to
locked rows: their checkbox is disabled otherwise, and "Select all" now
picks only the lockable rows.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:20 +02:00
Émile Ré
9353d85d03 Add bulk request access to portal documents
Visitors could only request access to one document, report, or file at
a time. Add row checkboxes and a bottom selection toolbar to the
compliance portal documents page so a visitor can select several rows
and request access to all still-locked ones in a single round-trip.

Expose a selection-scoped requestAccesses mutation that forwards the
chosen id lists to the existing RequestPortalAccess service (one
transaction, one NDA/auth gate). The resolver loads and tenant-checks
every target before requesting so a foreign id is rejected before any
access row is written, and echoes the affected nodes so the client
flips each row to pending in place.

Add a styled Base UI Checkbox to the v2 kit, a local selection context
shared by the independent row fragments, and mirror the new selection
strings across all locales.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:20 +02:00
Émile Ré
15b51640d3 Fix geoloc country ip block import script
Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:21:57 +02:00
Émile Ré
10200cb4c0 Update country ip blocks
Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:17:00 +02:00
Cursor Agent
3455784f52 Remove unused uniqueGIDs helper
MergeByCampaignID already dedupes with gid.NewSet.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:37 +00:00
Cursor Agent
9ad52fc27a Fix undefined source in AddCampaignSource
Declare AccessReviewSource before LoadByID so the package compiles
after RemoveCampaignSource cleanup.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:37 +00:00
Cursor Agent
b5574764cf Dedupe campaign source IDs with gid.NewSet
Remove local uniqueGIDs helper in favor of the existing gid set
utility used elsewhere in coredata.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:37 +00:00
Cursor Agent
3b3d7002a9 Drop pre-merge access source count check
Scoped rows in the MERGE desired_sources CTE already limit
snapshots to sources visible under the scoper.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:37 +00:00
Cursor Agent
4d154651a8 Use one path for campaign source merge
Remove early return on empty source IDs; count and MERGE always
run so clearing sources uses NOT MATCHED BY SOURCE delete.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:37 +00:00
Cursor Agent
447bdb88e5 Early-return empty campaign source merge
Delete scoped snapshots in one statement when the desired source
set is empty; validate and merge only when IDs are present.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:37 +00:00
Cursor Agent
abbb1ee875 Merge campaign scope sources in one SQL statement
Add AccessReviewCampaignSources.MergeByCampaignID and use it from
syncCampaignSources instead of per-row load, upsert, and delete.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:36 +00:00
Cursor Agent
f396107090 Drop redundant access source organization checks
Scoped LoadByID already enforces tenant isolation; remove
OrganizationID comparisons against the campaign in create, sync,
add source, and review engine paths.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:36 +00:00
Cursor Agent
6fc3b1e3e3 Remove accessreview Campaign wrapper type
Apply draft and lifecycle checks on loaded coredata records
directly in the campaign service.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:36 +00:00
Cursor Agent
3f545652d5 Use business campaign rules instead of status errors
Introduce accessreview.Campaign with draft/deletable predicates and
operation-specific client errors. Drop errUnlessDraftCampaign and
status-to-sentinel switches in the service layer.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
5dca6bb883 Use struct campaign errors with campaign ID in message
Business-layer errors carry the access review campaign GID in
Error() and match GraphQL sentinels via Is().

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
1422b6d5dd Express campaign client errors in the service layer
Remove status-to-error helpers and map loaded campaign data to
accessreview sentinels at each business rule instead of wrapping
coredata status values.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
09f131087c Map cancel campaign terminal errors to invalid
Return GraphQL invalid when cancel hits completed or cancelled
campaign status sentinels from the service layer.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
352c551e53 Return campaign status sentinels without wrapping
Drop CampaignStatusError from errors.go and map coredata status to
client errors in the service layer only. Cancel on terminal statuses
uses the same sentinels instead of fmt status strings.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
c187ea7124 Remove CampaignStatusErrors slice
List campaign status sentinels explicitly at resolver AnyOf
call sites instead of a shared slice.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
f8dcb6c014 Add errorx.AnyOf for sentinel error checks
Centralize errors.Is OR chains in access review campaign resolvers
and expose CampaignStatusErrors for the four non-draft status
sentinels.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
b3e60da4d5 Use status-specific errors for non-draft campaigns
Replace ErrCampaignCannotStart and ErrCampaignCannotUpdate with
sentinels per campaign status, mapped through CampaignStatusError
and wrapped with operation-specific fmt.Errorf prefixes.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
3d606dd0e8 Replace ErrCampaignNotDraft with operation-specific errors
Use ErrCampaignCannotStart and ErrCampaignCannotUpdate with clear
actionable messages instead of a generic draft-status sentinel
wrapped in noisy fmt.Errorf chains.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
eabd0fb659 Rename ErrCampaignNoSourcesSelected to ErrCampaignMissingSources
The failure is about unconfigured campaign sources, not an empty UI
selection.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
eebc957d36 Treat invalid campaign sources as not found
Drop ErrCampaignSourceOrganizationMismatch. When a source ID is
missing or belongs to another organization, return
coredata.ErrResourceNotFound so clients get a generic not-found
response instead of leaking cross-organization details.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
1dcfa31dab Rename ErrCampaignNoScopeSources to ErrCampaignNoSourcesSelected
Align the sentinel name with the validation it represents.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
0870e1dd15 Use sentinel errors for campaign validation failures
Follow the cookiebanner pattern: grouped var Err* sentinels in the
service package, wrapped with fmt.Errorf where context is needed, and
explicit errors.Is checks in GraphQL resolvers.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
a2b29b3d80 Use typed campaign errors instead of string matching
Introduce sentinel and structured errors for access review campaign
validation failures, and map them to INVALID in GraphQL resolvers via
errors.Is rather than matching error message prefixes.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:07 +00:00
Cursor Agent
ffaf637397 Let n8n create and update campaigns with scope sources
Replace the separate Add Source operation with multi-select source
fields on create and update. Create passes accessReviewSourceIds to
the existing GraphQL input; update gains the same omittable field and
backend source sync so workflows can configure sources in one step.

Load source options from the organization in the n8n UI, and keep
surfacing INVALID errors when start fails for missing sources.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:06 +00:00
Cursor Agent
2d93b1d793 Add scope source operation to access review n8n node
Campaigns cannot be started without at least one scope source, but the
n8n node had no way to attach sources after creation. Expose the
addAccessReviewCampaignSource mutation as an Add Source operation so
workflows can configure sources before starting.

Return INVALID instead of INTERNAL when start fails due to missing
sources or invalid status, so n8n surfaces the real error message.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 15:56:06 +00:00
Sacha Al Himdani
d61ec8dd65 Add search and status/role/type filters to People
Makes it practical to find people in larger orgs across GraphQL, MCP, CLI, and n8n, with page size raised to 100.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-27 17:20:18 +02:00
Sacha Al Himdani
edb67743ae Limit third party selectors to first-level parties
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-27 17:18:01 +02:00
Sacha Al Himdani
5c9c9e3888 Fix npm audit findings in postcss and react-router
Bump postcss to 8.5.23 and react-router to 8.3.0 to clear their high-severity advisories. Leave nested brace-expansion issues for a follow-up that won't break older minimatch consumers.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-27 17:07:59 +02:00
Bryan Frimin
308b18dd10 Release probod/v0.236.0 2026-07-27 14:36:59 +02:00
Cursor Agent
51144d25fc Add Risk Accepted status to finding forms
Findings create and update views filtered out RISK_ACCEPTED
even though the API requires a linked risk for that status.
Restore the option, collect riskId via a searchable paginated
picker, and clear stale links when status changes.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-27 14:14:43 +02:00