Skip to content

feat(integrations): migrate Groundcover, GitLab, Sentry, PostHog and Vercel onto the shared setup flow#4194

Merged
muddlebee merged 2 commits into
mainfrom
feat/setup-specs-grafana-groundcover
Jul 22, 2026
Merged

feat(integrations): migrate Groundcover, GitLab, Sentry, PostHog and Vercel onto the shared setup flow#4194
muddlebee merged 2 commits into
mainfrom
feat/setup-specs-grafana-groundcover

Conversation

@muddlebee

Copy link
Copy Markdown
Collaborator

Part of #4168. Follows #4191 (Datadog, Honeycomb, Coralogix).

Describe the changes you have made in this PR -

Second migration batch onto the shared setup flow: Groundcover, GitLab, Sentry, PostHog, Vercel. No new spec machinery — everything these needed already landed in #4191, which is the point of batching this way.

Two more wizard configurators were silently dropping credentials

Configurator Bug
_configure_vercel called sync_env_values({}) — neither VERCEL_API_TOKEN nor VERCEL_TEAM_ID reached any tier but the store
_configure_sentry wrote SENTRY_URL, SENTRY_ORG_SLUG and SENTRY_PROJECT_SLUG, but never SENTRY_AUTH_TOKEN to the keyring

That is five such bugs across two batches (Datadog, Honeycomb, Coralogix, Sentry, Vercel). The pattern is consistent enough to be worth stating plainly: hand-written per-vendor persistence was wrong more often than it was right. Both are fixed structurally rather than patched — the configurators no longer contain persistence code at all.

GitLab had no validation and no verification

_setup_gitlab prompted for a URL and a token and called upsert_integration — no _die on a blank token, no probe. A typo'd or empty token produced a stored integration that failed on first use. It now verifies before it persists, like every other spec-backed integration.

Three of the five have env var names that do not match the credential

Credential Env var
auth_token (GitLab) GITLAB_ACCESS_TOKEN
organization_slug (Sentry) SENTRY_ORG_SLUG
base_url (Sentry) SENTRY_URL

This is exactly the class of mistake tests/integrations/test_setup_spec_env_round_trip.py exists to catch, and it now covers all nine migrated integrations. I mutation-tested it again on the worst offender — pointing GitLab's spec at the plausible-but-wrong GITLAB_AUTH_TOKEN fails the suite:

FAILED test_persisted_credentials_are_read_back_by_the_catalog[gitlab]

The readers are single-sourced against the same constants the specs write (integrations/_catalog_impl.py, integrations/gitlab/__init__.py, integrations/posthog/config.py), so the two sides cannot drift for these vendors.

Sentry and PostHog constants needed care

config/constants/sentry.py and posthog.py already existed, but they hold OpenSRE's own telemetry config — the DSN it reports its own crashes to, and the write-only key for its own analytics project. Those are unrelated to the credentials a user supplies to query their Sentry or PostHog. Both module docstrings now say so explicitly, and the integration names sit under a separate marked section.

Deduplication

validate_gitlab_integration, validate_sentry_integration, validate_posthog_integration and validate_vercel_integration are deleted — all four files contained nothing else. The first three were literally build_X_config + validate_X_config, which is exactly what register_validation_verifier already wires up; the Vercel one duplicated client.probe_access().

Before deleting the Vercel tests I checked what they actually covered and found probe_access's failure path untested, so tests/integrations/vercel/test_client.py gains two tests (API error reported, blank token reports missing not failed) rather than losing that coverage.

Demo/Screenshot for feature changes and bug fixes -

GitLab verify-before-persist, sandboxed HOME, default base URL accepted, bad token:

$ opensre integrations setup gitlab

  Setting up gitlab

