Commit Graph

6 Commits

Author SHA1 Message Date
Aurélien Sibiril
0080d2caa7 Resolve the Segment workspace name and reuse listed permissions
Two corrections, both settled from Segment's published OpenAPI document
and their own client code rather than guessed.

The registration claimed the Public API exposes no workspace-name
endpoint on the token's scope. That is wrong: Get Workspace is the API
root, GET /, returning data.workspace.name for the workspace the token
is bound to — the base URL already encodes the US/EU region, so the URL
is the whole request. Without a resolver an organization running a prod
and a staging workspace saw two rows both named "Segment".

The per-user GET /users/{id} is what makes a large workspace exceed the
per-source budget, and it exists only to read permissions[].roleName.
Both endpoints return the same UserV1 schema, on which permissions is
declared but optional, so whether the list populates it is a server
behaviour no specification settles. Rather than assume, the list
response is now decoded for permissions and the per-user request is
issued only when the field is absent. Today Segment omits it — their own
Terraform provider's mock returns /users without permissions and
/users/{id} with them — so behaviour is unchanged; if that ever changes
the extra round trip disappears on its own. An empty-but-present array
is authoritative, meaning a user with no roles, not a missing field.

Page size stays at 200: the 1-1000 range is prose in the pagination
guide, the schema sets no maximum, and the migration guide says 200.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-26 09:22:05 +02:00
Aurélien Sibiril
4cbc35e79f Fix the Segment region input and invite duplicates
The region is a two-value allow-list the server resolves to an API host,
but it rendered as a free-text field: only PostHog is special-cased in
the API-key dialog, everything else falls through to a generic Field.
Typing "EU1" — the region Segment's own UI shows for the EU workspace —
passed the non-empty check, then failed the mutation, and the dialog's
generic error blamed the API key. It is a select now, so the label no
longer has to spell the accepted values out.

An invite that has already been accepted can still be listed, and the
member and the invite were keyed differently (user ID vs email), so the
same person surfaced as two rows — one active with roles, one inactive
without. Invites for an email already seen among members are dropped.

Per-user permission errors now name the user, and the probe URL builds
its query with url.Values rather than a hand-written string.

The region-to-host mapping is the only API-key setting that derives a
value instead of storing input verbatim, and it had no test; a typo in
either host would only have surfaced as a live 404.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-26 09:22:05 +02:00
Aurélien Sibiril
20502fc0be Use the MIT license header on the new connector files
The four connectors landed with the ISC header. contrib/claude/license.md
mandates MIT for every source file, and these were the only ISC files
left in pkg/accessreview/drivers and pkg/connector/provider — the two
"Make license declarations consistently MIT" commits had already cleared
both packages, so this re-opened a closed cleanup.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-26 09:22:05 +02:00
Aurélien Sibiril
21d6542855 Leave Segment members' active status unknown
Segment's /users API exposes no active/suspended field, so reporting every
confirmed member as Active=true fabricated a status the source never
provides, contrary to the AccountRecord contract (nil = no explicit signal).
Leave Active nil for confirmed members; pending invites keep Active=false,
which is a real signal from /invites.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-26 09:22:04 +02:00
Aurélien Sibiril
0b81393bdf Escape dynamic path segments in the Google Analytics and Segment drivers
The GA4 driver passed the account and property IDs to url.JoinPath as raw
segments, and the Segment driver built its per-user endpoint by
concatenating the user ID into url.URL.Path — both bypass the url.PathEscape
rule that every sibling driver (and the matching name resolvers) already
follow. The IDs are numeric today so there is no behaviour change, but this
keeps the drivers consistent and safe if a provider ever returns a segment
with a reserved character.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-26 09:22:04 +02:00
Aurélien Sibiril
60628645ae Add Google Analytics, Dotfile, Segment and Square access-review connectors
Two OAuth2 and two API-key connectors:

- Google Analytics (GA4): OAuth2 with both analytics.readonly and
  analytics.manage.users.readonly (readonly alone 403s on the accounts
  list); v1alpha accessBindings enumerated at account and property level
  and merged by email; manual account picker (Pattern 1) with a
  per-connection probe and name resolver; distinct from Google Workspace.
- Dotfile: API key in the X-DOTFILE-API-KEY header (Pattern 3); GET
  /v1/users (owner/admin, suspended_at) with a static probe.
- Segment (Twilio): Public API token as Bearer with a required Region
  setting (US or EU) mapped to the regional host; GET /users plus per-user
  GET /users/{id} for roles and /invites for pending members; per-connection
  BuildProbeURL.
- Square: OAuth2 (EMPLOYEES_READ) or a personal access token (Pattern 3);
  POST /v2/team-members/search returns email/status/is_owner directly, so no
  role resolution; custom probe and name resolver.

Google Analytics and Square are confidential OAuth clients, wired into the
bootstrap OAuth provider list and .env.example. Segment carries a required
extra setting, so the console add-source dialog maps region onto its
segmentRegion API-key input; without that mapping the value is silently
dropped and the create is rejected.

Cassette-backed driver tests plus unit tests for the Segment probe URL and
the bootstrap OAuth provider list.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-26 09:22:04 +02:00