Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/mcp_atlassian/confluence/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,12 @@ def from_env(cls) -> "ConfluenceConfig":
oauth_config = get_oauth_config_from_env()
auth_type = None

# Use the shared utility function directly
is_cloud = is_atlassian_cloud_url(url)
if url:
is_cloud = is_atlassian_cloud_url(url)
else:
# When no URL, let the @property is_cloud method handle detection
# It will check for OAuth cloud_id or return False
is_cloud = False

if oauth_config:
# OAuth is available - could be full config or minimal config for user-provided tokens
Expand Down
8 changes: 6 additions & 2 deletions src/mcp_atlassian/jira/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,12 @@ def from_env(cls) -> "JiraConfig":
oauth_config = get_oauth_config_from_env()
auth_type = None

# Use the shared utility function directly
is_cloud = is_atlassian_cloud_url(url)
if url:
is_cloud = is_atlassian_cloud_url(url)
else:
# When no URL, let the @property is_cloud method handle detection
# It will check for OAuth cloud_id or return False
is_cloud = False

if oauth_config:
# OAuth is available - could be full config or minimal config for user-provided tokens
Expand Down
6 changes: 4 additions & 2 deletions src/mcp_atlassian/utils/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ def get_available_services() -> dict[str, bool | None]:
logger.info(
"Using Confluence Server/Data Center authentication (PAT or Basic Auth)"
)
elif os.getenv("ATLASSIAN_OAUTH_ENABLE", "").lower() in ("true", "1", "yes"):

if os.getenv("ATLASSIAN_OAUTH_ENABLE", "").lower() in ("true", "1", "yes"):
confluence_is_setup = True
logger.info(
"Using Confluence minimal OAuth configuration - expecting user-provided tokens via headers"
Expand Down Expand Up @@ -112,7 +113,8 @@ def get_available_services() -> dict[str, bool | None]:
logger.info(
"Using Jira Server/Data Center authentication (PAT or Basic Auth)"
)
elif os.getenv("ATLASSIAN_OAUTH_ENABLE", "").lower() in ("true", "1", "yes"):

if os.getenv("ATLASSIAN_OAUTH_ENABLE", "").lower() in ("true", "1", "yes"):
jira_is_setup = True
logger.info(
"Using Jira minimal OAuth configuration - expecting user-provided tokens via headers"
Expand Down
64 changes: 64 additions & 0 deletions tests/unit/confluence/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,67 @@ def test_is_cloud_oauth_with_cloud_id():
oauth_config=oauth_config,
)
assert config.is_cloud is True


def test_from_env_oauth_enable_no_url():
"""Test BYOT OAuth mode - ATLASSIAN_OAUTH_ENABLE=true without URL or cloud_id."""
with patch.dict(
os.environ,
{
"ATLASSIAN_OAUTH_ENABLE": "true",
# No CONFLUENCE_URL set
# No ATLASSIAN_OAUTH_CLOUD_ID set
},
clear=True,
):
config = ConfluenceConfig.from_env()
assert config.auth_type == "oauth"
assert config.is_cloud is False


def test_from_env_oauth_enable_no_url_with_cloud_id():
"""Test BYOT OAuth mode - ATLASSIAN_OAUTH_ENABLE=true without URL but with cloud_id."""
with patch.dict(
os.environ,
{
"ATLASSIAN_OAUTH_ENABLE": "true",
"ATLASSIAN_OAUTH_CLOUD_ID": "test-cloud-id",
# No CONFLUENCE_URL set
},
clear=True,
):
config = ConfluenceConfig.from_env()
assert config.auth_type == "oauth"
assert config.is_cloud is True


def test_from_env_oauth_enable_with_cloud_url():
"""Test BYOT OAuth mode - ATLASSIAN_OAUTH_ENABLE=true with Cloud URL."""
with patch.dict(
os.environ,
{
"ATLASSIAN_OAUTH_ENABLE": "true",
"CONFLUENCE_URL": "https://test.atlassian.net/wiki",
},
clear=True,
):
config = ConfluenceConfig.from_env()
assert config.url == "https://test.atlassian.net/wiki"
assert config.auth_type == "oauth"
assert config.is_cloud is True # Should be Cloud based on URL


def test_from_env_oauth_enable_with_server_url():
"""Test BYOT OAuth mode - ATLASSIAN_OAUTH_ENABLE=true with Server URL."""
with patch.dict(
os.environ,
{
"ATLASSIAN_OAUTH_ENABLE": "true",
"CONFLUENCE_URL": "https://confluence.example.com",
},
clear=True,
):
config = ConfluenceConfig.from_env()
assert config.url == "https://confluence.example.com"
assert config.auth_type == "oauth"
assert config.is_cloud is False # Should be Server based on URL
64 changes: 64 additions & 0 deletions tests/unit/jira/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,67 @@ def test_is_cloud_oauth_with_cloud_id():
oauth_config=oauth_config,
)
assert config.is_cloud is True


