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>
Inline comments are more targeted than excluding the entire file
from secret scanning. Remove the .trufflehog.yml exclude file and
the --exclude-paths flag from the workflow.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Skip empty fingerprints in SystemPromptLeakGuardrail to prevent blank
values from flagging every message. Replace overly broad "sk-" pattern
in SensitiveDataGuardrail with specific LLM provider prefixes
("sk-proj-" for OpenAI, "sk-ant-" for Anthropic) to avoid false
positives on common words like "risk-based" or "task-management".
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Introduce a pkg/agent/guardrail package with three guardrails that
can be composed into any agent:
- PromptInjectionGuardrail: LLM-based input classifier that detects
prompt injection attempts before the agent processes them.
- SensitiveDataGuardrail: pattern-based output check for leaked
tokens, keys, connection strings, and raw SQL.
- SystemPromptLeakGuardrail: configurable output check that detects
system prompt content in responses using caller-provided
fingerprints.
The classifier prompt is embedded from a plain text file for easy
review and editing.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
When creating an organization with a name that produces a duplicate trust
center slug, the API now returns a Conflict response instead of a
generic Internal error.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
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>
Introduce a rank-style priority on tasks, scoped by
(organization_id, state). New tasks auto-assign the next
priority. Reordering uses the same CTE-based algorithm as
trust center references and compliance external URLs.
Exposed through GraphQL, MCP, and the PRIORITY order field.
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
When a magic link token expires, the user now sees a specific
error message ("This magic link has expired. Please request a
new one.") instead of the generic "Failed to connect" error.
This adds ErrExpiredToken to the IAM error types, checks for
statelesstoken.ErrExpiredToken in both GetMagicLinkEmail and
OpenSessionWithMagicLink, and handles it in the trust resolver
and frontend.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Previously the worker reset failed descriptions back to PENDING,
causing infinite retry loops for permanently broken evidence.
Add a FAILED status so these items stop cycling and can be
investigated.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
GetFileBase64 read the MIME type from the S3 response header,
which can be application/octet-stream for files uploaded without
an explicit content type. Use file.GetMimeType() from the
database instead, which stores the correct MIME type captured
at upload time. This fixes evidence description failures when
calling the OpenAI API with PDF files.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
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>
Trust centers were created without setting SearchEngineIndexing,
defaulting to an empty string in the database. This caused scan
errors when loading trust centers.
Add a migration to fix corrupted rows, set a DEFAULT on the
column, and add a CHECK constraint. Also set the field explicitly
when creating new trust centers.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Introduce dataloadgen-based dataloaders to batch individual
record-by-ID fetches in GraphQL resolvers into single SQL
queries. Each entity type (organization, framework, control,
vendor, document, risk, measure, task, file, report, profile)
gets a LoadByIDs method in coredata and a GetByIDs service
method with variadic arguments and dedicated collection return
types. Resolvers now use dataloader.FromContext instead of
direct service calls for single-record lookups.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
CAA issue records may contain parameters after a semicolon per
RFC 8659 (e.g. "letsencrypt.org; accounturi=..."). Split on ";"
and compare only the issuer domain so these records are accepted.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Before requesting a certificate from the ACME provider, verify
that CAA DNS records for the domain permit issuance by the
configured CA. This avoids wasting ACME attempts on domains
whose CAA policy would reject the request.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Without an explicit AuthStyle, the oauth2 library uses
auto-detection which tries Basic auth first. Microsoft
rejects this, and since PKCE codes are single-use, the
retry with the correct style fails.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
The SCIM client User struct had json:"-" tags on most fields
(GivenName, FamilyName, ExternalID, Department, etc.), so
ListUsers never populated them from the JSON response. The
bridge comparison always saw empty strings on the SCIM side
vs actual values from the provider, making needsUpdate true
for every user on every sync cycle.
Add custom UnmarshalJSON on User to properly parse nested
SCIM JSON (name object, enterprise extension) into the flat
struct, so the existing diff logic correctly skips unchanged
users.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
When CompleteHTTPChallenge fails, the challenge is already marked
invalid by Let's Encrypt. Retrying Accept on the same challenge
always fails with "authorization must be pending". Reset the
domain to pending with cleared challenge data so each retry
creates a new ACME order.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
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>
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>
- 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>
The OIDC provider is already tracked in iam_oidc_states.provider, so
there is no need for provider-specific session auth methods (GOOGLE,
MICROSOFT). Replace them with a single OIDC auth method.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
EnabledProviders() iterated a map, producing nondeterministic order.
Sort the slice before returning to ensure stable UI and test behavior.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Add Google and Microsoft sign-in buttons to the trust center connect
page, matching the console sign-in experience. The backend OIDC flow
already supports flexible continue URLs, so only the GraphQL schema
and frontend needed changes.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
- 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>
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>
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>
When an email has a sender name set (the organization name), the
mailer composes the From header as "OrgName via Probo" instead of
the default global sender name. This gives compliance page
recipients clearer context about which organization is contacting
them.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
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>
The export endpoint was hardcoding application/pdf for all trust center
files. Now the real MIME type from the stored file metadata is threaded
through the service layer and returned as a data URI, so non-PDF files
are handled correctly on the frontend. Watermarking is only applied when
the file is actually a PDF.
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Adds has_report, report_filename, and report_mime_type fields to Audit type to expose report attachment status. Introduces new getAuditReportUrl tool to generate presigned download URLs for audit reports. Updates NewAudit type converter to accept optional report object for enriching metadata.
Signed-off-by: Bryan Frimin <bryan@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>
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>