Commit Graph

39 Commits

Author SHA1 Message Date
Aurélien Sibiril
a5259fc978 Refine connector provider registry per review
Three follow-ups from review of the registry consolidation:

- Build Vercel's authorization URL with net/url instead of a
  hand-rolled "{integration_slug}" placeholder resolved by
  strings.ReplaceAll. The slug is escaped via url.PathEscape in a
  per-provider Registration.BuildAuthURL closure, and the unused
  AuthURLParams plumbing on Registration and OAuth2Connector is
  removed (OAuth2Connector now carries a typed IntegrationSlug).

- Drop the SettingsInput union type and the per-provider
  MarshalSettings closures. The create resolvers now build the typed
  coredata.*ConnectorSettings directly from the gqlgen input, the
  same way the OAuth callback path already does, so there is no
  shared catch-all DTO and no stringly-typed boundary.

- Restore ConnectorProviders() to a plain ordered slice literal; the
  intermediate map + slices.Sort added nondeterminism and a sort for
  no benefit.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-27 00:34:39 +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
Émile Ré
9156d6a16a Add wsl linter and fix
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-20 09:27:28 +04:00
Aurélien Sibiril
7d0dec82f6 Guard Helm connector env vars on clientId / clientSecret → Address review feedback on access-review drivers
- Guard Helm connector env vars on clientId / clientSecret
- Decode Vercel pagination cursor as *int64
- Drop Monday probe URL — no valid GET endpoint
- Address review feedback on access-review drivers

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:51 +02:00
Aurélien Sibiril
995769c4b6 Drop dead OAuth2 TokenExtraParams plumbing → Reject non-numeric ClickUp timestamps via strconv
- Drop dead OAuth2 TokenExtraParams plumbing
- Drop Deel-only x-client-id header from basic-form
- Follow Bitbucket workspace pagination cursor
- Reject non-numeric ClickUp timestamps via strconv

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:50 +02:00
Aurélien Sibiril
c2db47e698 Require CLIENT_SECRET for new access-review connectors → Drop Snyk, Ramp, Lever, Deel access-review providers
- Require CLIENT_SECRET for new access-review connectors
- Use Heroku account UUID as ExternalID
- Bump GitHub orgs picker to per_page=100
- Drop Snyk, Ramp, Lever, Deel access-review providers

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:50 +02:00
Aurélien Sibiril
8917b46541 Move Vercel /v2/user fetch to pkg/connector/vercel.go → Migrate connector settings callers to generic
- Move Vercel /v2/user fetch to pkg/connector/vercel.go
- Authorize NeedsConfiguration and SelectedOrganization
- Add coredata.ConnectorSettings[T] generic helper
- Migrate connector settings callers to generic

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:49 +02:00
Aurélien Sibiril
caec9f1ad5 Rename access-review migration with random time → Validate PagerDuty subdomain on OAuth callback
- Rename access-review migration with random time
- Move PagerDuty token-response handling to its own file
- Strip OAuth error_description from log and redirect
- Validate PagerDuty subdomain on OAuth callback

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:49 +02:00
Aurélien Sibiril
842f9cfbc5 Stop leaking customer email domain in cassette guard → Add PKCE coverage tests for entropy and replay
- Stop leaking customer email domain in cassette guard
- Deep-copy ExtraAuthParams in ApplyProviderDefaults
- Drop raw monday graphql error from returned errors
- Add PKCE coverage tests for entropy and replay

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:49 +02:00
Aurélien Sibiril
0147acd9f0 Add PKCE, token-body extras, AuthURL templating to OAuth2 → Add settings structs for Pattern-2 connector providers
- Add PKCE, token-body extras, AuthURL templating to OAuth2
- Add 13 connector provider enum values
- Add scopes, display names, name resolvers for 13 providers
- Add settings structs for Pattern-2 connector providers

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-17 17:22:48 +02:00
Bryan Frimin
5e55c888c4 Add Microsoft 365 SCIM bridge and access review driver
Microsoft 365's native SCIM endpoint is unreliable, so mirror the
Google Workspace bridge over Microsoft Graph: a new MICROSOFT_365
OAuth2 connector, a SCIM bridge provider listing /v1.0/users with
$select pagination, and an access review driver that derives admin
status from /directoryRoles members. Refactor the bridge runner to
share OAuth2 plumbing across providers and surface the new bridge
type, scopes, UI card, and bootstrap env wiring.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-05-06 15:41:30 +02:00
Aurélien Sibiril
a6379bb9f4 Always send Bearer auth for OAuth2 connectors
Provider token_type values are not reliably valid HTTP auth schemes
(Slack returns "bot" / "user", some providers send an empty string),
which produces a malformed Authorization header on subsequent
requests. Every OAuth2 connector in this codebase actually uses a
bearer token, so we always send "Bearer".

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-22 11:15:48 +02:00
Bryan Frimin
472ca703b5 Mitiate SSRF attack
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-20 12:11:17 +02:00
Aurélien Sibiril
c7ec1bcab3 Validate Slack OAuth2 token response
Check the ok and error fields from Slack's token
response and reject flows with a missing access token.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-13 19:24:46 +02:00
Aurélien Sibiril
c6a5d98755 Drop grouped brackets for single declarations
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-13 19:24:46 +02:00
Aurélien Sibiril
cc6d271f10 Remove unused ScopesCover function
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-13 19:24:46 +02:00
Aurélien Sibiril
1def3a4136 Remove unused request param from InitiateWithState
The r *http.Request parameter was not read inside
InitiateWithState — all test call sites passed nil.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-13 19:24:46 +02:00
Aurélien Sibiril
71f6364df0 feat(connector): support OAuth2 scope preservation and incremental auth
Extend the OAuth2 connector so a reconnect can request the union of
previously granted and newly requested scopes without losing either.
Four related changes:

