Skip to content

Fix Jira integration for Atlassian Cloud migration#916

Open
clcollins wants to merge 1 commit intoopenshift:mainfrom
clcollins:fix-jira-atlassian-cloud-migration
Open

Fix Jira integration for Atlassian Cloud migration#916
clcollins wants to merge 1 commit intoopenshift:mainfrom
clcollins:fix-jira-atlassian-cloud-migration

Conversation

@clcollins
Copy link
Copy Markdown
Member

Problem

Red Hat migrated Jira from on-prem (https://issues.redhat.com) to Atlassian Cloud (https://redhat.atlassian.net). This broke ocm-backplane accessrequest create — users receive a 403 when the CLI tries to create Jira notification issues because:

  1. The default Jira base URL still pointed to the old on-prem instance
  2. PAT (Personal Access Token) authentication is not supported by Atlassian Cloud — it requires Basic Auth (email + API token)
  3. URL parsing in ohssService.go hardcoded a .com domain suffix via strings.SplitAfter(issue.Self, ".com"), which breaks for .net domains

Practical Impact

SREs have been unable to use AccessRequests since the Jira migration a few weeks ago. SREs were unaware they were able to break-glass to access clusters when AccessRequests were not working, resulting in delayed incident response and cluster access issues.

Changes

  • pkg/cli/config/config.go: Update default JiraBaseURL to https://redhat.atlassian.net. Add JiraEmail field to BackplaneConfiguration with JIRA_EMAIL env var support and config file fallback.
  • pkg/info/info.go: Add BackplaneJiraEmailEnvName constant for the JIRA_EMAIL environment variable.
  • pkg/jira/issueService.go: Switch from jira.PATAuthTransport to jira.BasicAuthTransport using email + API token. Add validation for missing JiraEmail.
  • pkg/jira/ohssService.go: Replace brittle strings.SplitAfter(issue.Self, ".com") with net/url.Parse() for domain-agnostic URL construction.

New Tests

  • pkg/jira/ohssService_test.go: Tests for Atlassian Cloud .net URL parsing, legacy .com URL parsing, empty Self field, and ClusterID custom field extraction.
  • pkg/cli/config/config_test.go: Tests for JIRA_EMAIL env var loading, env var precedence over config file, and config file fallback.

User Migration

After this change, users need to configure their Jira email:

ocm-backplane config set jira-email user@redhat.com

Or via environment variable:

export JIRA_EMAIL=user@redhat.com

Context

Test Plan

  • go test ./pkg/jira/... — 7/7 pass
  • go test ./pkg/cli/config/... — all pass
  • go test ./pkg/accessrequest/... — all pass
  • Manual test: ocm-backplane accessrequest create with JIRA_EMAIL and JIRA_API_TOKEN set against a cluster with access protection enabled

Red Hat migrated Jira from on-prem (issues.redhat.com) to Atlassian Cloud
(redhat.atlassian.net). This broke access request creation because:

1. The default Jira base URL pointed to the old instance
2. PAT authentication is not supported by Atlassian Cloud - it requires
   Basic Auth (email + API token)
3. URL parsing in ohssService hardcoded ".com" domain suffix

Changes:
- Update default JiraBaseURL to redhat.atlassian.net
- Switch from PATAuthTransport to BasicAuthTransport (email + API token)
- Add JiraEmail config field with JIRA_EMAIL env var support
- Fix URL parsing in ohssService to use net/url instead of string split
- Add tests for URL parsing, ClusterID extraction, and JiraEmail config

Mirrors the approach taken in osdctl commit 54dbc7aefe1f.

Created with assistance from Claude 🤖 <claude@anthropic.com>

Signed-off-by: Christopher Collins <collins.christopher@gmail.com>
@openshift-ci openshift-ci bot requested review from smarthall and xiaoyu74 April 5, 2026 22:37
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 5, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: clcollins
Once this PR has been reviewed and has the lgtm label, please assign samanthajayasinghe for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

Walkthrough

This PR adds Jira email configuration support, updates the default Jira URL endpoint from issues.redhat.com to redhat.atlassian.net, changes authentication from PAT to Basic Auth using email and token, and improves URL parsing for Jira issue links in the OHSS service.

Changes

Cohort / File(s) Summary
Configuration Management
pkg/cli/config/config.go, pkg/cli/config/config_test.go, pkg/info/info.go
Added JiraEmail field to BackplaneConfiguration with environment variable support (JIRA_EMAIL). Changed JiraBaseURLDefaultValue from https://issues.redhat.com to https://redhat.atlassian.net. Added three subtests validating environment variable precedence and config file parsing for JiraEmail.
JIRA Service Authentication
pkg/jira/issueService.go
Updated authentication transport from PATAuthTransport to BasicAuthTransport using email and token credentials. Added validation for JiraEmail field. Updated error message to "JIRA API token is not defined".
OHSS Service URL Handling
pkg/jira/ohssService.go, pkg/jira/ohssService_test.go
Refactored WebURL construction from string splitting to proper URL parsing using net/url. Updated imports accordingly. Added four test cases covering Atlassian Cloud URLs, legacy URLs, empty URLs, and cluster ID extraction from custom fields.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 5, 2026

@clcollins: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 45.45455% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.97%. Comparing base (59c1c29) to head (ce270f2).

Files with missing lines Patch % Lines
pkg/jira/issueService.go 0.00% 6 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #916      +/-   ##
==========================================
+ Coverage   53.93%   53.97%   +0.04%     
==========================================
  Files          88       88              
  Lines        6656     6662       +6     
==========================================
+ Hits         3590     3596       +6     
- Misses       2596     2597       +1     
+ Partials      470      469       -1     
Files with missing lines Coverage Δ
pkg/cli/config/config.go 71.49% <100.00%> (+0.39%) ⬆️
pkg/info/info.go 100.00% <ø> (ø)
pkg/jira/ohssService.go 80.64% <100.00%> (+9.67%) ⬆️
pkg/jira/issueService.go 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
pkg/jira/issueService.go (1)

82-99: Add direct unit tests for createIssueService() auth behavior.

The migration logic is good, but this path is currently untested directly (email-required validation + BasicAuth transport selection). Add focused tests here so future auth regressions are caught earlier.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/jira/issueService.go` around lines 82 - 99, Add unit tests that directly
exercise createIssueService(): mock or stub config.GetBackplaneConfiguration to
return configurations with (a) empty JiraEmail and a valid JiraToken to assert
it returns the expected validation error about missing email, and (b) valid
JiraEmail and JiraToken to assert it successfully constructs a
jira.BasicAuthTransport (verify the returned IssueService or inspect the
transport.Username/Password values used). Use unique symbols createIssueService,
config.GetBackplaneConfiguration, bpConfig.JiraEmail, bpConfig.JiraToken, and
jira.BasicAuthTransport to locate code under test and ensure the tests fail on
regressions in auth selection and email-required validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/cli/config/config.go`:
- Line 65: The current normalization in pkg/accessrequest/accessRequest.go
relies on getJiraBaseURL() (and the constant JiraBaseURLDefaultValue) to
TrimPrefix(issueID, getJiraBaseURL()+"/browse/"), which breaks when Jira hosts
differ (.com vs .net); change the extraction to be domain-agnostic by locating
the "/browse/" path segment (or using a regex to capture the segment after
"/browse/") and extracting the issue key regardless of host, updating the logic
in the function that performs this normalization so it no longer depends on
getJiraBaseURL() or the JiraBaseURLDefaultValue.

In `@pkg/jira/ohssService.go`:
- Around line 75-77: The WebURL construction using url.Parse(issue.Self) can
produce malformed values when Parse returns a relative URL (empty Scheme/Host);
update the logic around url.Parse(issue.Self) (the block that sets
formatIssue.WebURL) to validate that u.Scheme is "http" or "https" and u.Host is
non-empty before formatting "%s://%s/browse/%s"; if those checks fail, do not
build the WebURL (leave it empty or use a safe fallback), and add unit tests for
relative/malformed issue.Self inputs to cover this case.

---

Nitpick comments:
In `@pkg/jira/issueService.go`:
- Around line 82-99: Add unit tests that directly exercise createIssueService():
mock or stub config.GetBackplaneConfiguration to return configurations with (a)
empty JiraEmail and a valid JiraToken to assert it returns the expected
validation error about missing email, and (b) valid JiraEmail and JiraToken to
assert it successfully constructs a jira.BasicAuthTransport (verify the returned
IssueService or inspect the transport.Username/Password values used). Use unique
symbols createIssueService, config.GetBackplaneConfiguration,
bpConfig.JiraEmail, bpConfig.JiraToken, and jira.BasicAuthTransport to locate
code under test and ensure the tests fail on regressions in auth selection and
email-required validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 96c52a5e-ba3b-4c80-9f4b-2752f192b622

📥 Commits

Reviewing files that changed from the base of the PR and between 59c1c29 and ce270f2.

📒 Files selected for processing (6)
  • pkg/cli/config/config.go
  • pkg/cli/config/config_test.go
  • pkg/info/info.go
  • pkg/jira/issueService.go
  • pkg/jira/ohssService.go
  • pkg/jira/ohssService_test.go

JiraConfigForAccessRequestsKey = "jira-config-for-access-requests"
prodEnvNameDefaultValue = "production"
JiraBaseURLDefaultValue = "https://issues.redhat.com"
JiraBaseURLDefaultValue = "https://redhat.atlassian.net"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Default domain switch exposes domain-coupled issue ID parsing in access requests.

After Line 65 changes the default to .net, pkg/accessrequest/accessRequest.go (Line 82) still strips URLs using strings.TrimPrefix(issueID, getJiraBaseURL()+"/browse/"). Full legacy .com browse URLs won’t be normalized and can fail later issue-key handling. Consider making issue-ID extraction domain-agnostic (parse /browse/<KEY> from any Jira host).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/cli/config/config.go` at line 65, The current normalization in
pkg/accessrequest/accessRequest.go relies on getJiraBaseURL() (and the constant
JiraBaseURLDefaultValue) to TrimPrefix(issueID, getJiraBaseURL()+"/browse/"),
which breaks when Jira hosts differ (.com vs .net); change the extraction to be
domain-agnostic by locating the "/browse/" path segment (or using a regex to
capture the segment after "/browse/") and extracting the issue key regardless of
host, updating the logic in the function that performs this normalization so it
no longer depends on getJiraBaseURL() or the JiraBaseURLDefaultValue.

Comment on lines +75 to +77
if u, err := url.Parse(issue.Self); err == nil {
formatIssue.WebURL = fmt.Sprintf("%s://%s/browse/%s", u.Scheme, u.Host, issue.Key)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Current WebURL parsing logic =="
rg -n -C3 'url\.Parse\(issue\.Self\)|WebURL' pkg/jira/ohssService.go

echo
echo "== Existing Self URL test cases =="
rg -n -C2 'Self\s*=' pkg/jira/ohssService_test.go

echo
echo "== Check for malformed/relative Self coverage =="
rg -n -C2 'malformed|invalid|relative|scheme|host' pkg/jira/ohssService_test.go || true

Repository: openshift/backplane-cli

Length of output: 1321


Harden WebURL construction by validating parsed URL components.

At lines 75-77, url.Parse() succeeds for relative URLs without returning an error, but leaves u.Scheme and u.Host empty. This produces malformed WebURLs like :///browse/<key>. Add explicit checks for HTTP(S) scheme and non-empty host.

Current code has no test coverage for relative or malformed Self values.

Proposed fix
-		if u, err := url.Parse(issue.Self); err == nil {
+		if u, err := url.Parse(issue.Self); err == nil &&
+			(u.Scheme == "http" || u.Scheme == "https") &&
+			u.Host != "" {
 			formatIssue.WebURL = fmt.Sprintf("%s://%s/browse/%s", u.Scheme, u.Host, issue.Key)
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if u, err := url.Parse(issue.Self); err == nil {
formatIssue.WebURL = fmt.Sprintf("%s://%s/browse/%s", u.Scheme, u.Host, issue.Key)
}
if u, err := url.Parse(issue.Self); err == nil &&
(u.Scheme == "http" || u.Scheme == "https") &&
u.Host != "" {
formatIssue.WebURL = fmt.Sprintf("%s://%s/browse/%s", u.Scheme, u.Host, issue.Key)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/jira/ohssService.go` around lines 75 - 77, The WebURL construction using
url.Parse(issue.Self) can produce malformed values when Parse returns a relative
URL (empty Scheme/Host); update the logic around url.Parse(issue.Self) (the
block that sets formatIssue.WebURL) to validate that u.Scheme is "http" or
"https" and u.Host is non-empty before formatting "%s://%s/browse/%s"; if those
checks fail, do not build the WebURL (leave it empty or use a safe fallback),
and add unit tests for relative/malformed issue.Self inputs to cover this case.

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.

2 participants