Commit Graph

1761 Commits

Author SHA1 Message Date
Sacha Al Himdani
e8e5e9bf9d Show missing OAuth scopes after connector reconnect
Partial grants completed without feedback, leaving Reconnect
required unexplained. Keep the token and toast the backend
missing-scopes error after the OAuth callback redirect.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-31 15:32:45 +02:00
Émile Ré
afdf0aacc7 Show locale mismatch banner for visitors
Visitors have no Identity.locale, so the banner now falls
back to a supported navigator language match and omits the
persist action. Unsupported browser languages stay silent
instead of pretending English is preferred.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-31 11:53:58 +02:00
Ludovic Vielle
2f81b69ad1 Fix manual agent install download instructions
Repo-wide /releases/latest pointed at the wrong
assets when other tracks published more recently.
Point users at probo-agent/v* releases and split
download vs enroll into separate copy blocks with
placeholder URLs they fill in.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-31 11:08:23 +02:00
Émile Ré
4d8d26aad2 Split Link/Anchor from button navigators
Rename button-styled Link/Anchor to ButtonLink/
ButtonAnchor and add underlined text Link/Anchor
so names match look and element. Hero meta uses
plain Anchors for contact and custom links.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-31 10:59:20 +02:00
Émile Ré
93818d8292 Polish portal banner actions and alignment
Prefer the saved locale as the primary CTA, soften secondary
and NDA actions, tint dismiss hovers to the banner palette,
and center the leading icon with the message.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:28 +02:00
Émile Ré
2c52360bd6 Use Sign for the NDA page CTA
The button is on the review page itself, so Review and sign
is redundant. Console keeps its own reviewAndSign key.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:28 +02:00
Émile Ré
404b9e347a Extract shared Banner for portal notices
Locale and NDA notices shared layout chrome but were not kit
Callouts. Pull the full-bleed band into Banner and rename the
feature wrappers so the names match the role.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:28 +02:00
Émile Ré
51ba02cedd Differentiate portal callout colors and width
When both banners stack they read as one band if they share
gold. Use sky (info) for locale and amber (warning) for NDA,
and keep content inside the same max-w-5xl column as TopBar.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:28 +02:00
Émile Ré
1e8690aaae Extract locale mismatch callout variants
Match the unsigned-NDA banner layout: keep layout classes in
tv slots so the callout shell stays free of raw utilities.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:27 +02:00
Émile Ré
7f7c836e57 Show unsigned NDA banner in the portal shell
Signed-in users with an incomplete portal NDA need a clear
path to review and sign without waiting for a private
document export to fail the gate.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:27 +02:00
Émile Ré
312cb67106 Add Documents back link on the NDA gate
Match the document viewer header so users can leave without
signing, returning to the list instead of the continue URL
that would re-trigger the gate.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:27 +02:00
Émile Ré
c96bf22e1c Handle auth gates in every portal mutation
Mutations never reach route error boundaries, so each call
site reimplemented sign-in / full-name / NDA redirects.
Consume those gates in the shared useMutation notifier and
drop the duplicated handlers.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:27 +02:00
Émile Ré
693ee7002b Redirect viewer export to the NDA gate
Document export is a mutation, so NDA_SIGNATURE_REQUIRED never
reaches the route boundary. Catch it in the export hook, stop
re-firing on mutate identity churn, and match gate errors by
name when instanceof fails across package copies.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:26 +02:00
Ludovic Vielle
7731566c68 Add soft delete for revoked devices
Admins could only revoke devices, so never-enrolled and revoked
inventory rows piled up with no way to remove them. Soft-delete
is limited to REVOKED devices (revoke first), and ITAM GC now
hard-deletes PENDING/REVOKED orphans with no API key, postures,
or valid enrollment token—including user tombstones without
history.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-30 16:34:16 +02:00
Sacha Al Himdani
573549fcec Show reconnect when access-review connectors need new OAuth scopes
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-30 15:43:47 +02:00
Cursor Agent
5cd407bd86 Emit audit and SCIM log exports as CSV
JSONL was awkward in spreadsheets and SIEM imports. Write
tab-separated-friendly CSV with organization name on every row,
resolve audit actors to email or API key name, and enrich SCIM rows
with profile email and display name when available.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-30 10:12:47 +00:00
Émile Ré
b3cf6d909b Improve people list filters and invite state
Replace the cramped status checkboxes with a multi-select
dropdown (new DropdownCheckboxItem), and update the Relay
store to PENDING when an activation email is sent so the
row reflects the server-side state change immediately.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 09:19:42 +02:00
Émile Ré
bb16be8d17 Cancel pending people search on filter change
A debounced search could fire after status, role, kind, or sort
changed and refetch with the previous filter values, briefly
reverting the list. Cancel the pending callback before those
immediate refetches so the latest filters stick.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 09:19:42 +02:00
Émile Ré
eecf8a1d97 Make profile state filters multi-value
Address PR review feedback on the profile-state split: SAML sign-in now
activates a pending profile, deactivation counts owners against the
profile's own organization to close a last-owner bypass, the migration
leaves historical activated_at/deactivated_at NULL rather than
fabricating timestamps, and pending members are no longer rendered with
the deactivated (faded) styling.

