Commit Graph

1122 Commits

Author SHA1 Message Date
Sacha Al Himdani
0920690816 Add ability to disconnect Slack channel from compliance page
Users could connect a Slack channel to their compliance page but had no
way to remove or change the connection afterward. This adds a disconnect
button with a confirmation dialog next to connected Slack channels.

- GraphQL: deleteSlackConnection mutation with resolver
- Frontend: Disconnect button using useMutation with @deleteEdge

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-03-30 15:40:21 +02:00
Sacha Al Himdani
999171a626 Add document approval workflow
Introduce a complete approval system for document publishing. Document
versions can now require approval from selected reviewers before being
published, with automatic publishing once all approvers have approved.

- Add approval quorum and decision tables with backfill migration
- Implement request approval, approve, and reject flows with electronic
  signature support for approve decisions
- Add employee approvals page with dedicated tab and pending approvals view
- Add changelog field to publish and request approval flows
- Pre-select previous version's approvers in the publish dialog
- Show quorum approvers in document list with 100 approver hard limit
- Expose approval workflow through GraphQL, MCP, and CLI
- Remove legacy default approvers feature entirely
- Add comprehensive e2e test coverage for approval workflows

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-03-27 19:43:20 +01:00
Sacha Al Himdani
4a2d308da0 Add task drag-and-drop reordering
Order tasks by priority (ASC) by default. Enable drag-and-drop
on the TODO and DONE tabs using native HTML5 drag events,
following the compliance external URLs pattern. The "All" tab
remains read-only since priority is scoped per state.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-03-27 15:47:12 +01:00
Bryan Frimin
619ec7b882 Add AI-powered evidence description generation
Introduce a background worker that automatically generates
compliance-focused descriptions for uploaded evidence files
using configurable LLM providers. Descriptions are surfaced
across all interfaces: GraphQL API, MCP API, CLI, and the
console UI.

Key changes:
- Multi-provider LLM config with per-agent settings (pointer
  types for Temperature/MaxTokens to preserve zero values)
- Evidence description worker with bounded concurrency
- EvidenceDescriptionStatus typed enum with PostgreSQL enum type
- New `prb evidence` CLI commands (list, view, delete)
- Evidence description displayed in console table and preview
- Migration only marks evidences without files as completed

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-26 14:32:41 +01:00
Bryan Frimin
8bbed534a9 Fix batch signature dialog wording
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-26 11:25:57 +01:00
Sacha Al Himdani
a3580a5647 Treat ESLint warnings as errors in all packages
Add --max-warnings 0 to every eslint lint script so that any warning
causes a non-zero exit code. This makes `make lint` and CI fail on
warnings, not just hard errors.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-03-26 10:47:33 +01:00
Sacha Al Himdani
93c3b70ecc Fix frontend lint warnings in documents and references
- Remove unused `rank` field from CompliancePageReferenceListItemFragment;
  the parent list fragment already fetches it for drag-and-drop reordering.
  Thread `rank` through the onEdit call chain so the edit dialog can still
  pre-populate the field via a dedicated parameter instead of the fragment.
- Add missing `documentTypeFilter` dependency to the refetch useEffect in
  DocumentList so stale closure values are never used on tab change.