def test_from_env_oauth_enable_no_url():
"""Test BYOT OAuth mode - ATLASSIAN_OAUTH_ENABLE=true without URL or cloud_id."""
with patch.dict(
os.environ,
{
"ATLASSIAN_OAUTH_ENABLE": "true",
# No JIRA_URL set
# No ATLASSIAN_OAUTH_CLOUD_ID set
},
clear=True,
):
config = JiraConfig.from_env()
assert config.auth_type == "oauth"
assert config.is_cloud is False


def test_from_env_oauth_enable_no_url_with_cloud_id():
"""Test BYOT OAuth mode - ATLASSIAN_OAUTH_ENABLE=true without URL but with cloud_id."""
with patch.dict(
os.environ,
{
"ATLASSIAN_OAUTH_ENABLE": "true",
"ATLASSIAN_OAUTH_CLOUD_ID": "test-cloud-id",
# No JIRA_URL set
},
clear=True,
):
config = JiraConfig.from_env()
assert config.auth_type == "oauth"
assert config.is_cloud is True


def test_from_env_oauth_enable_with_cloud_url():
"""Test BYOT OAuth mode - ATLASSIAN_OAUTH_ENABLE=true with Cloud URL."""
with patch.dict(
os.environ,
{
"ATLASSIAN_OAUTH_ENABLE": "true",
"JIRA_URL": "https://test.atlassian.net",
},
clear=True,
):
config = JiraConfig.from_env()
assert config.url == "https://test.atlassian.net"
assert config.auth_type == "oauth"
assert config.is_cloud is True


def test_from_env_oauth_enable_with_server_url():
"""Test BYOT OAuth mode - ATLASSIAN_OAUTH_ENABLE=true with Server URL."""
with patch.dict(
os.environ,
{
"ATLASSIAN_OAUTH_ENABLE": "true",
"JIRA_URL": "https://jira.example.com",
},
clear=True,
):
config = JiraConfig.from_env()
assert config.url == "https://jira.example.com"
assert config.auth_type == "oauth"
assert config.is_cloud is False
81 changes: 81 additions & 0 deletions tests/unit/utils/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,84 @@ def test_invalid_environment_variables(self, invalid_vars, caplog):
_assert_authentication_logs(
caplog, "not_configured", ["confluence", "jira"]
)

def test_oauth_enable_without_urls(self, caplog):
"""Test BYOT OAuth mode - ATLASSIAN_OAUTH_ENABLE=true without service URLs."""
with MockEnvironment.clean_env():
import os

os.environ["ATLASSIAN_OAUTH_ENABLE"] = "true"

result = get_available_services()
_assert_service_availability(
result, confluence_expected=True, jira_expected=True
)
# Should log the minimal OAuth configuration messages
assert_log_contains(
caplog,
"INFO",
"Using Confluence minimal OAuth configuration - expecting user-provided tokens via headers",
)
assert_log_contains(
caplog,
"INFO",
"Using Jira minimal OAuth configuration - expecting user-provided tokens via headers",
)

def test_oauth_enable_with_urls(self, caplog):
"""Test BYOT OAuth mode - ATLASSIAN_OAUTH_ENABLE=true with service URLs."""
with MockEnvironment.clean_env():
import os

os.environ["ATLASSIAN_OAUTH_ENABLE"] = "true"
os.environ["CONFLUENCE_URL"] = "https://test.atlassian.net/wiki"
os.environ["JIRA_URL"] = "https://test.atlassian.net"

result = get_available_services()
_assert_service_availability(
result, confluence_expected=True, jira_expected=True
)
# Should log the minimal OAuth configuration messages (overrides URL-based detection)
assert_log_contains(
caplog,
"INFO",
"Using Confluence minimal OAuth configuration - expecting user-provided tokens via headers",
)
assert_log_contains(
caplog,
"INFO",
"Using Jira minimal OAuth configuration - expecting user-provided tokens via headers",
)

@pytest.mark.parametrize(
"oauth_enable_value", ["true", "True", "TRUE", "1", "yes", "YES"]
)
def test_oauth_enable_value_variations(self, oauth_enable_value, caplog):
"""Test various ATLASSIAN_OAUTH_ENABLE value formats."""
with MockEnvironment.clean_env():
import os

os.environ["ATLASSIAN_OAUTH_ENABLE"] = oauth_enable_value

result = get_available_services()
_assert_service_availability(
result, confluence_expected=True, jira_expected=True
)

@pytest.mark.parametrize(
"oauth_disable_value", ["false", "False", "FALSE", "0", "no", "NO", ""]
)
def test_oauth_enable_disabled_values(self, oauth_disable_value, caplog):
"""Test values that should NOT enable BYOT OAuth mode."""
with MockEnvironment.clean_env():
import os

os.environ["ATLASSIAN_OAUTH_ENABLE"] = oauth_disable_value

result = get_available_services()
_assert_service_availability(
result, confluence_expected=False, jira_expected=False
)
_assert_authentication_logs(
caplog, "not_configured", ["confluence", "jira"]
)
Loading