Skip to content
Merged
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
47 changes: 47 additions & 0 deletions Rover_Lookup/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Python
build/
develop-eggs/
dist/
downloads/
*.egg
*.egg-info/
eggs/
.eggs/
.installed.cfg
lib/
lib64/
MANIFEST
parts/
*__pycache__*/
*.py[cod]
*$py.class
.Python
sdist/
*.so
var/
wheels/

# Testing
.coverage
coverage
htmlcov/
.nox/
.pytest_cache/
.tox*/

# IDEs
.idea/
*.swo
*.swp
.vscode/
.vscodesettings.json

# OS
.DS_Store
.env
*.pem
Thumbs.db
*venv/

# Logs
*.log
122 changes: 122 additions & 0 deletions Rover_Lookup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Rover_Lookup

A Python package for translating GitHub usernames to Red Hat Associate email addresses using LDAP queries against the Red Hat Rover service.

## Overview

This package queries the Red Hat Rover LDAP service to find Red Hat Associates based on their GitHub profile information stored in the `rhatSocialURL` field and returns their email addresses from multiple fields (`rhatPrimaryMail`, `mail`, and `rhatPreferredAlias`).

## Installation

1. Install the required dependencies:
```bash
pip install -r requirements.txt [-r test-requirements.txt]
```

2. Add the Rover_Lookup package to your Python path or install it locally.

## Usage

### Basic Usage

```python
from Rover_Lookup import github_username_to_emails

# Look up email addresses for a GitHub username
emails = github_username_to_emails("github-username")

if emails is None:
print("LDAP query failed")
elif not emails:
print("No email addresses found")
else:
print(f"Found emails: {emails}")
```

### Advanced Usage with Custom LDAP Settings

```python
from Rover_Lookup import github_username_to_emails

emails = github_username_to_emails(
github_username="github-username",
ldap_server="ldap://your-rover-server.com",
ldap_base_dn="ou=users,dc=redhat,dc=com",
ldap_bind_dn="cn=bind-user,dc=redhat,dc=com",
ldap_password="your-password"
)
```

### Enabling Debug Logging

```python
from Rover_Lookup import configure_logging
import logging

# Configure logging to see debug information
configure_logging(level=logging.DEBUG)
```

## Function Reference

### `github_username_to_emails(github_username, **kwargs)`

Translate a GitHub username to Red Hat Associate email addresses via LDAP lookup.

**Parameters:**
- `github_username` (str): The GitHub username to look up
- `ldap_server` (str, optional): LDAP server address (default: "ldap://ldap.corp.redhat.com")
- `ldap_base_dn` (str, optional): Base DN for LDAP search (default: "ou=users,dc=redhat,dc=com")
- `ldap_bind_dn` (str, optional): DN for LDAP authentication (default: anonymous bind)
- `ldap_password` (str, optional): Password for LDAP authentication

**Returns:**
- `List[str]`: List of unique email addresses if found
- `[]`: Empty list if no email addresses found in the record(s)
- `None`: If the LDAP query failed

**Behavior:**
- Constructs an LDAP filter based on `rhatSocialURL` matching `Github->https://github.com/{username}`
- Searches for Red Hat Associates with the matching GitHub profile
- Extracts email addresses from `rhatPrimaryMail`, `mail`, and `rhatPreferredAlias` fields
- Returns a deduplicated, sorted list of email addresses
- Handles multiple records by combining email addresses from all matching entries
- Logs errors using the standard Python logger for debugging

## LDAP Query Details

The package constructs LDAP queries with the following characteristics:

- **Filter**: `(rhatSocialURL=Github->https://github.com/{username})`
- **Scope**: Subtree search
- **Attributes**: `['rhatPrimaryMail', 'mail', 'rhatPreferredAlias']`

The `rhatSocialURL` field contains values in the format:
```
Github->https://github.com/username
```

## Error Handling

The function handles various error conditions:

- **Invalid input**: Empty GitHub username
- **Missing dependencies**: ldap3 library not installed
- **LDAP errors**: Connection failures, authentication issues, search errors
- **No results**: No matching records found
- **Empty emails**: Records found but no email addresses in the expected fields

All errors are logged using the Python `logging` module for debugging purposes.

## Example

See `example.py` for a complete usage example with logging configuration.

## Requirements

- Python 3.9+
- ldap3 >= 2.9.0

## License

GNU Lesser General Public License, Version 2.1, February 1999
11 changes: 11 additions & 0 deletions Rover_Lookup/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
Rover_Lookup - A Python package for translating GitHub usernames to Red Hat Associate email addresses.

This package queries the Red Hat Rover LDAP service to find Associates based on their
GitHub profile information and returns their email addresses.
"""

from .lookup import github_username_to_emails

__version__ = "1.0.0"
__all__ = ["github_username_to_emails"]
45 changes: 45 additions & 0 deletions Rover_Lookup/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""
Example usage of the Rover_Lookup package.

This script demonstrates how to use the github_username_to_emails function
to look up Red Hat Associate email addresses based on their GitHub username.
"""

import logging

from Rover_Lookup import github_username_to_emails


def main():
# Configure logging to see debug information
logging.getLogger().setLevel(logging.DEBUG)

# Example GitHub username (replace with actual username)
github_username = "ninja-quokka"

print(f"Looking up email addresses for GitHub username: {github_username}")