- Break overlong line in DocumentList (canSendAnySignatureNotifications).

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-03-26 10:47:33 +01:00
Sacha Al Himdani
8c02c53315 Update copyright headers across all Go files
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-03-25 17:38:32 +01:00
Bryan Frimin
81a4ec7c6e Remove useless card
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-25 08:19:28 +01:00
Bryan Frimin
784c88895a Allow editing non-SCIM fields on SCIM-managed profiles
Contract start and end dates are never synced by SCIM, so they
should remain editable even when a profile is SCIM-managed.
The backend now skips overwriting SCIM-synced fields (fullName,
kind, position, additionalEmailAddresses) for SCIM profiles,
and the frontend disables only those fields instead of the
entire form.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-24 16:44:53 +01:00
Bryan Frimin
359f85f5da Add SEO controls and sitemap for compliance pages
Add search engine indexing toggle, robots.txt, and sitemap.xml
generation for compliance pages. Replace checkboxes with toggle
components in the compliance page UI and add an "Open" button
in the page header to quickly access the live compliance page.
The search engine indexing toggle is disabled when the compliance
page is inactive.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-24 15:55:31 +01:00
Bryan Frimin
87c7552a35 Replace inline password form with link to dedicated sign-in page
The SignInPage now shows OIDC, SSO, and email buttons instead of
embedding the email/password form directly. Users clicking "Sign in
with email" are taken to the existing PasswordSignInPage.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:46 +01:00
Bryan Frimin
d05367eeb2 Style
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:46 +01:00
Bryan Frimin
887e994ff1 Refactor OIDC buttons: extract OIDCButton component, inline loops
Address PR review feedback:
- Remove OIDCButtons wrapper components that only loop, inline .map()
  directly in SignInPage and ConnectPage
- OIDCButton uses useTranslate() and useSafeContinueUrl() hooks
  internally instead of receiving hook results as props
- Move OIDCButton to local _components folders
- Fix eslint import grouping in SignInPage

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:46 +01:00
Bryan Frimin
0476cd2d87 Use preloaded query for SignInPage instead of lazy load
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:46 +01:00
Bryan Frimin
42129f7ce2 Restore inline password form in SignInPage
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:45 +01:00
Bryan Frimin
dcc08c42e3 Fix lint errors in SignInPage: use Relay fragment for OIDC providers
- Add blank line between import groups (import-x/order)
- Use Relay fragment in OIDCButtons to colocate field queries (relay/unused-fields)

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:45 +01:00
Bryan Frimin
f8e086a00b Address PR review feedback for OIDC sign-in pages
- Remove inline password form from SignInPage (use PasswordSignInPage)
- Extract Divider and OIDCButtons to _components folder
- Move OIDC providers into page queries instead of lazy-loaded queries
- Create useSafeContinueUrl hook for trust app using getPathPrefix
- Use safeContinueUrl.toString() for continue URL parameter
- Fix wg.Go style in IAM service Run method

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:44 +01:00
Bryan Frimin
29b41208f3 Address PR review feedback for OIDC login
- Remove sensitive nonce values from error messages to prevent logging leaks
- Guard ticker intervals against non-positive durations in SAML domain
  verifier and garbage collector to prevent panics
- Require both client ID and client secret for Google/Microsoft OIDC
  providers to be marked as enabled
- Replace http.DefaultClient with kit/httpclient for JWKS fetching to
  ensure proper timeouts
- Fix eslint indentation in SignInPage OIDC button click handler

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:43 +01:00
Bryan Frimin
3066e7d14c Fix eslint errors in sign-in page
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:43 +01:00
Bryan Frimin
83468db034 Refactor sign-in page and IAM service lifecycle
Redesign the sign-in page to show email/password form inline
with OIDC provider buttons (with vendor icons) instead of
separate pages. Extract OIDCProvider type to its own file.

Replace errgroup with sync.WaitGroup + WithCancelCause for
graceful shutdown in IAM services. Refactor garbage collectors
to use functional options and time.Ticker instead of
time.After to avoid repeated allocations.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:43 +01:00
Bryan Frimin
23084a72a2 Add OIDC login support for Google and Microsoft providers
Implements OpenID Connect authentication flow with PKCE, JWT verification, and enterprise-only account restrictions. Adds OIDC service with JWKS caching and state management, HTTP handlers for login/callback flows, GraphQL query for available providers, and sign-in UI integration.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-23 14:17:43 +01:00
Bryan Frimin
3b5122da5e Style
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-21 19:16:21 +01:00
Bryan Frimin
7b320916af Add audit log feature for recording all actions
Adds audit logging that records all authorized actions performed by
users and API keys. The audit log is automatically populated whenever
the authorizer approves an action, and is queryable via GraphQL, MCP,
and CLI interfaces. Permission checks are excluded via a dry-run flag
to avoid phantom entries on page loads.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-21 19:16:19 +01:00
Bryan Frimin
fce754cff4 Fix measure category filter not applying on initial page load
When navigating back to the measures page with a ?category query parameter, the filter wasn't applied to the initial Relay query. The component state was initialized from the URL, but the Relay fragment loaded with its default category: null. Add a mount effect that triggers a refetch with the initial category parameter.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-20 11:46:52 +01:00
Bryan Frimin
19eb2f5d84 Add formal consent disclaimer when skipping confirmation email
Display a legal notice requiring the operator to certify they have
obtained verifiable prior consent (GDPR, CAN-SPAM) before bypassing
the confirmation email flow.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-20 09:54:28 +01:00
Bryan Frimin
c5589793da Allow skipping confirmation email when adding mailing list subscribers
When creating a new subscriber, operators can now check "Skip confirmation email" if they already have the recipient's consent. This creates the subscriber in confirmed status and skips sending the notification email.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-20 09:54:25 +01:00
Bryan Frimin
bedfd61168 Rename Vendor to Subprocessor in trust API surface
Rename Vendor → Subprocessor, VendorConnection → SubprocessorConnection, and VendorEdge → SubprocessorEdge across the GraphQL schema, Go resolvers, and React frontend components. Internal coredata types remain unchanged. User-facing labels in console app updated to reflect terminology change.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-20 09:52:37 +01:00
Bryan Frimin
f756b7273d Paginate findings and obligations 500 by 500
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 23:57:12 +01:00
Bryan Frimin
a7319e54a1 Paginate measures 500 by 500 instead of 100 by 100
Increase MaxCursorSize from 100 to 500 to allow larger page sizes, and set the measures list frontend query to fetch 500 items per page by default.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 23:55:50 +01:00
Bryan Frimin
a1f8f01165 Fix query loaders to reload on parameter changes
Remove !queryRef guard and add proper dependency arrays so queries
refetch when organizationId or meetingId changes.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 19:02:51 +01:00
Bryan Frimin
89882d368c Rewrite context routes to use useQueryLoader pattern
Replace loaderFromQueryLoader/loadQuery in route definitions with
useQueryLoader inside dedicated Loader components, matching the
compliance-page pattern. Use index routes instead of redirect hacks.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 19:02:51 +01:00
Bryan Frimin
e1133b1e9a Access context fields explicitly to satisfy relay/unused-fields lint
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 19:02:50 +01:00
Bryan Frimin
a9ebeef0fa Transform meetings page into context page with tabs
Add structured organization context with 5 markdown sections (Product, Architecture, Team, Processes, Customers) editable inline. Meetings are now a tab within the context page. Moved all GraphQL queries from hooks/graph/MeetingGraph.ts into colocated components following new best practices. Updated database schema, backend services, GraphQL resolvers, and MCP API to support the new context fields and structure.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 19:02:50 +01:00
Bryan Frimin
c2a1843c67 Address PR review comments
- Fix import order: react-relay before react-router
- Add parentheses around arrow function parameter
- Sync category filter with URL param changes, not just on mount

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 18:33:43 +01:00
Bryan Frimin
ad7a3ecbe9 Fix measure breadcrumb category filter
When clicking a category name in the measure detail breadcrumb, users should be taken back to the measures list with that category filtered. Previously, the breadcrumb linked to a route that wasn't read by the measures page.

Changed the breadcrumb to use a ?category search param instead of a route segment, and updated the measures page to initialize and sync its category filter from the URL. Removed the now-unused category/:categoryId route.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 18:33:41 +01:00
Sacha Al Himdani
a5dc9a13ad Fix style
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-03-19 14:36:30 +01:00
Sacha Al Himdani
1db8e7133e Add document archiving
Documents can be archived and unarchived. Archived documents are
read-only, excluded from the trust center, and moved to a dedicated
Archived tab in the document list.

