# Using Mock OAuth2 Server in CI/CD

This guide explains how to use the mock OAuth2 server infrastructure in continuous integration pipelines.

## GitHub Actions Configuration

### Running with Mock OAuth (Default)

The tests automatically use mock OAuth by default. No special configuration needed:

```yaml
name: Tests with Mock OAuth

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.12'

    - name: Install dependencies
      run: |
        pip install -r requirements-dev.txt

    - name: Run OAuth tests (mock)
      run: |
        pytest tests/test_oauth_integration_flows.py -v
```

### Running with Real OAuth (Using Secrets)

To test with real OAuth credentials (e.g., Authentik, Auth0):

```yaml
name: Tests with Real OAuth

on: [push, pull_request]

jobs:
  test-real-oauth:
    runs-on: ubuntu-latest
    # Only run if secrets are available (not on external PRs)
    if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.12'

    - name: Install dependencies
      run: |
        pip install -r requirements-dev.txt

    - name: Run OAuth tests (real)
      env:
        AUTHENTIK_CLIENT_ID: ${{ secrets.AUTHENTIK_CLIENT_ID }}
        AUTHENTIK_CLIENT_SECRET: ${{ secrets.AUTHENTIK_CLIENT_SECRET }}
        AUTHENTIK_CONFIG_URL: ${{ secrets.AUTHENTIK_CONFIG_URL }}
      run: |
        # Tests auto-detect real credentials and use them
        pytest tests/test_oauth_integration_flows.py -v -m requires_external
```

### Hybrid Approach (Best Practice)

Run both mock and real tests in separate jobs:

```yaml
name: OAuth Tests

on: [push, pull_request]

jobs:
  test-mock-oauth:
    name: OAuth Tests (Mock)
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.12'

    - name: Install dependencies
      run: |
        pip install -r requirements-dev.txt

    - name: Run mock OAuth tests
      run: |
        pytest tests/test_oauth_integration_flows.py \
          -v \
          -m "not requires_external"

  test-real-oauth:
    name: OAuth Tests (Real - Internal Only)
    runs-on: ubuntu-latest
    # Only run on internal commits where secrets are available
    if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.12'

    - name: Install dependencies
      run: |
        pip install -r requirements-dev.txt

    - name: Run real OAuth tests
      env:
        AUTHENTIK_CLIENT_ID: ${{ secrets.AUTHENTIK_CLIENT_ID }}
        AUTHENTIK_CLIENT_SECRET: ${{ secrets.AUTHENTIK_CLIENT_SECRET }}
        AUTHENTIK_CONFIG_URL: ${{ secrets.AUTHENTIK_CONFIG_URL }}
      run: |
        pytest tests/test_oauth_integration_flows.py \
          -v \
          -m requires_external
```

## Required GitHub Secrets

To enable real OAuth testing, configure these secrets in your repository:

1. Go to **Settings → Secrets and variables → Actions**
2. Add the following secrets:

| Secret Name | Description | Example Value |
|-------------|-------------|---------------|
| `AUTHENTIK_CLIENT_ID` | OAuth client ID | `docuelevate-app` |
| `AUTHENTIK_CLIENT_SECRET` | OAuth client secret | `super-secret-value` |
| `AUTHENTIK_CONFIG_URL` | OIDC discovery URL | `https://auth.example.com/application/o/docuelevate/.well-known/openid-configuration` |

## Docker Service (Alternative to Testcontainers)

If you prefer not to use testcontainers in CI, you can run mock-oauth2-server as a service:

```yaml
name: Tests with OAuth Service

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    services:
      mock-oauth:
        image: ghcr.io/navikt/mock-oauth2-server:2.1.1
        ports:
          - 8080:8080
        options: >-
          --health-cmd "wget -q -O /dev/null http://localhost:8080/default/.well-known/openid-configuration || exit 1"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.12'

    - name: Install dependencies
      run: |
        pip install -r requirements-dev.txt

    - name: Configure OAuth to use service
      run: |
        export OAUTH_MOCK_URL=http://localhost:8080
        export USE_MOCK_OAUTH=true

    - name: Run tests
      run: |
        pytest tests/test_oauth_integration_flows.py -v
```

## Forcing Mock or Real Mode

