Commit 2e1a03a9 authored by Jan Reimes's avatar Jan Reimes
Browse files

feat(credentials): enhance credential handling and prompting options

- Add EOL_PROMPT environment variable to control interactive prompting.
- Update CLI argument for prompt_credentials to accept None.
- Modify resolve_credentials function to read prompt behavior from EOL_PROMPT if not explicitly set.
- Document credential resolution order and usage in QUICK_REFERENCE.md.
parent 265979a6
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -10,6 +10,10 @@ EOL_USERNAME=your_username_here
# Your ETSI Online password
EOL_PASSWORD=your_password_here

# Whether to prompt for credentials when missing (default: false unless EOL_PROMPT=true)
# Set to "true", "1", or "yes" to enable interactive prompting
EOL_PROMPT=false

# HTTP Cache Configuration
# Controls caching behavior for all HTTP requests

+67 −0
Original line number Diff line number Diff line
@@ -566,3 +566,70 @@ Get-Item "$env:USERPROFILE\.tdoc-crawler\http-cache.sqlite3" | Select-Object Len

**Q: Is the cache shared between commands?**
**A:** Yes! All commands share the same cache database at `~/.tdoc-crawler/http-cache.sqlite3`

## 🔐 ETSI Online (EOL) Credentials

Credentials are used for authenticated access to the 3GPP portal. Most commands work without credentials using unauthenticated endpoints. Credentials are only prompted or required when:

- Crawling meeting metadata from authenticated portal endpoints
- Fetching TDoc metadata that requires authentication

### Credential Resolution

Credentials are resolved in this order:

1. **CLI parameters** (`--eol-username`, `--eol-password`)
2. **Environment variables** (`EOL_USERNAME`, `EOL_PASSWORD`)
3. **Interactive prompt** (only if `EOL_PROMPT=true` or `--prompt-credentials` is set)

### Configuration

**Environment Variables** (add to `.env` file):

```bash
EOL_USERNAME=your_username      # Your ETSI Online account username
EOL_PASSWORD=your_password      # Your ETSI Online account password
EOL_PROMPT=false                # Set to "true" to enable interactive prompting
```

**CLI Parameters** (for `crawl-meetings` and `query-tdocs`):

```bash
--eol-username USER             # ETSI Online username
--eol-password PASS             # ETSI Online password
--prompt-credentials            # Prompt for credentials if missing
--no-prompt-credentials         # Never prompt (default)
```

### No Prompting by Default

By default, the CLI **does not prompt** for credentials. This means:

| Scenario | Behavior |
|----------|----------|
| Credentials in `.env` | Used automatically |
| Credentials via CLI args | Used automatically |
| No credentials provided | Command proceeds without auth (uses unauthenticated endpoints) |
| `EOL_PROMPT=true` | Prompts interactively when credentials missing |

### Examples

```bash
# Using environment variables
export EOL_USERNAME=myuser
export EOL_PASSWORD=mypass
tdoc-crawler crawl-meetings

# Using CLI parameters
tdoc-crawler crawl-meetings --eol-username myuser --eol-password mypass

# Enabling interactive prompting
export EOL_PROMPT=true
tdoc-crawler crawl-meetings  # Will prompt if credentials missing

# Or use CLI flag
tdoc-crawler crawl-meetings --prompt-credentials

# Running without credentials (uses unauthenticated endpoints)
tdoc-crawler crawl-meetings  # Works, may be slower
```
+1 −1
Original line number Diff line number Diff line
@@ -190,7 +190,7 @@ def crawl_meetings(
    verbose: VerboseOption = False,
    eol_username: EolUsernameOption = None,
    eol_password: EolPasswordOption = None,
    prompt_credentials: PromptCredentialsOption = True,
    prompt_credentials: PromptCredentialsOption = None,
) -> None:
    """Crawl meeting metadata from 3GPP portal."""
    subgroups = parse_subgroups(subgroup)
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ NoFetchOption = Annotated[
EolUsernameOption = Annotated[str | None, typer.Option("--eol-username", help="ETSI Online account username")]
EolPasswordOption = Annotated[str | None, typer.Option("--eol-password", help="ETSI Online account password")]
PromptCredentialsOption = Annotated[
    bool,
    bool | None,
    typer.Option("--prompt-credentials/--no-prompt-credentials", help="Prompt for credentials when missing"),
]
IncludeWithoutFilesOption = Annotated[
+20 −3
Original line number Diff line number Diff line
@@ -125,16 +125,33 @@ def build_limits(
def resolve_credentials(
    username: str | None,
    password: str | None,
    prompt: bool,
    prompt: bool | None = None,
) -> PortalCredentials | None:
    """Resolve portal credentials from parameters, environment, or prompt."""
    """Resolve portal credentials from parameters, environment, or prompt.

    Resolution order:
    1. CLI parameters (username, password)
    2. Environment variables (EOL_USERNAME, EOL_PASSWORD)
    3. Interactive prompt (if EOL_PROMPT=true or prompt=True)

    Args:
        username: CLI-provided username
        password: CLI-provided password
        prompt: Whether to prompt interactively. If None, reads from EOL_PROMPT env var.

    Returns:
        PortalCredentials instance if resolved, None otherwise
    """
    resolved_username = username or os.getenv("EOL_USERNAME")
    resolved_password = password or os.getenv("EOL_PASSWORD")

    if resolved_username and resolved_password:
        return PortalCredentials(username=resolved_username, password=resolved_password)

    if prompt:
    # Only prompt if explicitly requested via parameter or EOL_PROMPT env var
    should_prompt = prompt if prompt is not None else os.getenv("EOL_PROMPT", "").lower() in ("true", "1", "yes")

    if should_prompt:
        resolved_username = typer.prompt("EOL username")
        resolved_password = typer.prompt("EOL password", hide_input=True)
        return PortalCredentials(username=resolved_username, password=resolved_password)