Clarify that indexes should not be added speculatively and
should only be introduced when justified by production query
latency. Also document that columns should avoid DEFAULT
clauses, with guidance on backfilling non-nullable columns.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Private items should still be listed on the compliance page — only
items with visibility "NONE" should be excluded. Also add missing
trailing newline in the template file.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
The fetch helpers silently swallowed pagination/list errors by breaking
out of the loop, which could return a successful response with
incomplete compliance data. Return errors instead.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Pipe characters and newlines in dynamic values break Markdown table
structure. Add a cell template function that escapes these characters.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Renders compliance data (frameworks, documents, audits, subprocessors, references, and external links) as a plain-text Markdown document. The endpoint supports all required visibility filters and pagination.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
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>
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>
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>
Source a gitignored .sandbox.env file (if present) before running
probod-bootstrap so each developer can inject their own secrets
(SSO, API keys, etc.) without committing them to the repo.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Avoid platform conflicts between macOS host and Linux VM by
bind-mounting a VM-local directory over /workspace/node_modules.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Remove !queryRef guard and add proper dependency arrays so queries
refetch when organizationId or meetingId changes.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
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>
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>
- 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>
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>
Use baseurl.Parse to construct the HTTPS redirect URL in the
trust center HTTP handler, breaking the taint chain from raw
request headers. Apply path.Clean to the slug-based redirect
in stripTrustPrefix to normalize path traversal sequences.
Addresses CodeQL go/unvalidated-url-redirection (CWE-601).
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
Adds go-fmt and go-fix Makefile targets that fail when gofmt or go fix
suggest changes. Both are wired into the lint target and used in CI.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
The SAML Assertion Consumer Service endpoint receives cross-origin POSTs from external identity providers by design. Bypass CSRF protection for this specific endpoint since the endpoint validates SAML response signatures itself.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
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>
The pg_advisory_xact_lock inside the WITH clause caused race conditions
in READ COMMITTED mode. When a transaction blocked on the lock and resumed
after acquiring it, it used a stale snapshot and computed the same reference
ID as the previous transaction, violating the unique constraint. Moving the
lock to a separate statement before the INSERT ensures the snapshot includes
all previously committed data.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
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>
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>
CountByRiskID and CountByControlID CTEs did not include m.category in their SELECT
lists, causing "column category does not exist" errors when MeasureFilter applied
category constraints. Added m.category to both CTEs.
Also add comprehensive e2e tests for measure filtering by category at organization,
risk, and control levels.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
The CountActiveOwnerByOrganizationID query joins iam_membership_profiles with
iam_memberships, but used an unqualified tenant_id = @tenant_id in the WHERE
clause. Since both tables have a tenant_id column, PostgreSQL raised an
"ambiguous column" error when deleting an owner. Fixed by prefixing with the
table alias (p.tenant_id) to match the pattern used in CountByOrganizationID.
Added TestUser_RemoveOwner e2e test to verify one owner can remove another.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Increase sleep time from 10ms to 1100ms to ensure timestamp precision works
consistently across databases with second-level granularity. Strengthen
AssertTimestampsOnUpdate to require strictly increasing timestamps instead of
allowing equal values.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
When creating an organization, the owner's membership profile was being set with the organization name as the full name instead of the owner's actual full name. Fetch the identity's full name and use it for the profile.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Enforce minimum (25) and maximum (100) bounds on cursor size to prevent negative values or excessively large page sizes. All three API surfaces (GraphQL, MCP, CLI) funnel through NewCursor, so the fix belongs here.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
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>
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>
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>
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>
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>