❯ GitLab base URL (e.g. https://gitlab.example.com/api/v4) https://gitlab.com/api/v4
❯ GitLab access token **********************

  Validating gitlab credentials...
  error: Gitlab validation failed: {"message":"401 Unauthorized"}

$ cat $HOME/.opensre/integrations.json   →  (nothing saved)
$ cat $HOME/.env                          →  (nothing saved)

Before this change GitLab did not verify at all — that token would have been stored.


Code Understanding and AI Usage

Did you use AI assistance (ChatGPT, Claude, Copilot, etc.) to write any part of this code?

  • No, I wrote all the code myself
  • Yes, I used AI assistance (continue below)

If you used AI assistance:

  • I have reviewed every single line of the AI-generated code
  • I can explain the purpose and logic of each function/component I added
  • I have tested edge cases and understand how the code handles them
  • I have modified the AI output to follow this project's coding standards and conventions

Explain your implementation approach:

Same problem as #4191 — three surfaces configured integrations and disagreed about where credentials land, so whether an integration blocked make deploy depended on which command you used. This batch moves five more onto the one flow.

I picked these five because they are all "N fields plus a registered verifier" with no branching prompts, which meant the batch needed no new spec features and stays reviewable. Grafana is still deferred: its wizard path has a _confirm boolean (verify_ssl) and a ca_bundle field that is only asked when that boolean is true, and SetupField models neither a boolean nor a conditional field. That is a design decision I would rather make against Grafana and the databases together than smuggle into a batch PR.

Key pieces:

  • integrations/<vendor>/setup.py × 5 — declarative field lists; no logic.
  • config/constants/<vendor>.py — env names, imported by both the writer (spec) and the reader (load_env_integrations and friends), which is what makes the two sides unable to drift.
  • The wizard configurators collapse to one line each via the existing configure_from_spec.

Edge cases covered by the extended parametrized suites: blank required field fails on that field rather than after every prompt; defaulted fields (GITLAB_BASE_URL, SENTRY_URL, POSTHOG_BASE_URL, GROUNDCOVER_MCP_URL, GROUNDCOVER_TIMEZONE) accept a bare enter; optional fields (VERCEL_TEAM_ID, SENTRY_PROJECT_SLUG, Groundcover's tenant/backend) may be left blank and clear every tier when blanked; failed verification persists nothing anywhere.

One deliberate non-change: Groundcover's key resolves from GROUNDCOVER_API_KEY or GROUNDCOVER_MCP_TOKEN. Setup writes the primary name only, so there is one place to look; the fallback still resolves for anyone who already set it.


Checklist before requesting a review

  • I have added proper PR title and linked to the issue
  • I have performed a self-review of my code
  • I can explain the purpose of every function, class, and logic block I added
  • I understand why my changes work and have tested them thoroughly
  • I have considered potential edge cases and how my code handles them
  • If it is a core feature, I have added thorough tests
  • My code follows the project's style guidelines and conventions

…Vercel onto the shared setup flow

Second batch of #4168, and the first that needed no new spec machinery —
everything these five required landed with #4191.

Two more wizard configurators were dropping credentials on the floor:
_configure_vercel called sync_env_values({}) so neither the token nor the
team id reached any tier but the store, and _configure_sentry wrote the
URL, org and project slugs but never SENTRY_AUTH_TOKEN to the keyring.
That is five such bugs across two batches; hand-written per-vendor
persistence was wrong more often than it was right. Both are fixed by
removing the persistence code rather than correcting it.

GitLab was worse: _setup_gitlab prompted for a URL and a token, called
upsert_integration, and stopped — no check for a blank token and no probe
at all, so a typo produced a stored integration that failed on first use.

Three of the five name their env vars differently from the credential
they carry (auth_token as GITLAB_ACCESS_TOKEN, organization_slug as
SENTRY_ORG_SLUG, base_url as SENTRY_URL), which is the mistake the
round-trip test exists to catch; it now covers all nine migrated
integrations. The readers — _catalog_impl, integrations/gitlab and
integrations/posthog/config — import the same constants the specs write,
so the two sides cannot drift.

config/constants/sentry.py and posthog.py already existed but hold
OpenSRE's *own* telemetry config: the DSN it reports its crashes to and
the write-only key for its analytics project. Those are unrelated to what
a user supplies to query their own Sentry or PostHog, so both docstrings
now say so and the integration names sit under a separate section.

Deletes the four wizard validators, whose files contained nothing else.
Three were literally build_X_config + validate_X_config, which is what
register_validation_verifier already wires up; Vercel's duplicated
client.probe_access(). Vercel's probe failure path turned out to be
untested, so tests/integrations/vercel/test_client.py gains that coverage
rather than losing it with the validator.
@muddlebee

Copy link
Copy Markdown
Collaborator Author

@greptile review

@github-actions

Copy link
Copy Markdown
Contributor

Greptile code review

This repo uses Greptile for automated review. Before merge, aim for Confidence Score: 5/5 with zero unresolved review threads — see CONTRIBUTING.md.

Run a review — add a PR comment with:

@greptile review

Give it ~5-10 minutes (sometimes longer) for results, then fix feedback and re-trigger until you reach Confidence Score: 5/5.

Optional: automate with the greploop skill.

@greptile-apps

greptile-apps Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR migrates five integrations — Groundcover, GitLab, Sentry, PostHog, and Vercel — onto the shared IntegrationSetupSpec / apply_setup flow introduced in #4191. The migration fixes two credential-persistence bugs (_configure_vercel was calling sync_env_values({}), dropping both Vercel env vars; _configure_sentry never wrote SENTRY_AUTH_TOKEN to the keyring) and adds missing validation-before-persist for GitLab.

  • Five new setup.py specs and matching constants modules (config/constants/{gitlab,groundcover,vercel}.py) single-source every env var name so the writer (spec) and reader (_catalog_impl.py, per-vendor config modules) reference the same constant and cannot drift.
  • Four redundant validator shim files (integration_validators/{gitlab,posthog,sentry,vercel}.py) are deleted; the shared register_validation_verifier path already wires up the same logic.
  • New Vercel client tests cover the previously-untested probe_access failure path and the blank-token short-circuit, replacing the deleted validator-layer tests.

Confidence Score: 5/5

Safe to merge — the change is a clean structural migration with no new logic, and the two credential-persistence bugs it fixes are clearly demonstrated by the extended round-trip test suite.

Every changed surface is a direct mechanical substitution: string literals replaced with constants, hand-written persistence loops replaced with apply_setup, and thin shim files deleted. The round-trip tests now cover all nine migrated integrations, and the new Vercel client tests close the one gap left when the validator shims were removed. No branching logic was added, no auth boundary was moved, and the env-var routing decisions (keyring vs .env) follow the existing is_sensitive_env_key convention without any exceptions.

No files require special attention.

Important Files Changed

Filename Overview
integrations/gitlab/setup.py New spec for GitLab; correctly marks auth_token required (fixing the old silent-empty-token bug) and maps base_url to GITLAB_BASE_URL_ENV with a sensible default.
integrations/groundcover/setup.py New spec for Groundcover; required/optional split is correct, and the primary GROUNDCOVER_API_KEY env var is used (GROUNDCOVER_MCP_TOKEN fallback is resolver-only, per design).
integrations/sentry/setup.py New spec for Sentry; auth_token is now correctly routed to the keyring via SENTRY_AUTH_TOKEN (is_sensitive_env_key matches *_TOKEN), and project_slug is optional.
integrations/posthog/setup.py New spec for PostHog; covers the three user-supplied credentials. POSTHOG_TIMEOUT_SECONDS is intentionally omitted (advanced setting with a safe default, not part of interactive setup).
integrations/vercel/setup.py New spec for Vercel; fixes the old sync_env_values({}) bug — VERCEL_API_TOKEN now routes to keyring, VERCEL_TEAM_ID to .env.
config/constants/sentry.py Adds four Final[str] integration constants under a separate section; docstring clarifies the two unrelated uses of the Sentry name in this codebase.
config/constants/posthog.py Adds four Final[str] integration env-var constants alongside the existing analytics constants; docstring now explicitly separates the two concerns.
integrations/_catalog_impl.py Replaces all inline string literals for groundcover, sentry, gitlab, and vercel env var names with the new constants; posthog delegated to posthog_config_from_env() which was updated separately.
tests/integrations/test_setup_spec_env_round_trip.py Extends the round-trip suite to all five new integrations, providing mutation-tested coverage that writer and reader constants cannot drift.
tests/integrations/vercel/test_client.py Adds two new probe_access tests covering the failure path (API error detail survives) and blank-token short-circuit (reports missing, not failed); correctly does not patch list_projects for the blank-token case.
surfaces/cli/wizard/integration_validators/gitlab.py Deleted — was a thin shim over build_gitlab_config + validate_gitlab_config, which register_validation_verifier already provides.
tests/cli/wizard/test_integration_health.py Removes tests for the four deleted validator shims; the all membership test is updated to match the reduced export set.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User: opensre integrations setup service] --> B[CLI handler: _setup_service]
    B --> C[_run_spec_setup / configure_from_spec]
    C --> D[IntegrationSetupSpec]
    D --> E{apply_setup}
    E --> F[_collect_credentials
validates required fields]
    F -->|missing required field| G[Exit with error
 nothing persisted]
    F -->|all fields present| H[_verify
calls spec.verify]
    H -->|status != passed| I[Retry prompt
 nothing persisted]
    H -->|passed| J[_persist_env
keyring for _TOKEN/_KEY
.env for everything else]
    J --> K[upsert_integration
integration store]
    K --> L[Setup complete]

    subgraph New setup.py specs
        M[gitlab/setup.py GITLAB_SETUP]
        N[groundcover/setup.py GROUNDCOVER_SETUP]
        O[sentry/setup.py SENTRY_SETUP]
        P[posthog/setup.py POSTHOG_SETUP]
        Q[vercel/setup.py VERCEL_SETUP]
    end

    D -.->|one of| M
    D -.->|one of| N
    D -.->|one of| O
    D -.->|one of| P
    D -.->|one of| Q
Loading

Reviews (3): Last reviewed commit: "style(config): annotate the new env-name..." | Re-trigger Greptile

Comment thread config/constants/sentry.py Outdated
@greptile-apps

greptile-apps Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR migrates five more integrations — Groundcover, GitLab, Sentry, PostHog, and Vercel — onto the IntegrationSetupSpec + apply_setup shared flow introduced in #4191. Along the way it fixes two silent credential-persistence bugs (_configure_vercel called sync_env_values({}) so no env vars were written; _configure_sentry never wrote SENTRY_AUTH_TOKEN to the keyring) and one missing-verification bug (GitLab stored credentials before checking them).

  • Five new declarative setup.py specs replace the ad-hoc while-loops and hand-rolled persistence in each wizard configurator and CLI handler; each spec is a pure field list with no logic.
  • Centralized env-var constants in config/constants/{gitlab,groundcover,posthog,sentry,vercel}.py single-source both sides of every write/read pair, preventing the name drift that caused three of the five persistence bugs.
  • Four thin validator-wrapper files deleted (gitlab.py, posthog.py, sentry.py, vercel.py under integration_validators/); the round-trip test suite extended to all nine migrated integrations verifies the coverage gap is filled by the shared verifier registry.

Confidence Score: 5/5

Safe to merge. All five integrations now follow the same write path; the bug fixes are structurally sound and fully covered by the extended round-trip and wizard-flow test suites.

Every stated bug fix is verified end-to-end: the env round-trip test confirms each credential reaches the correct tier, and the wizard flow tests confirm no credentials are saved when verification fails. The constants files are internally consistent with the batch-1 pattern. The deleted validator wrappers had no logic that is not now covered by register_validation_verifier / register_probe_verifier. No behavioral regressions were identified.

No files require special attention. The only things worth a second read are the intentional credential/env-var name mismatches (auth_token → GITLAB_ACCESS_TOKEN, base_url → SENTRY_URL) — these are documented in both the constants modules and the PR description and are verified by the round-trip suite.

Important Files Changed

Filename Overview
integrations/gitlab/setup.py New declarative spec; correctly maps auth_token → GITLAB_ACCESS_TOKEN (intentional name mismatch, documented) and adds verify=verify_gitlab so blank/wrong tokens fail before persisting
integrations/sentry/setup.py New spec; SENTRY_AUTH_TOKEN_ENV routes to keyring via is_sensitive_env_key, fixing the bug where the old wizard never persisted SENTRY_AUTH_TOKEN; SENTRY_BASE_URL_ENV='SENTRY_URL' preserves the backward-compatible env var name
integrations/vercel/setup.py New spec; VERCEL_API_TOKEN_ENV routes to keyring, fixing the old wizard's sync_env_values({}) that dropped both credentials; team_id correctly marked optional
integrations/groundcover/setup.py New spec; imports DEFAULT_GROUNDCOVER_MCP_URL and DEFAULT_GROUNDCOVER_TIMEZONE from config_models; optional fields (tenant_uuid, backend_id) correctly carry required=False
integrations/posthog/setup.py New spec; POSTHOG_PERSONAL_API_KEY_ENV ends in _KEY so routes to keyring; no timeout_seconds field (intentional — matches pre-existing behavior, runtime-only param)
config/constants/sentry.py Adds user-integration constants below a clear section separator; docstring correctly explains the dual-namespace problem; DEFAULT_SENTRY_BASE_URL annotated Final[str] consistently with existing constants
config/constants/posthog.py Adds user-integration env var names; POSTHOG_TIMEOUT_SECONDS_ENV is exported but has no setup field (intentional — runtime operational parameter, not a setup credential)
integrations/_catalog_impl.py Mechanical refactor: all five integration readers now use constants instead of string literals; behavior is unchanged but the two sides of each write/read pair can no longer drift independently
tests/integrations/test_setup_spec_env_round_trip.py Extended to cover all five new integrations; each entry uses distinct recognizable values per field so a field-swap bug would fail rather than accidentally match
tests/integrations/vercel/test_client.py Adds the two previously untested probe_access paths: API failure detail propagation and blank-token returning 'missing' not 'failed'
surfaces/cli/wizard/configurators/gitlab.py Old 35-line while-loop with hand-rolled persistence collapsed to a single configure_from_spec call; patching target in test_flow.py correctly updated to _gitlab_configurator.GITLAB_SETUP
tests/cli/wizard/test_flow.py GitLab wizard tests correctly updated: GITLAB_SETUP patched via dataclasses.replace; persistence patches moved from _gitlab_configurator to _setup_flow
tests/integrations/test_cli_spec_setup.py Adds all five new integrations to the parametrized spec-setup suite and adds a new test verifying each spec's service name maps to the correct _HANDLERS entry

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI/Wizard
    participant configure_from_spec
    participant apply_setup
    participant Verifier
    participant Keyring
    participant DotEnv
    participant Store

    User->>CLI/Wizard: opensre integrations setup service
    CLI/Wizard->>configure_from_spec: "configure_from_spec(SETUP_SPEC, title=...)"
    configure_from_spec->>configure_from_spec: prompt for each field
    configure_from_spec->>apply_setup: apply_setup(spec, values)
    apply_setup->>apply_setup: _collect_credentials() validate required fields
    alt missing required field
        apply_setup-->>configure_from_spec: "SetupOutcome(ok=False)"
        configure_from_spec->>User: re-prompt
    end
    apply_setup->>Verifier: spec.verify(setup, credentials)
    Verifier-->>apply_setup: status passed or failed
    alt verification failed
        apply_setup-->>configure_from_spec: "SetupOutcome(ok=False)"
        configure_from_spec->>User: re-prompt
    end
    apply_setup->>Keyring: sync_env_secret(TOKEN_ENV, value)
    apply_setup->>DotEnv: sync_env_values non-secret envs
    apply_setup->>Store: upsert_integration(service, credentials)
    apply_setup-->>configure_from_spec: "SetupOutcome(ok=True, env_path=...)"
    configure_from_spec-->>User: display title and env path
Loading

Reviews (2): Last reviewed commit: "feat(integrations): migrate Groundcover,..." | Re-trigger Greptile

config/constants/sentry.py and posthog.py annotate every constant they
hold, including DEFAULT_SENTRY_BASE_URL added in the same change; the new
*_ENV names did not, which reads as though they are variables.

The standalone per-vendor env modules (telegram, datadog, gitlab, …) use
no Final and stay as they are — they are consistent with each other and
with the telegram precedent. Only the two files that mix styles change.
@muddlebee

Copy link
Copy Markdown
Collaborator Author

@greptile review

@github-actions

Copy link
Copy Markdown
Contributor

💜 One more reason the project grows. Thanks @muddlebee — your contribution just landed!


👋 Join us on Discord - OpenSRE : hang out, contribute, or hunt for features and issues. Everyone's welcome.

muddlebee added a commit that referenced this pull request Jul 22, 2026
Keep both migration batches' constants, CLI setup cases, and env
round-trip coverage. Drop wizard health validators deleted on either
side (gitlab/sentry/posthog/vercel and dagster/pagerduty/incident_io).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant