# Chef Server Integration Testing Guide

This guide explains how to test the authenticated Chef Server integration with a **live Chef Server**, including secrets redaction functionality.

> **NOTE: Testing Without Chef Server?** See [Mock Chef Server Testing Guide](MOCK_CHEF_SERVER.md) for testing with mocked HTTP responses - no Chef Server required!

## Quick Links

- **[Mock Testing Guide](MOCK_CHEF_SERVER.md)** - Test without a real Chef Server (recommended for development)
- **Unit tests** - `tests/unit/test_chef_server_client.py` (repository source)
- **Mock integration tests** - `tests/integration/test_chef_server_mock.py` (repository source)
- **This Guide** - Testing with a live Chef Server instance

## Prerequisites

1. **Chef Server Access**: You need access to a Chef Server instance (Chef Infra Server, Hosted Chef, or AWS OpsWorks Chef Automate)
2. **Chef Client Credentials**: A client or user account with API access
3. **RSA Private Key**: The PEM-encoded private key for authentication

## Setting Up Test Environment

### Option 1: Using Chef Manage (Chef Server Web UI)

1. **Log into Chef Manage**:
   ```bash
   # Navigate to your Chef Server in a browser
   https://your-chef-server.example.com
   ```

2. **Create or Select a Client**:
   - Go to Policy → Clients
   - Create a new client or select an existing one
   - Download the private key (only shown once during creation)

3. **Note Your Organisation**:
   - Check the URL or dashboard for your organisation name
   - Common default is `"default"` or your company name

### Option 2: Using Chef Workstation CLI

1. **Install Chef Workstation**:
   ```bash
   # macOS
   brew install chef-workstation

   # Linux (see https://www.chef.io/downloads)
   ```

2. **Configure Knife**:
   ```bash
   knife configure
   # Enter your Chef Server URL, organisation, and user name
   ```

3. **Locate Your Credentials**:
   ```bash
   # Default location
   cat ~/.chef/client.pem
   ```

### Option 3: Local Test Chef Server (Docker)

For testing without production access, spin up a local Chef Server:

```bash
# Using Docker Compose
docker run -d \
  --name chef-server \
  -p 443:443 \
  chef/chef-server:latest

# Access container to create client
docker exec -it chef-server bash
chef-server-ctl user-create testuser Test User test@example.com password123
chef-server-ctl org-create testorg "Test Organisation" --association_user testuser
```

## Configuration

### Environment Variables Method (Recommended)

Set up environment variables for testing:

```bash
# Required
export CHEF_SERVER_URL="https://your-chef-server.example.com"
export CHEF_CLIENT_NAME="your-client-name"
export CHEF_CLIENT_KEY_PATH="/path/to/client.pem"

# Optional (defaults shown)
export CHEF_ORG="default"
```

### Direct Parameter Method

Alternatively, pass credentials directly to tools (useful for testing different configurations):

```bash
# See examples in CLI Testing section below
```

## Testing Secrets Redaction

### Test 1: Invalid Key Error (Redaction)

Test that malformed keys are redacted in error messages:

```bash
# Create a file with invalid key content
echo "-----BEGIN RSA PRIVATE KEY-----
INVALID_KEY_CONTENT_HERE
-----END RSA PRIVATE KEY-----" > /tmp/bad-key.pem

# Run validation (should fail with redacted key)
poetry run souschef validate-chef-server \
  --server-url "https://chef.example.com" \
  --organisation "default" \
  --client-name "testclient" \
  --client-key-path "/tmp/bad-key.pem"
```

**Expected Output**:
```
Failed: ***REDACTED***
# NOT: -----BEGIN RSA PRIVATE KEY----- INVALID_KEY_CONTENT_HERE ...
```

### Test 2: Authentication Failure (Redaction)

Test that authentication errors don't leak key material:

```bash
# Use a valid key format but wrong credentials
poetry run souschef validate-chef-server \
  --server-url "https://chef.example.com" \
  --organisation "wrong-org" \
  --client-name "wrong-client" \
  --client-key-path "/path/to/valid-key.pem"
```