# Call the lookup function
# Note: You may need to provide LDAP connection parameters depending on your setup
emails = github_username_to_emails(
github_username=github_username,
# Uncomment and modify these if you need custom LDAP settings:
# ldap_server="ldap://your-rover-server.com",
# ldap_base_dn="ou=users,dc=example,dc=com",
# ldap_bind_dn="cn=your-bind-user,dc=example,dc=com",
# ldap_password="your-password"
)

if emails is None:
print("❌ LDAP query failed. Check the logs for details.")
elif not emails:
print("📭 No email addresses found for this GitHub username.")
else:
print(f"✅ Found {len(emails)} email address(es):")
for i, email in enumerate(emails, 1):
print(f" {i}. {email}")


if __name__ == "__main__":
main()
144 changes: 144 additions & 0 deletions Rover_Lookup/lookup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"""
LDAP lookup functions for translating GitHub usernames to Red Hat Associate email addresses
"""

import logging
from typing import List, Optional
import warnings

# Ignore deprecation warnings related to pyasn1's use of typeMap and tagMap
# which are triggered by ldap3's use of pyasn1.
warnings.filterwarnings(
"ignore",
message=r"(tag|type)Map is deprecated. Please use (TAG|TYPE)_MAP instead.",
category=DeprecationWarning,
module="pyasn1.codec.ber.encoder",
)
from ldap3 import Connection, SUBTREE # noqa: E402
from ldap3.core.exceptions import LDAPException # noqa: E402

logger = logging.getLogger(__name__)


def github_username_to_emails(
github_username: str,
ldap_server: Optional[str] = None,
ldap_base_dn: Optional[str] = None,
ldap_bind_dn: Optional[str] = None,
ldap_password: Optional[str] = None,
) -> Optional[List[str]]:
"""
Translate a GitHub username to Red Hat Associate email addresses via LDAP lookup.

Args:
github_username (str): The GitHub username to look up
ldap_server (str, optional): LDAP server address; if None, uses default Rover server
ldap_base_dn (str, optional): Base DN for LDAP search; if None, uses default
ldap_bind_dn (str, optional): DN for LDAP authentication; if None, uses anonymous bind
ldap_password (str, optional): Password for LDAP authentication

Returns:
Optional[List[str]]: List of unique email addresses if found, empty list if no emails,
None if query failed
"""
if not github_username:
logger.error("GitHub username cannot be empty")
return None

# Default LDAP configuration for Red Hat Rover service
# FIXME: These should be configured via config file.
if ldap_server is None:
ldap_server = "ldap://ldap.corp.redhat.com" # Default Rover LDAP server
if ldap_base_dn is None:
ldap_base_dn = "ou=users,dc=redhat,dc=com" # Default base DN

# Construct the LDAP filter to match the GitHub "Professional Social Media" URL.
# The rhatSocialURL field contains values like "Github->https://github.com/username".
github_url = f"https://github.com/{github_username}"
ldap_filter = f"(rhatSocialURL=Github->{github_url})"

# Attributes to retrieve (email fields)
attributes = ["rhatPrimaryMail", "mail", "rhatPreferredAlias"]

try:
# Create LDAP server connection; if credentials were not provided, the connection
# will use an anonymous binding.
conn = Connection(ldap_server, ldap_bind_dn, ldap_password, auto_bind=True)
except LDAPException as e:
msg = f"Error connecting to LDAP server {ldap_server!r}: {str(e)}"
if "redhat.com" in ldap_server and "invalid server address" in str(e):
msg += "; is the VPN active?"
logger.error(msg)
return None
except Exception as e:
logger.error(
f"Unexpected error connecting to LDAP server {ldap_server!r}: {str(e)}"
)
return None

logger.debug(f"Searching for GitHub username: {github_username}")
logger.debug(f"LDAP filter: {ldap_filter}")

try:
# Perform the LDAP search
success = conn.search(
search_base=ldap_base_dn,
search_filter=ldap_filter,
search_scope=SUBTREE,
attributes=attributes,
)

if not success:
logger.warning(f"LDAP search failed for GitHub username: {github_username}")
return None

entries = conn.entries
logger.debug(f"Found {len(entries)} LDAP entries")

if not entries:
logger.info(f"No LDAP entries found for GitHub username: {github_username}")
return []

# Extract email addresses from all entries
email_addresses = set() # Use set to automatically handle uniqueness

for entry in entries:
logger.debug(f"Processing LDAP entry: {entry.entry_dn}")

# Check each email field
for attr_name in attributes:
if hasattr(entry, attr_name):
attr_value = getattr(entry, attr_name)
if attr_value:
# Handle both single values and lists
emails = (
attr_value.value
if isinstance(attr_value.value, list)
else [attr_value.value]
)
for email in emails:
if email: # Skip empty strings
email_addresses.add(str(email).strip())

# Convert set to sorted list for consistent output
result_emails = sorted(list(email_addresses))

logger.debug(
f"Found {len(result_emails)} unique email addresses for GitHub username: {github_username}"
)
logger.debug(f"Email addresses: {result_emails}")

return result_emails

except LDAPException as e:
logger.error(
f"LDAP error while looking up GitHub username {github_username}: {str(e)}"
)
return None
except Exception as e:
logger.error(
f"Unexpected error while looking up GitHub username {github_username}: {str(e)}"
)
return None
finally:
conn.unbind()
1 change: 1 addition & 0 deletions Rover_Lookup/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ldap3>=2.9.0
Loading