- Add archived_at timestamp and status (ACTIVE/ARCHIVED) PG enum column
- Rename DocumentStatus → DocumentVersionStatus, introduce DocumentStatus
- Archive/unarchive mutations in GraphQL, MCP, and CLI
- Bulk archive/unarchive mutations with Active/Archived tabs in the list
- ABAC policies: write actions denied on archived docs, unarchive denied
  on active docs
- Remove control/risk mappings and reset trust center visibility on archive
- Exclude archived documents from mapping dialogs and trust center tab

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-03-19 14:15:54 +01:00
Bryan Frimin
a6c88c9631 Add fulltext search to measures page
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 12:36:51 +01:00
Bryan Frimin
c3be391e9d Fix DocumentList: clear selection on filter change, update connection ID, fix indentation
Addresses PR review comments: clears selected document IDs when changing
the type filter to prevent bulk actions on hidden rows, updates the Relay
connection ID when the filter changes so mutations target the correct
connection, and fixes eslint indentation violations.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 12:31:41 +01:00
Bryan Frimin
4f54241382 Add document types filtering and rename ISMS to GOVERNANCE
Adds 5 new document types (PLAN, REGISTER, RECORD, REPORT, TEMPLATE), renames ISMS to GOVERNANCE, and implements type-based filtering across GraphQL, MCP, and frontend. Includes migration, enum updates, filter implementation with SQL array support, and frontend dropdown UI with Relay refetch pattern.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 12:31:39 +01:00
Bryan Frimin
d7c120c144 Rename NONCONFORMITY to MINOR_NONCONFORMITY and add MAJOR_NONCONFORMITY
Support distinguishing between minor and major non-conformities in findings. Rename the existing NONCONFORMITY enum value to MINOR_NONCONFORMITY and add a new MAJOR_NONCONFORMITY value across all API layers (GraphQL, MCP, CLI) and the database.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 10:02:28 +01:00
Bryan Frimin
a46366fad4 Style
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 09:54:35 +01:00
Bryan Frimin
82f241628c Refactor MeasuresPage to use Relay fragments
Replace the client-side grouped-by-category view (fetching 500 items)
with a flat table using server-side filtering and cursor-based
pagination. Colocate GraphQL queries, fragments, and mutations in the
component file per console CLAUDE.md conventions.

Backend changes add a category filter to the measure list endpoints
(GraphQL, MCP) and a new measureCategories field on Organization.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 09:54:33 +01:00
Bryan Frimin
32cc4a4f9c WIP
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 09:39:39 +01:00
Bryan Frimin
239f201a93 Restore missing useState import in AuditsPage
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 09:39:38 +01:00
Bryan Frimin
5c42d2e9ba Simplify dropzone overlay to use fixed positioning without portal
Remove createPortal and main element ref/state in favor of a simple
fixed overlay with top-12 offset. This avoids React 19 strict mode
violations around ref access during render and setState in effects.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 09:39:38 +01:00
Bryan Frimin
6eebfa11ef Use state instead of ref for main element portal target
Replace mainRef with useState to avoid accessing ref.current during
render, which is forbidden by React 19's strict ref rules.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 09:39:38 +01:00
Bryan Frimin
f89fdc02b1 Clean up main element style on unmount in AuditsPage
Add cleanup function to the useEffect that sets position: relative on
the main element, so the style is restored when the component unmounts.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 09:39:37 +01:00
Bryan Frimin
44cc650af2 Fix dragCounterRef going negative in audit list dropzone
Clamp the counter with Math.max(0, ...) and use <= 0 check to prevent
the drag overlay from getting stuck when dragLeave fires more than
dragEnter.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-19 09:39:37 +01:00