**Expected Output**:
```
Failed: Authentication failed - check your Chef Server credentials
# NOT: Any output containing the actual key content
```

### Test 3: Connection Timeout (Safe Output)

Test network errors don't expose credentials:

```bash
# Use unreachable server
poetry run souschef validate-chef-server \
  --server-url "https://nonexistent.example.com" \
  --organisation "default" \
  --client-name "testclient" \
  --client-key-path "/path/to/client.pem"
```

**Expected Output**:
```
Failed: Connection timeout - could not reach https://nonexistent.example.com
# No key material in output
```

## CLI Testing

### Test Connection Validation

```bash
# Test with environment variables
poetry run souschef validate-chef-server \
  --server-url "$CHEF_SERVER_URL" \
  --organisation "$CHEF_ORG" \
  --client-name "$CHEF_CLIENT_NAME" \
  --client-key-path "$CHEF_CLIENT_KEY_PATH"
```

**Expected Success Output**:
```
Success: Successfully connected to Chef Server at https://your-chef-server.example.com/organizations/default
```

### Test Node Query

```bash
# Query all nodes
poetry run souschef query-chef-nodes \
  --search-query "*:*" \
  --server-url "$CHEF_SERVER_URL" \
  --organisation "$CHEF_ORG" \
  --client-name "$CHEF_CLIENT_NAME" \
  --client-key-path "$CHEF_CLIENT_KEY_PATH"
```

**Expected Output**:
```json
{
  "status": "success",
  "count": 5,
  "nodes": [
    {
      "name": "web-server-01",
      "roles": ["role[webserver]"],
      "environment": "production",
      "platform": "ubuntu",
      "ipaddress": "10.0.1.10",
      "fqdn": "web-server-01.example.com"
    },
    ...
  ]
}
```

### Test with Inline Key (Not Recommended in Production)

```bash
# Read key into variable
KEY_CONTENT=$(cat /path/to/client.pem)

# Pass inline (for testing only)
poetry run souschef validate-chef-server \
  --server-url "$CHEF_SERVER_URL" \
  --organisation "$CHEF_ORG" \
  --client-name "$CHEF_CLIENT_NAME" \
  --client-key "$KEY_CONTENT"
```

## MCP Tool Testing

### Using Claude Desktop

1. **Configure MCP Server**:

   Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or equivalent:

   ```json
   {
     "mcpServers": {
       "souschef": {
         "command": "poetry",
         "args": ["run", "python", "-m", "souschef.server"],
         "cwd": "/path/to/souschef",
         "env": {
           "CHEF_SERVER_URL": "https://your-chef-server.example.com",
           "CHEF_ORG": "default",
           "CHEF_CLIENT_NAME": "your-client",
           "CHEF_CLIENT_KEY_PATH": "/path/to/client.pem"
         }
       }
     }
   }
   ```

2. **Test in Claude Desktop**:

   Ask Claude:
   ```
   Use the validate_chef_server_connection tool to test the Chef Server connection.
   ```

   Then:
   ```
   Use get_chef_nodes to list all nodes in the Chef Server.
   ```

3. **Verify Redaction**:

   Intentionally break the configuration:
   ```json
   "CHEF_CLIENT_KEY_PATH": "/nonexistent/key.pem"
   ```

   Restart Claude Desktop and ask it to validate the connection. The error message should show `***REDACTED***` instead of any key material.

### Using MCP Inspector

For lower-level testing:

```bash
# Install MCP Inspector
npm install -g @modelcontextprotocol/inspector

# Run with SousChef
mcp-inspector poetry run python -m souschef.server
```

Navigate to `http://localhost:5173` and test tools interactively.

## Unit Test Verification

Run the secrets redaction test suite:

