-
Notifications
You must be signed in to change notification settings - Fork 1
Fix: Jira dashboard config params not reaching notifier #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
1e5bed4
Fix: Jira dashboard config params not reaching notifier
dc-larsen e451758
Merge branch 'main' into fix/jira-dashboard-config-params
lelia aabf89b
Add script to verify JIRA config
lelia 27bd5f3
Add unittests for notifier functionality, plus README for tests
lelia 678d928
Update ignore file to include necessary scripts
lelia b267d42
Update parameter docs to provide local verification option
lelia 5ec0cb5
Merge branch 'main' into fix/jira-dashboard-config-params
lelia 35a5e75
Guard against empty env vars overriding valid config
dc-larsen 9a685ff
Merge branch 'main' into fix/jira-dashboard-config-params
lelia File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| #!/usr/bin/env python3 | ||
| """ | ||
| Verify that dashboard-provided Jira config (via Socket API) flows into JiraNotifier. | ||
|
|
||
| This script does NOT call Jira. It only loads Socket Basics config, builds the | ||
| NotificationManager, and inspects JiraNotifier params. | ||
|
|
||
| Expected env vars: | ||
| - SOCKET_SECURITY_API_KEY or SOCKET_SECURITY_API_TOKEN (required) | ||
| - SOCKET_ORG or SOCKET_ORG_SLUG (recommended; auto-discovery is attempted) | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import json | ||
| import logging | ||
| import os | ||
| import sys | ||
| from pathlib import Path | ||
|
|
||
| from socket_basics.core.config import merge_json_and_env_config | ||
| from socket_basics.core.notification.manager import NotificationManager | ||
|
|
||
|
|
||
| def _summarize_jira(notifier) -> dict: | ||
| return { | ||
| "server": getattr(notifier, "server", None), | ||
| "project": getattr(notifier, "project", None), | ||
| "email": getattr(notifier, "email", None), | ||
| "api_token_present": bool(getattr(notifier, "api_token", None)), | ||
| } | ||
|
|
||
|
|
||
| def _load_dotenv(dotenv_path: Path) -> None: | ||
| if not dotenv_path.exists(): | ||
| return | ||
| try: | ||
| for raw_line in dotenv_path.read_text().splitlines(): | ||
| line = raw_line.strip() | ||
| if not line or line.startswith("#"): | ||
| continue | ||
| if line.startswith("export "): | ||
| line = line[len("export "):].strip() | ||
| if "=" not in line: | ||
| continue | ||
| key, val = line.split("=", 1) | ||
| key = key.strip() | ||
| val = val.strip().strip("'").strip('"') | ||
| if key and key not in os.environ: | ||
| os.environ[key] = val | ||
| except Exception: | ||
| # Best-effort; do not fail if .env parsing is imperfect | ||
| pass | ||
|
|
||
|
|
||
| def main() -> int: | ||
| logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s") | ||
|
|
||
| repo_root = Path(__file__).resolve().parents[1] | ||
| _load_dotenv(repo_root / ".env") | ||
|
|
||
| try: | ||
| config_dict = merge_json_and_env_config() | ||
| except Exception as exc: | ||
| print(f"ERROR: failed to load config: {exc}") | ||
| return 2 | ||
|
|
||
| # Load notifications.yaml and build manager | ||
| try: | ||
| import yaml | ||
|
|
||
| cfg_path = repo_root / "socket_basics" / "notifications.yaml" | ||
| notif_cfg = None | ||
| if cfg_path.exists(): | ||
| with open(cfg_path, "r") as f: | ||
| notif_cfg = yaml.safe_load(f) | ||
| except Exception as exc: | ||
| print(f"ERROR: failed to load notifications.yaml: {exc}") | ||
| return 2 | ||
|
|
||
| nm = NotificationManager(notif_cfg, app_config=config_dict) | ||
| nm.load_from_config() | ||
|
|
||
| jira_notifiers = [n for n in nm.notifiers if getattr(n, "name", "").lower() == "jira"] | ||
| if not jira_notifiers: | ||
| print("Jira notifier not enabled. Check that dashboard config includes jira_url or env provides JIRA_URL.") | ||
| return 1 | ||
|
|
||
| # Print details for first Jira notifier | ||
| summary = _summarize_jira(jira_notifiers[0]) | ||
| print("Jira notifier config summary:") | ||
| print(json.dumps(summary, indent=2)) | ||
|
|
||
| missing = [k for k, v in summary.items() if k in ("server", "project", "email") and not v] | ||
| if missing: | ||
| print(f"WARNING: missing expected fields: {', '.join(missing)}") | ||
| return 1 | ||
|
|
||
| print("OK: Jira dashboard config appears to be wired into JiraNotifier.") | ||
| return 0 | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| sys.exit(main()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # Tests | ||
|
|
||
| Quick-start for running tests locally: | ||
|
|
||
| ```bash | ||
| ./venv/bin/python -m pytest | ||
| ``` | ||
|
|
||
| Notes: | ||
| - Tests are lightweight and should not require external services. | ||
| - Use the local config-wiring script for Jira setup validation: | ||
| `./venv/bin/python scripts/verify_jira_dashboard_config.py` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| from socket_basics.core.notification.jira_notifier import JiraNotifier | ||
| from socket_basics.core.config import normalize_api_config | ||
|
|
||
|
|
||
| def test_jira_notifier_reads_new_param_names(): | ||
| n = JiraNotifier( | ||
| { | ||
| "jira_url": "https://acme.atlassian.net", | ||
| "jira_project": "SEC", | ||
| "jira_email": "bot@acme.example", | ||
| "jira_api_token": "token123", | ||
| } | ||
| ) | ||
| assert n.server == "https://acme.atlassian.net" | ||
| assert n.project == "SEC" | ||
| assert n.email == "bot@acme.example" | ||
| assert n.api_token == "token123" | ||
|
|
||
|
|
||
| def test_jira_notifier_falls_back_to_auth_dict(): | ||
| n = JiraNotifier( | ||
| { | ||
| "jira_url": "https://acme.atlassian.net", | ||
| "jira_project": "SEC", | ||
| "auth": {"email": "auth@acme.example", "api_token": "auth-token"}, | ||
| } | ||
| ) | ||
| assert n.email == "auth@acme.example" | ||
| assert n.api_token == "auth-token" | ||
|
|
||
|
|
||
| def test_normalize_api_config_maps_jira_keys(): | ||
| normalized = normalize_api_config( | ||
| { | ||
| "jiraUrl": "https://acme.atlassian.net", | ||
| "jiraProject": "SEC", | ||
| "jiraEmail": "bot@acme.example", | ||
| "jiraApiToken": "token123", | ||
| } | ||
| ) | ||
| assert normalized["jira_url"] == "https://acme.atlassian.net" | ||
| assert normalized["jira_project"] == "SEC" | ||
| assert normalized["jira_email"] == "bot@acme.example" | ||
| assert normalized["jira_api_token"] == "token123" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import os | ||
|
|
||
| from socket_basics.core.notification.manager import NotificationManager | ||
|
|
||
|
|
||
| def _base_cfg(): | ||
| return { | ||
| "notifiers": { | ||
| "jira": { | ||
| "module_path": "socket_basics.core.notification.jira_notifier", | ||
| "class": "JiraNotifier", | ||
| "parameters": [ | ||
| {"name": "jira_url", "env_variable": "INPUT_JIRA_URL", "type": "str"}, | ||
| {"name": "jira_project", "env_variable": "INPUT_JIRA_PROJECT", "type": "str"}, | ||
| {"name": "jira_email", "env_variable": "INPUT_JIRA_EMAIL", "type": "str"}, | ||
| {"name": "jira_api_token", "env_variable": "INPUT_JIRA_API_TOKEN", "type": "str"}, | ||
| ], | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| def test_param_precedence_app_config_over_env_and_default(monkeypatch): | ||
| cfg = _base_cfg() | ||
| # default should be overridden by env, then app_config should win | ||
| cfg["notifiers"]["jira"]["parameters"][0]["default"] = "https://default.example" | ||
| monkeypatch.setenv("INPUT_JIRA_URL", "https://env.example") | ||
|
|
||
| nm = NotificationManager(cfg, app_config={"jira_url": "https://app.example"}) | ||
| nm.load_from_config() | ||
|
|
||
| jira = next(n for n in nm.notifiers if getattr(n, "name", "") == "jira") | ||
| assert jira.server == "https://app.example" | ||
|
|
||
|
|
||
| def test_param_precedence_env_over_default(monkeypatch): | ||
| cfg = _base_cfg() | ||
| cfg["notifiers"]["jira"]["parameters"][0]["default"] = "https://default.example" | ||
| monkeypatch.setenv("INPUT_JIRA_URL", "https://env.example") | ||
|
|
||
| nm = NotificationManager(cfg, app_config={}) | ||
| nm.load_from_config() | ||
|
|
||
| jira = next(n for n in nm.notifiers if getattr(n, "name", "") == "jira") | ||
| assert jira.server == "https://env.example" | ||
|
|
||
|
|
||
| def test_param_precedence_default_used_when_no_env_or_app_config(monkeypatch): | ||
| cfg = _base_cfg() | ||
| # Use default for jira_project while enabling via app_config jira_url | ||
| cfg["notifiers"]["jira"]["parameters"][1]["default"] = "DEFAULTPROJ" | ||
| monkeypatch.delenv("INPUT_JIRA_PROJECT", raising=False) | ||
|
|
||
| nm = NotificationManager(cfg, app_config={"jira_url": "https://app.example"}) | ||
| nm.load_from_config() | ||
|
|
||
| jira = next(n for n in nm.notifiers if getattr(n, "name", "") == "jira") | ||
| assert jira.project == "DEFAULTPROJ" | ||
|
|
||
|
|
||
| def test_jira_enabled_via_app_config(monkeypatch): | ||
| cfg = _base_cfg() | ||
| monkeypatch.delenv("INPUT_JIRA_URL", raising=False) | ||
|
|
||
| nm = NotificationManager(cfg, app_config={"jira_url": "https://app.example"}) | ||
| nm.load_from_config() | ||
|
|
||
| jira = next(n for n in nm.notifiers if getattr(n, "name", "") == "jira") | ||
| assert jira.server == "https://app.example" |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.