Drop the single-value state filter in favor of the multi-value states
across the profile and signatory surfaces. Remove ProfileFilter.state
(only states[] remains) and convert the signatures profileState filter
to profileStates. Turn the console people filter, the CLI
"user list --state" flag, and the n8n listUsers and getAllSignatures
state inputs into multi-select controls, where an empty selection means
all states.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 09:19:42 +02:00
Émile Ré
b10fc55b7f Rename user archive action to deactivate
"Archive" was misleading for users: the action sets a profile to
DEACTIVATED while keeping the person in the organization. Rename it to
"deactivate" across the API, CLI, MCP, n8n, and console UI.

Consolidate the two overlapping operations into a single deactivateUser
backed by the fuller, guarded logic (SCIM guard, last-active-owner
guard, invitation expiry, signature cancellation, membership update,
webhook) and authorized via iam:membership-profile:deactivate. Remove
the archiveUser surface and the thin state-only deactivate path.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 09:19:42 +02:00
Émile Ré
99c3235b46 Exclude deactivated owners from asset table picker
The inline owner picker on the assets table queried people without a
state filter, so deactivated profiles remained selectable as owners.
Restrict it to ACTIVE and PENDING to match the other owner pickers,
keeping pending members assignable while dropping deactivated ones.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 09:19:42 +02:00
Émile Ré
4a276e3ef7 Split inactive profile state
Replace the binary profile ACTIVE/INACTIVE model with PENDING, ACTIVE,
and DEACTIVATED so invited-but-not-yet-activated members remain
assignable to assets, data, and risks instead of being treated like
deactivated users.

Add activated_at/deactivated_at timestamps and Mark* lifecycle helpers,
and update every transition (create, invite/re-invite, activation,
archive, SCIM, SAML, sessions, compliance-portal grant) to the new
states. Expose a multi-state states[] filter across coredata, GraphQL,
MCP, and the console owner pickers, which now request ACTIVE and
PENDING members.

A migration renames the membership_state enum, classifies existing
inactive profiles as PENDING from recent invitation activity, and
backfills the new timestamp columns.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 09:19:42 +02:00
Sacha Al Himdani
cd6c46212a Add log export for audit logs and SCIM events
Route audit-log and SCIM-event exports through export_jobs with typed
arguments, an iam BuildAndUploadExport/SendExportEmail implementation,
and a concurrent export-job worker with stale recovery. Stream JSONL via
page.WalkAll into S3, and expose the request flow on console, connect,
MCP, and CLI.