```bash
# Run all redaction tests
poetry run pytest tests/unit/test_chef_server_client.py::TestSecretsRedaction -v

# Run integration test for MCP tool redaction
poetry run pytest tests/unit/test_server.py::test_validate_chef_server_connection_redacts_keys -v

# Run all Chef Server tests
poetry run pytest tests/unit/test_chef_server_ui.py tests/unit/test_chef_server_client.py \
  tests/unit/test_server.py::test_validate_chef_server_connection_success \
  tests/unit/test_server.py::test_validate_chef_server_connection_redacts_keys \
  tests/unit/test_server.py::test_get_chef_nodes_success -v
```

## Debugging

### Enable Debug Logging

To see detailed request/response information (keys still redacted):

```bash
export LOG_LEVEL=DEBUG
poetry run souschef validate-chef-server \
  --server-url "$CHEF_SERVER_URL" \
  --organisation "$CHEF_ORG" \
  --client-name "$CHEF_CLIENT_NAME" \
  --client-key-path "$CHEF_CLIENT_KEY_PATH"
```

### Test Signature Generation

Use Python interactively to test auth headers:

```python
from souschef.core.chef_server import _build_auth_headers, _load_client_key

key = _load_client_key("/path/to/client.pem", None)
headers = _build_auth_headers(
    "GET",
    "/organizations/default/search/node?q=*:*",
    b"",
    "your-client-name",
    "2026-02-16T12:00:00Z",
    key
)

print(headers)
# Should see X-Ops-Authorization-1, X-Ops-Userid, etc.
```

### Common Issues

#### "Authentication failed" with valid credentials

- **Check organisation name**: Must match Chef Server configuration
- **Verify client name**: Case-sensitive
- **Key format**: Must be unencrypted PEM format (not PKCS#8 or encrypted)

#### "Connection timeout"

- **Firewall**: Ensure port 443 is accessible
- **URL format**: Include `https://` scheme
- **DNS**: Server hostname must resolve

#### "Client key path does not exist"

- **Path resolution**: Use absolute paths, not relative
- **Permissions**: Key file must be readable
- **Path expansion**: Use `$HOME` instead of `~` in environment variables

## Security Considerations

### What Gets Redacted

The `_redact_sensitive_data()` function redacts:

1. **PEM private keys**: Any `-----BEGIN ... PRIVATE KEY-----` blocks
2. **Base64 key content**: Multi-line base64 strings (40+ chars per line)
3. **Credential assignments**: `password=value`, `token:value`, `secret="value"`

### What Doesn't Get Redacted

Safe to include in error messages:
- Server URLs
- Client/user names
- Organisation names
- Node names, roles, environments
- Status codes (401, 403, 404)

### Production Recommendations

1. **Use key paths**: Prefer `CHEF_CLIENT_KEY_PATH` over `CHEF_CLIENT_KEY`
2. **Protect key files**: Set permissions to `0600`
3. **Rotate keys**: Periodically regenerate client keys
4. **Audit logs**: Monitor Chef Server logs for API access
5. **Use secrets managers**: Store keys in Vault, AWS Secrets Manager, etc.

## Acceptance Criteria Verification

From Issue #197, verify each criterion:

- [YES] **Key-based auth**: RSA signature with X-Ops-* headers
- [YES] **Configuration**: Server URL, org, client name via env vars
- [YES] **Basic endpoints**: nodes, roles, environments, cookbooks, policies
- [YES] **Connection test**: `validate_chef_server_connection` tool
- [YES] **Clear errors**: HTTP status codes with helpful messages
- [YES] **Secrets redaction**: PEM keys and passwords masked in output

## Next Steps

After validating the integration:

1. **Test with production Chef Server** (read-only operations first)
2. **Integrate with CI/CD** (see [docs/docker-deployment.md](../docker-deployment.md))
3. **Implement cookbook downloading** (Issue #198)
4. **Add caching layer** (reduce API calls)

## Support

If you encounter issues:

1. Check the [Chef Server API documentation](https://docs.chef.io/server/api_chef_server/)
2. Review [ARCHITECTURE.md](../ARCHITECTURE.md) for code structure
3. Open an issue on GitHub with redacted error output
