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>
Signed-in users should browse the compliance portal the
same way visitors do. Keep @nda on export and access
mutations so signatures are only required when loading a
document.
Signed-off-by: Émile Ré <emile@probo.com>
Delete and DeleteExpired omitted Scoper, breaking the
tenant-isolation pattern used elsewhere in coredata. Pass a
tenant scope from ExchangeEnrollmentToken and NewNoScope from
the ITAM GC so cross-tenant cleanup stays explicit.
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
Reminders that fall due on Saturday or Sunday no longer send
over the weekend or spend the escalation ladder unused. SQL
keeps calendar cadence and rolls weekend due times to Monday
at the same clock hour. The first debounced notice is unchanged.
Co-authored-by: Sacha Al Himdani <sacha@probo.com>
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
ITAM GraphQL actions were never registered in the shared OAuth2
scope registry, so bearer-token callers failed closed even when
role policies allowed them. Add v1:itam / v1:itam:read mappings,
register them in probod, and sync the CLI client scopes.
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
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>
Omit level to return direct third parties; pass level to filter
by hierarchy depth. Documented on the tool and filter field.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
Bump transitive brace-expansion to patched releases (5.0.9 / 2.1.3 / 1.1.17) so expand() cannot OOM the process on crafted brace patterns.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
LoadExistingByIDs scanned into MembershipProfile without
activated_at/deactivated_at after the profile-state split, so
SCIM_EVENT CSV exports failed collecting rows by ID.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
WriteRow was a variadic alias for Write(SanitizeRecord(...))
with no extra safety or column checks. Export call sites already
use []string headers; matching encoding/csv keeps one API surface.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
SCIM events store user_name, not identity_id; profile GIDs
in /Users/{id} paths drive LoadExistingByIDs and identity
email lookup instead of batching by user_name.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Email comes from identity when a profile matches; empty
email only when the event has no profile row to join.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Drop the doc-only source file; keep export guidance on the
main Writer entry point.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Trim-based formula detection skipped the old rule for
leading control characters; check those bytes before trim.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Ignore leading Unicode space when detecting formula cells,
extend starter runes, and document export usage in package
doc.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Wrap encoding/csv with formula-safe cell sanitization and
use it from log export streaming.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Load SCIM profile emails via Identities in the export
layer, drop the cross-table join, sanitize formula-leading
cells, and fall back to validated userName when profile email
is missing. Drop redundant gid array casts in LoadByIDs.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Replace full Identity and PersonalAPIKey batch loads with
rows that select only id, email, name fields used in export.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
The batch loader no longer scans into MembershipProfile with
placeholder email and organization name columns from dropped
identity and organization joins.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
ANY(@ids) with an empty array is valid in Postgres and
CollectRows already yields an empty slice; the early nil
assignments added noise without changing callers.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
WalkAll now accepts loaders and callbacks typed as S ~[]T so
exports can use AuditLogEntries and SCIMEvents directly. Pass the
trimmed page slice to walk, not the over-fetched loader result.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Audit exports no longer emit a metadata JSON column. SCIM full
names come only from membership profiles, not request bodies.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
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>
Unsigned darwin release tarballs replaced the Developer ID
binary on each auto-update, so Background Task Management
treated every release as a new identity and showed the generic
executable icon. Sign those archives with a stable identifier,
refuse signature downgrades, and attribute daemon/tray jobs to
Probo Agent.app via AssociatedBundleIdentifiers.
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
Main renamed archiveUser to deactivateUser; keep the new name and
set its title and full annotation hints.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Pick up mcpgen main so go generate emits tool titles and refined
readOnlyHint/destructiveHint annotations from the schema.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Omiting destructiveHint defaults to true in the MCP spec, so reads
must set it explicitly even though the field is only meaningful when
not read-only.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Fill in readonly, destructive, idempotent, and openWorld on every
tool so clients can rely on explicit values instead of MCP defaults
(destructive and openWorld both default to true when omitted).
Drop the temporary mcpgen vendor from this change; that lands in a
separate pull request.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Claude and other MCP clients use title, readOnlyHint, and
destructiveHint to present reads, writes, and deletes accurately.
Add a title to every tool, mark missing delete/unlink/cancel/void
tools as destructive, and teach mcpgen to emit those annotations
(including destructiveHint: false for non-destructive writes).
Temporary third_party/mcpgen fork until title support lands
upstream.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Only the checkbox glyph was dimmed, so disabled options still
looked clickable. Apply data-disabled styles to the whole item
for opacity, cursor, and hover.
Signed-off-by: Émile Ré <emile@probo.com>
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>
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>