Skip to content

Generalize auth model for multi-plugin support #85

@ewega

Description

@ewega

Problem

BuildCreateRequest() and BuildTestRequest() in cmd/connection_types.go hardcode AuthMethod: "AccessToken" (lines 93, 116). This means every connection is created with token-based auth regardless of what the upstream DevLake plugin expects.

This blocks four plugins that use different auth models:

Plugin Required Auth What Breaks
Azure DevOps Custom BasicAuth (base64 :<token>) Wrong auth header sent to DevLake API
Jenkins BasicAuth (username + password) No username field in payload
Bitbucket BasicAuth (username + app password) No username field, no usesApiToken flag
Jira MultiAuth (token OR basic) Can't specify auth method choice

Additionally, ConnectionParams only has a Token field — no Username/Password pair for BasicAuth plugins. And looksLikeZeroDateTokenExpiresAt in line 278 hardcodes def.Plugin == "github" || def.Plugin == "gh-copilot" instead of using a ConnectionDef field.

Proposed Solution

1. Add auth fields to ConnectionDef

go type ConnectionDef struct { // ... existing fields ... AuthMethod string // "AccessToken" (default), "BasicAuth", etc. NeedsUsername bool // true for BasicAuth plugins (Jenkins, Bitbucket, Jira) UsernamePrompt string // "Jenkins username", "Bitbucket username" UsernameEnvVars []string // ["JENKINS_USER", "JENKINS_USERNAME"] UsernameEnvFileKeys []string // .devlake.env keys for username NeedsTokenExpiry bool // true = apply zero-date workaround (replaces hardcoded plugin check) }

2. Extend ConnectionParams

go type ConnectionParams struct { Token string Username string // for BasicAuth plugins Org string Enterprise string Name string Proxy string Endpoint string }

3. Update BuildCreateRequest() / BuildTestRequest()

Use def.AuthMethod (defaulting to "AccessToken" when empty for backward compat) instead of hardcoding. For BasicAuth, send Username and Password fields.

4. Extend request structs in client.go

go type ConnectionCreateRequest struct { // ... existing fields ... Username string json:"username,omitempty"Password stringjson:"password,omitempty"}

5. Update connection creation flow

  • runConnectionsInternal() prompts for username when def.NeedsUsername is true
  • runAddConnection() accepts --username flag
  • Token resolution still works for password (rename conceptually in prompts)

6. Replace hardcoded plugin check

Replace if (def.Plugin == "github" || def.Plugin == "gh-copilot") && looksLikeZeroDateTokenExpiresAt(err) with if def.NeedsTokenExpiry && looksLikeZeroDateTokenExpiresAt(err).

Scope of Changes

  • cmd/connection_types.go — add fields to ConnectionDef, update BuildCreateRequest, BuildTestRequest, replace hardcoded plugin check
  • internal/devlake/client.go — add Username/Password to request structs
  • cmd/configure_full.go — update runConnectionsInternal() for username prompting
  • cmd/configure_connection_add.go — add --username flag
  • Tests for all changed functions

Acceptance Criteria

  • Existing github/gh-copilot connections still work unchanged (backward compat)
  • New AuthMethod field on ConnectionDef drives payload construction
  • --username flag available on connection add
  • token.Resolve still works for password resolution in BasicAuth mode
  • No hardcoded plugin names outside connectionRegistry for auth logic
  • go build ./..., go test ./..., go vet ./... pass

Blocks

References

  • cmd/connection_types.go:83-105BuildCreateRequest
  • cmd/connection_types.go:278 — hardcoded plugin name check
  • internal/devlake/client.go:67-93 — request structs
  • internal/token/resolve.go — token resolution chain
  • Upstream Jenkins connection: incubator-devlake/backend/plugins/jenkins/models/connection.go (BasicAuth)
  • Upstream Azure DevOps: incubator-devlake/backend/plugins/azuredevops_go/models/connection.go (custom BasicAuth)

Metadata

Metadata

Assignees

Labels

refactorCode restructure, no behavior change

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions