Commit Graph

7 Commits

Author SHA1 Message Date
Aurélien Sibiril
9c0f95bab1 Restore trailing slash on Sentry API requests
Commit f5703d390 replaced the fmt.Sprintf URL construction with
url.JoinPath, which calls path.Join and therefore strips a trailing
slash unless the final element carries one. Sentry's API only routes
slashed paths and answers 404 without redirecting, so every
ListAccounts call failed on its first request and no access-review
campaign targeting Sentry could fetch a single account.

The failure was invisible for two reasons. queryMembers maps 404 to
errSentryOrgNotAccessible, so a routing bug surfaced to users as
"reconnect the connector with the correct organization" -- advice that
could never help, because the slug was never wrong. And commit
74ce2bc5d edited the recorded request URL in testdata/sentry.yaml to
match the new construction instead of re-recording the cassette, which
kept CI green; that cassette still carries Sentry's own Link header
with the trailing slash, contradicting its own request line.

Pass the slash on the final JoinPath element in both the members
endpoint and the organization name resolver, revert the cassette to the
URL Sentry actually served, and add a regression test that drives the
driver against a server which 404s unslashed paths, so the URL shape is
pinned independently of the cassette matcher.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-22 17:27:55 +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
Ludovic Vielle
8094e7cfd0 Truncate access review roles with badge list
Long role strings in the access review table broke row layout when
drivers joined many roles into one comma-separated value. Expose
roles as a string array in GraphQL by splitting the stored role at
the API layer, and render the first three roles as badges with a
"+X more" popover for the rest.

Closes ENG-459.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-06-16 11:25:31 +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
Aurélien Sibiril
93d8d20dbf Surface stale Sentry slug in ListAccounts error
ListAccounts on a connector whose stored slug is no longer accessible
to its OAuth token currently returns "cannot fetch sentry members:
unexpected status 404" -- opaque, and indistinguishable from a real
Sentry outage. The campaign source-fetch worker records that string
verbatim as the customer-visible LastError, with no hint that the
connector itself needs reconnection.

queryMembers now returns a sentinel errSentryOrgNotAccessible on 404,
and ListAccounts wraps it with the slug and a directive to reconnect.
errors.Is preserves the chain so future callers can branch on the
permanent-config-failure case without string matching.

No auto-recovery: the only safe slug is one the customer explicitly
chose. Picking a different visible org would silently rebind the
source to the wrong tenant.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-28 19:22:45 +02:00
Aurélien Sibiril
036cd3306e Reuse ListSentryOrganizations in Sentry driver
SentryDriver.resolveOrgSlug duplicated the same /organizations/?member=true
call already implemented in ListSentryOrganizations, which is consumed by
the OAuth org picker. Delegating to the shared helper prevents the two
call sites from drifting (response shape, header set, pagination) and
keeps the driver focused on member listing.

Pure refactor: no behavior change. Add an httptest-backed smoke test
covering the empty-stored-slug path end-to-end through ListAccounts so
the auto-discovery flow stays exercised after the refactor.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-05-28 19:22:45 +02:00
Aurélien Sibiril
2320e1e0be Add access source drivers
Add Driver interface and implementations for Google
Workspace, Linear, Slack, 1Password, HubSpot, DocuSign,
Notion, Brex, Tally, Cloudflare, CSV, Probo memberships,
Sentry, OpenAI, Supabase, GitHub, Intercom, and Resend.
Include name resolvers, VCR test infrastructure with
cassettes, and RFC 5988 link header parser.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-02 14:37:29 +02:00