Commit Graph

23 Commits

Author SHA1 Message Date
Bryan Frimin
7e0d187dcf Flatten compliance portal package layout
Remove the root complianceportal package and the resolver
facade that existed only to break an IAM import cycle. Admin
policies, domain URL helpers, and actions live under
management; visitor OAuth metadata, brand URLs, and public
read paths live under visitor. Drop the duplicate trust API
magic-link mutations now that Connect handles portal auth, and
stop IAM from owning compliance page email branding.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-21 15:44:20 +02:00
Bryan Frimin
ce1b64b529 Update GraphQL, MCP, and CLI for the portal
Rewire the console and visitor resolvers onto the management and visitor
services with compliance-portal authorization. Rename the GraphQL and MCP
ComplianceExternalURL type to ComplianceCustomLink, expose trust center
profile fields, default and custom domains, public URL, and the managed
flag, and drop the profile fields from the organization surface.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-21 15:44:08 +02:00
Sacha Al Himdani
4c57d201a4 Make license declarations consistently MIT
The source headers, LICENSE files, and license metadata had drifted
apart. Align the entire project to MIT:

- Convert every source-file header to the MIT text across all comment
  styles (Go, TS, TSX, JS, MJS, SQL, CSS, GraphQL, shell), including
  SPDX-License-Identifier tags
- Set the root and cookie-banner LICENSE files to the MIT text with a
  "MIT License" title line
- Switch the package.json license fields, Docker image label, and
  cookie-banner README to MIT
- Update docs and the genmodels header generator accordingly
- Normalize copyright lines to a single format
  (Copyright (c) <year(s)> Probo Inc <hello@probo.com>.): unify the
  hello@getprobo.com and hello@probo.inc emails to hello@probo.com and
  the comma-separated years to a hyphenated range

Genuine third-party references are intentionally left untouched: the
Lucide icon attributions (Lucide is ISC) and the trivy dependency
license allowlist.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-13 16:21:14 +02:00
Aurélien Sibiril
37121e7bac Verify Crisp website ownership before connecting
Crisp is a managed (Model B) connector: Probo holds one plugin token
server-side and each connection carries only a Website ID. Nothing
stops one organization from entering another organization's Website
ID, so prove control of the website before creating the connection.

Probo derives a per-(organization, website) verification code as an
HMAC over the token secret and exposes it through a new
crispVerificationCode query. The customer pastes it into the Probo
plugin's per-website settings; at connect time the resolver reads the
setting back through the managed plugin token and requires a
constant-time match before any row is written. The managed key and
plugin ID come from bootstrap, so the connector stays hidden until the
deployment configures them.

The settings fetch is injected so the create-time gate's branch wiring
is unit-tested (mismatch and not-subscribed reject, internal errors
stay generic, a matching code passes), and the managed-versus-client
key resolution is covered too.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-11 16:50:32 +02:00
Bryan Frimin
bf255b198c Bound GraphQL request cost to prevent alias-flooding DoS
The GraphQL endpoint built its gqlgen server with bare handler.New and
no limits, so a single request with thousands of aliased resolver calls
was parsed, validated, executed, and marshalled in full. Under load this
let an unauthenticated client drive excessive CPU and memory use against
POST /api/connect/v1/graphql and the console and trust endpoints, which
share the same constructor (GHSA-prh2-g8pv-m7p9).

Add configurable guards in the shared gqlutils.NewHandler: a parser
token limit rejects oversized queries at lex time before any execution,
a fixed complexity limit caps field-selection count, an LRU query cache
avoids repeated parsing, and field suggestions are disabled. The limits
flow from a new APIConfig.GraphQL section through server and api config
into all three GraphQL handlers, with PROBOD_API_GRAPHQL_* env vars and
Helm values exposed for per-environment tuning.