You can override the automatic detection with environment variables:

```bash
# Force mock mode (even if real credentials available)
export USE_MOCK_OAUTH=true
pytest tests/test_oauth_integration_flows.py -v

# Force real mode (will skip if credentials not available)
export USE_REAL_OAUTH=true
pytest tests/test_oauth_integration_flows.py -v
```

## Debugging OAuth Tests in CI

### View Container Logs

Add this step to debug mock OAuth server issues:

```yaml
- name: Show mock OAuth logs (on failure)
  if: failure()
  run: |
    docker ps -a
    docker logs $(docker ps -aq --filter ancestor=ghcr.io/navikt/mock-oauth2-server:2.1.1)
```

### Enable Verbose Logging

```yaml
- name: Run tests with verbose logging
  run: |
    pytest tests/test_oauth_integration_flows.py -vvs --log-cli-level=DEBUG
```

### Check Well-Known Endpoint

```yaml
- name: Verify mock OAuth server
  run: |
    curl -f http://localhost:8080/default/.well-known/openid-configuration || exit 1
```

## Performance Considerations

- **Mock OAuth**: ~1s startup time, tests run in <10s
- **Real OAuth**: Depends on network latency, typically <30s
- **Docker Service**: Fastest for CI (pre-started), ~0.5s overhead

## Security Best Practices

1. ✅ **Never commit real OAuth credentials** to the repository
2. ✅ **Use GitHub secrets** for real credentials
3. ✅ **Restrict real OAuth tests** to internal PRs only
4. ✅ **Use mock OAuth** for external/fork PRs
5. ✅ **Rotate secrets** regularly if compromised

## Troubleshooting

### Tests Skip with "OAuth credentials not available"

**Cause**: Real OAuth credentials not configured or not accessible.

**Solution**:
- For local dev: Use mock mode (default)
- For CI: Add secrets to GitHub repository settings
- Check secret availability: `if github.event_name == 'push'`

### Mock OAuth Server Won't Start

**Cause**: Docker not available or testcontainers can't start container.

**Solution**:
```yaml
- name: Start Docker
  run: |
    sudo systemctl start docker
    docker ps
```

### Tests Timeout Waiting for Server

**Cause**: Server taking too long to start or health check failing.

**Solution**: Increase timeout in `conftest_oauth.py`:
```python
container.wait_for_ready(timeout=60)  # Increase from 30
```

## Example: Complete GitHub Actions Workflow

```yaml
name: Full OAuth Testing Suite

on: [push, pull_request]

jobs:
  # Fast mock OAuth tests (always run)
  mock-oauth-tests:
    name: OAuth Tests (Mock)
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.12'

    - name: Install dependencies
      run: pip install -r requirements-dev.txt

    - name: Run mock OAuth tests
      run: |
        pytest tests/test_oauth_integration_flows.py \
          -v \
          -m "not requires_external" \
          --cov=app.auth \
          --cov-report=term-missing

    - name: Upload coverage
      uses: codecov/codecov-action@v3
      with:
        files: ./coverage.xml
        flags: oauth-mock

  # Real OAuth tests (only for internal PRs/pushes)
  real-oauth-tests:
    name: OAuth Tests (Real - Internal)
    runs-on: ubuntu-latest
    if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.12'

    - name: Install dependencies
      run: pip install -r requirements-dev.txt

    - name: Run real OAuth tests
      env:
        AUTHENTIK_CLIENT_ID: ${{ secrets.AUTHENTIK_CLIENT_ID }}
        AUTHENTIK_CLIENT_SECRET: ${{ secrets.AUTHENTIK_CLIENT_SECRET }}
        AUTHENTIK_CONFIG_URL: ${{ secrets.AUTHENTIK_CONFIG_URL }}
      run: |
        pytest tests/test_oauth_integration_flows.py \
          -v \
          -m requires_external

    - name: Upload coverage
      uses: codecov/codecov-action@v3
      with:
        files: ./coverage.xml
        flags: oauth-real
```

This workflow:
- ✅ Runs mock tests on all PRs (fast, no secrets needed)
- ✅ Runs real tests only when secrets available
- ✅ Uploads separate coverage reports
- ✅ Provides detailed feedback