- Connection gains Scopes() []string so callers no longer need a type
  switch to reach the scope set. OAuth2Connection and APIKeyConnection
  implement it; SlackConnection inherits via embedding.
- OAuth2State carries RequestedScopes and CompleteWithState falls
  back to it when the provider omits the scope field (RFC 6749 §5.1
  allows this when granted equals requested). Without the fallback
  the stored Scope would be empty and the next reconnect would have
  no diff base.
- providerDefinition gains SupportsIncrementalAuth, set only for
  Google Workspace. When the flag is true and the caller passes
  InitiateOptions.IncludeGrantedScopes, the auth URL carries
  include_granted_scopes=true and the prompt=consent param is
  dropped so reuse flows see only the delta consent screen.
- InitiateOptions gains ConnectorID so the reconnect case is passed
  explicitly instead of relying on the caller to mutate r.URL.Query.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-13 19:24:46 +02:00
Aurélien Sibiril
62bab0f732 fix(connector): relax Slack incoming webhook requirement
ParseSlackTokenResponse treated the incoming_webhook field as
mandatory, which blocked any Slack OAuth2 flow that did not request
the incoming-webhook scope. Access review Slack connects only ask
for users:read and users:read.email and would fail at token parsing.

Treat incoming_webhook as optional: populate SlackSettings when it
is present, leave them empty otherwise. The existing compliance-page
webhook URL is preserved through Reconnect in a later commit.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-13 19:24:46 +02:00
Aurélien Sibiril
d0fedcf39e feat(connector): add scope parsing utilities
ParseScopeString, FormatScopeString, UnionScopes and ScopesCover
encapsulate OAuth2 scope-set arithmetic. ParseScopeString accepts
both the RFC 6749 space-separated form and GitHub's comma-separated
non-compliant form in one pass, so callers can stay format-agnostic.

These primitives are the foundation for scope-preserving reconnect:
later commits compute the union of stored and requested scopes so
a reconnect never drops a previously granted scope.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-13 19:24:46 +02:00
Aurélien Sibiril
e006f335b2 Pass OAuth2 scopes to connector at initiate time
Add an InitiateOptions struct to the Connector interface so each
caller can declare the scopes it needs instead of having them baked
into the connector at registration. The HTTP handler reads repeated
?scope= query parameters from /connectors/initiate and forwards them.

Also restore GOOGLE_WORKSPACE and LINEAR provider definitions which
were silently dropped from the bootstrap config refactor.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-08 11:05:12 +02:00
Aurélien Sibiril
f3db9d186b Simplify ConnectorRegistry to pure store
Remove provider-default mutation from Register; defaults are now
applied via ApplyProviderDefaults before registration. Rename
receiver from cr to r. Fix error messages to follow the cannot
convention. Wrap providerProbeURLs in var () block.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-08 11:05:12 +02:00
Aurélien Sibiril
f7085f98be Add OAuth2 provider definitions to connector package
Centralise static OAuth2 properties (auth URL, token URL, scopes,
extra params, token endpoint auth) per provider in a single map.
This removes the need to duplicate these values in deployment
config; only ClientID and ClientSecret remain configurable.

Introduces ApplyProviderDefaults to set redirect URI and provider
defaults onto an OAuth2Connector at wiring time.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-08 11:05:12 +02:00
Aurélien Sibiril
46dee27bcf Add connector infrastructure for access review
Add API key connector protocol, OAuth2 client credentials
grant, token refresh config, provider info endpoint,
ConnectorProviders helper, and bootstrap configs for all
OAuth providers. Move OAuth2 state decode near type.

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
Bryan Frimin
ece54f1616 Fix golint errors
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-02-02 18:42:50 +01:00
Bryan Frimin
3d4b215b8f Add bridge backend for sync
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-02-02 09:14:39 +01:00
Bryan Frimin
bc5bbdae81 Add scim bridge with connector
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-02-02 09:14:38 +01:00
Bryan Frimin
59aa332ab5 Move to vanity import url
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2025-10-31 17:01:52 +01:00
Sacha Al Himdani
de004ce8d7 Add slack integration
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2025-10-23 15:10:54 +02:00
Bryan Frimin
16a5f0c7f9 Remove debug log
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2025-05-14 08:08:35 -07:00
Bryan Frimin
fdd596233e Fix continue ignored
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2025-04-20 21:32:13 -07:00
Bryan Frimin
82f95a354e Fix silient token reponse error
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2025-04-20 21:20:23 -07:00
Bryan Frimin
9aeed6da4a Add settins connector view
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2025-04-20 21:16:49 -07:00
Bryan Frimin
44a05be1af Encrypt connector sensitive data
Add database field level encryption level to sensitive data to reduce
the risk in term of data leak. I dedice to have only one key for now in
a near future I may move to one master key and one encryption key per
organization to make rotation easiest.

I don't use built-in pg_crypto function to have clear seperation and
avoid any encryption key leak.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2025-04-20 21:16:18 -07:00
Bryan Frimin
868c45b15d Fix empty string secret for state token
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2025-04-20 21:16:17 -07:00
Bryan Frimin
fd698d8485 Fix no error with duplicate connector name
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2025-04-20 21:16:17 -07:00
Bryan Frimin
7d3a9e6d3b Remove debug log
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2025-04-20 21:16:17 -07:00
Bryan Frimin
8c516c1689 Add connector with OAuth2 support
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2025-04-20 21:16:16 -07:00