Co-authored-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-29 18:57:31 +02:00
Émile Ré
b2e2d15582 Share copy-link helper and fix UK plurals
List rows and the viewer toolbar used the same clipboard
toast path; Ukrainian moreRegions needs one/few/many forms.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
b0ad5796b6 Portal drawer selects onto the viewport
The swipe Popup keeps a CSS transform that re-roots
position:fixed, so Base UI's modal inert cutout missed
the locale trigger and blocked hover and clicks.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
72ca18e204 Extract document viewer toolbar component
Keeps DocumentViewer focused on layout and preview state, and
gives the page/zoom/copy/download chrome its own home.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
e9d0825b5e Keep document title on locked viewer
Unauthorized visitors still need the document identity and a
way back to the list; only the preview toolbar is withheld,
with the access CTA replacing the file body.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
98e1177aab Label document share as copy link
Sharing only copies the viewer URL, so rename the action and
expose the same control on each documents list row.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
5469a960e2 Truncate long country lists with a popover
AWS-scale region lists blew out subprocessor cards. Cap the
visible labels and open the rest from a +N trigger using a
new Base UI Popover in the v2 kit.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
69721c6afd Stretch Trusted by tiles to equal row height
When a reference name wraps to two lines, sibling cards in the
same grid row stayed shorter because MediaTile only sized to its
content. Fill the grid cell and grow the caption so peers match.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:54 +02:00
Émile Ré
39d5c58f20 Proxy compliance portal API paths in Vite
Vite only forwarded /graphql, so /initiate?continue=… fell through
to the SPA and the locale loader rewrote it to /en/initiate.
Match the host-root API routes (including query strings) so local
OAuth hits the Go backend.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:54 +02:00
Émile Ré
1d19879b51 Add in-tab display mode toggle for users
Let signed-in visitors override the OS color scheme from
the account menu without persisting across reloads, and
keep themed logos in sync with the effective mode.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:54 +02:00
Émile Ré
7c6ab85916 Stack TopBar brand and shorten nav labels
Long nav copy was squeezing the entity name into an
ellipsis inside max-w-5xl. Stack name over the tagline,
hide brand text below lg, and shorten the longest
topBar.nav strings so the brand stays readable.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:54 +02:00
Émile Ré
b1b23988fc Show locale code in guest language select
Full language names (e.g. Bahasa Indonesia) made the
guest top-bar control too wide next to Get access.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:54 +02:00
Cursor Agent
6cbfe7e755 Sync console document lang with i18next locale
Static lang=\"en\" in index.html left French UI declared as English
for assistive tech. Mirror the compliance portal by updating
document.documentElement.lang on init and when the locale changes.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-29 16:39:58 +00:00
Cursor Agent
b229da0115 Block delete for in-progress access review campaigns
Reject deletion while a campaign is fetching sources so workers are
not racing a removed record. All other statuses remain deletable.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-29 16:02:26 +00:00
Cursor Agent
b156b0333a Allow deleting access review campaigns in any status
Drop the backend status gate on campaign delete and show delete in
the console whenever the user has delete permission, regardless of
whether the campaign is draft, in progress, or completed.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-29 16:02:26 +00:00
Cursor Agent
9c1cecfc1e Allow deleting completed access review campaigns
Completed campaigns were immutable because delete only accepted draft
or cancelled status. Extend deletion to completed records and surface
delete in the console for that status.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-29 16:02:26 +00:00
Ludovic Vielle
ad615a47a0 Show posture values and report history
Pass/fail was the main device UI signal, but operators need
the agent's observed value. Expose a formatted value per
check, show current postures on the device page, and replace
the Postures tab with paginated report history grouped by
agent push time. Status stays in the model for later rulesets.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-29 16:27:23 +02:00
Cursor Agent
fe215efbd1 Add audit start and end dates to audits
ISO audits often span a window distinct from certificate validity.
Store optional audit_start_date and audit_end_date on the audit
record and expose them through GraphQL, MCP, CLI, n8n, and console.

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

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-28 17:27:33 +02:00
Émile Ré
82a62005f8 Harden email verification resend against abuse
Add a per-address confirmation-email cooldown and disable the
resend/forgot-password submit buttons while the mutation is in
flight so callers cannot flood the mail queue or double-submit.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-28 15:11:06 +02:00
Émile Ré
5d0882778f Gate password sign-in on email verification
Unverified password identities were able to open sessions after
signing out. Reject sign-in with EMAIL_NOT_VERIFIED and add a
resend-confirmation flow so users can complete verification.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-28 15:11:05 +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é
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é
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
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