Defaults are sized with generous headroom over real traffic: the parser
token limit (15000) and complexity limit (2000) sit far above the
largest legitimate frontend query yet well below the proof-of-concept
flood, so normal usage is unaffected while floods are rejected cheaply.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-30 14:10:41 +02:00
Bryan Frimin
231f7d153e Replace trust center alias with resource alias in console API
Drop the setTrustCenterAlias and removeTrustCenterAlias mutations and
the alias field on Audit in favor of generic setResourceAlias and
removeResourceAlias mutations backed by the resourcealias service.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-22 11:40:10 +02:00
Ludovic Vielle
eccef41767 Adopt File type for trust logos and MCP
Trust GraphQL and MCP still exposed presigned URL strings for
trust-center logos while console and connect already serve stable
File.downloadUrl paths. Phase 1 migrates the seven public logo
fields on trust GraphQL and the trust-center file references on MCP
to the shared File type; trust GraphQL NDA stays on fileUrl for a
follow-up.

Trust resolvers load public files through filemanager and map them
with types.NewFile. The trust app Relay queries and components now
read logo.downloadUrl. MCP specification, resolvers, and helpers
are updated in sync, including NDA on MCP where callers already
have file access.

filemanager is split into focused files and its URL surface is
narrowed to GenerateFileURL(file) for stable app URLs and
GeneratePresignedURL for S3 redirects. GetPublicFile remains the
DB entry point when only a file ID is known.

Add trust and MCP e2e coverage for public logo download URLs.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-11 16:03:45 +02:00
Ludovic Vielle
3f484ac330 Compute stable URL in types.NewFile, wire baseURL into console v1 Resolver
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-10 15:53:35 +02:00
Sacha Al Himdani
9ac71f948f Update contact email to hello@probo.com
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-06-09 16:45:23 +02:00
Bryan Frimin
3dfc833671 Replace supervisor with agentrun worker service
Move agent-run orchestration from the legacy supervisor path into the new
agentrun worker/service package and wire it through coredata, server,
policies, and GraphQL resolvers.

This consolidates run lifecycle handling around lease-aware workers and
aligns API surface with the new agent-run domain model so reviewers can
follow one coherent execution path.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-08 15:27:50 +02:00
Aurélien Sibiril
e18ecdda8b Consolidate connector provider dispatch behind a typed *Registry
The console previously dispatched per-provider logic through a fan of
init()-side-effect maps (driver names, OAuth2 metadata, probe URLs,
display names, settings switches), spread across pkg/connector,
pkg/accessreview/drivers and the console v1 resolvers. Adding a new
provider required edits in every one of those places and a corresponding
switch arm in CreateConnectorRequest. The same per-provider knowledge
also leaked into Helm templates as hand-rolled environment-variable
blocks per connector.

This commit collapses the dispatch surface into a single typed
*provider.Registry. The registry is constructed once by
NewBuiltinRegistry at probod startup and threaded as an explicit
dependency into every consumer (accessreview service, console v1
resolver, OAuth2 wiring). There is no package-level state. Each
provider lives in one file under pkg/connector/provider/ that exposes
a private xxxRegistration() *Registration constructor; NewBuiltinRegistry
enumerates them.

CreateConnectorRequest loses its per-provider settings fields and
takes a single RawSettings json.RawMessage produced by the
per-provider MarshalSettings closure. The 1Password SCIM bridge URL
is validated at create time (http(s) scheme + non-empty host) so a
malformed value fails fast at the resolver boundary. The Helm chart
gains probo.connectorEnv and probo.connectorSecretEntries templates
so adding a connector requires zero Helm changes. Access-review name
resolution moves into the same Registration value to keep one
authoritative dispatch table.

Tests cover every Registration (DisplayName, NewDriver wired),
Register error paths (nil, empty Provider, empty DisplayName,
duplicate), All / ProviderDisplayName / ProviderOAuth2Scopes /
ProbeURL hit and miss paths, the ApplyOAuth2Defaults templating and
PKCE branches, and ConnectorSettings[T] round-trip plus malformed-JSON
error path. The pre-refactor ApplyProviderDefaults test in
pkg/connector is replaced by the equivalent in
pkg/connector/provider.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-27 00:34:39 +02:00
Bryan Frimin
5e9ff656d3 Add per-request Authorize dataloader to console v1
Resolving a typical Console GraphQL query triggers many parallel
authorize calls (one per resource per field resolver). This commit
collapses them via a dataloader: parallel calls within the same
request are gathered into a single iam.Authorizer.AuthorizeMulti pass,
and only fall back to per-item Authorize when AuthorizeMulti rejects
the whole batch (e.g. mixed organizations).

The loader key encodes resource id, action, options, and a canonical
JSON-encoded attribute map so logically identical calls share a key
while differing ones do not. The loader is created without caching so
repeated calls within a request still produce one audit log entry per
call. dataloader.NewAuthorizeFunc preserves the existing
authz.AuthorizeFunc signature and error mapping.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-23 13:31:36 -07:00
Émile Ré
9156d6a16a Add wsl linter and fix
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-20 09:27:28 +04:00
Sacha Al Himdani
b9262b5150 Add risk assessment system
Introduce a hierarchical risk assessment model with six entity types:

- Risk Assessment: top-level container scoped to an organization
- Risk Assessment Scope: sub-container for scoping threat modeling
  exercises within an assessment
- Risk Assessment Node: DFD elements typed as ENTITY, BOUNDARY,
  ASSET, or DATA within a scope
- Risk Assessment Process: directed data flows between two nodes
- Risk Assessment Threat: descriptive threats attached to a process
  with a free-text category (e.g. Confidentiality, Integrity)
- Risk Scenario: thin join linking a threat to a risk from the
  register, carrying only a name and description

Risk scoring (likelihood, impact, treatment) remains on the existing
Risk entity. Threats are purely descriptive. Risk Scenarios connect
the threat model to the risk register without duplicating scores.

Backend: migration with PG enum for node types, coredata structs,
service layer with full CRUD and validation, GraphQL schema with
18 mutations and paginated connections, authorization actions and
policies, and base_resolvers.go Node dispatch for all entity types.

Frontend: Risk Assessments list page with create dialog, detail page
showing scopes as cards with nodes/processes/threats tables, inline
create/edit/delete actions on all entities, and a Scenarios tab on
the Risk detail page linking threats to risks. Existing RiskGraph.ts
hook file removed in favor of colocated queries in page files.

E2E tests cover CRUD for all entity types, RBAC, and tenant
isolation.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-19 21:44:27 +02:00
Émile Ré
7099a3d702 Replace vendor JSON with common third parties API
The CreateVendorDialog previously loaded the entire @probo/vendors
JSON bundle client-side and used MiniSearch for fuzzy search. This
replaces it with a GraphQL query against the common_third_parties
database table, searched server-side via ILIKE filtering.

Backend: adds CommonThirdParty GraphQL type, a pkg/thirdparty
service, and a commonThirdParties(name) root query. Frontend:
splits into CommonThirdPartyCombobox (display) and an @inline
fragment read on selection via readInlineData.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:36 +04:00
Émile Ré
1ec8e475de Add UX for cookie banner management
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-20 17:47:04 +04:00
Aurélien Sibiril
ebfc0b7e31 Add access review console GraphQL API
Add queries, mutations, and types for access review
campaigns, access sources, access entries with decisions
and flags, connector provider info, and provider org
listing. Wire accessreview.Service into the Resolver.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-02 14:37:29 +02: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
Sacha Al Himdani
4d2cb793b6 Add compliance page mailing list base
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-03-11 15:34:36 +01:00
Bryan Frimin
c191d25e9a Add electronic signature
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-02-23 09:38:27 +01:00
Émile Ré
7322201dab Plug trust center part 1
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-01-17 12:34:23 -08:00
Émile Ré
1257347df9 Extract authn & authz utils
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-01-17 12:34:03 -08:00
Émile Ré
c6094ff572 Implement organization assumption check in authorization layer
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-01-17 12:34:01 -08:00