Major additions: - marketplace/: Agent template registry with FTS5 search, ratings, versioning - observability/: Prometheus metrics, distributed tracing, structured logging - ledger/migrations/: Database migration scripts for multi-tenant support - tests/governance/: 15 new test files for phases 6-12 (295 total tests) - bin/validate-phases: Full 12-phase validation script New features: - Multi-tenant support with tenant isolation and quota enforcement - Agent marketplace with semantic versioning and search - Observability with metrics, tracing, and log correlation - Tier-1 agent bootstrap scripts Updated components: - ledger/api.py: Extended API for tenants, marketplace, observability - ledger/schema.sql: Added tenant, project, marketplace tables - testing/framework.ts: Enhanced test framework - checkpoint/checkpoint.py: Improved checkpoint management Archived: - External integrations (Slack/GitHub/PagerDuty) moved to .archive/ - Old checkpoint files cleaned up Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
396 lines
10 KiB
Markdown
396 lines
10 KiB
Markdown
# Production Credentials Setup Guide
|
|
|
|
> How to configure external integration credentials for Slack, GitHub, and PagerDuty.
|
|
|
|
## Overview
|
|
|
|
The Agent Governance System uses HashiCorp Vault for secure credential storage. Each integration has a dedicated secret path with specific required keys. The system also supports environment variable overrides for development and CI environments.
|
|
|
|
## Prerequisites
|
|
|
|
- Vault server running at `https://127.0.0.1:8200` (or `VAULT_ADDR`)
|
|
- Vault root token or appropriate access policy
|
|
- Admin access to Slack, GitHub, and PagerDuty accounts
|
|
|
|
## Credential Priority
|
|
|
|
The secrets manager loads credentials in this order:
|
|
|
|
1. **Environment variables** (highest priority)
|
|
2. **Vault secrets** (production)
|
|
3. **Mock values** (testing only, when `INTEGRATION_DRY_RUN=true`)
|
|
|
|
---
|
|
|
|
## Slack Integration
|
|
|
|
### Vault Path
|
|
```
|
|
secret/data/integrations/slack
|
|
```
|
|
|
|
### Required Keys
|
|
|
|
| Key | Description | Format |
|
|
|-----|-------------|--------|
|
|
| `slack_bot_token` | Bot User OAuth Token | `xoxb-...` |
|
|
| `slack_webhook_url` | Incoming Webhook URL | `https://hooks.slack.com/services/...` |
|
|
|
|
### How to Obtain
|
|
|
|
#### Bot Token
|
|
1. Go to [api.slack.com/apps](https://api.slack.com/apps)
|
|
2. Create a new app or select existing
|
|
3. Navigate to **OAuth & Permissions**
|
|
4. Under **Bot Token Scopes**, add:
|
|
- `chat:write` - Send messages
|
|
- `chat:write.public` - Send to public channels
|
|
- `files:write` - Upload files (optional)
|
|
5. Click **Install to Workspace**
|
|
6. Copy the **Bot User OAuth Token** (`xoxb-...`)
|
|
|
|
#### Webhook URL
|
|
1. In your Slack app, go to **Incoming Webhooks**
|
|
2. Enable incoming webhooks
|
|
3. Click **Add New Webhook to Workspace**
|
|
4. Select the target channel
|
|
5. Copy the **Webhook URL**
|
|
|
|
### Store in Vault
|
|
|
|
```bash
|
|
# Set Vault address and token
|
|
export VAULT_ADDR="https://127.0.0.1:8200"
|
|
export VAULT_TOKEN=$(cat /opt/vault/init-keys.json | python3 -c "import sys,json; print(json.load(sys.stdin)['root_token'])")
|
|
|
|
# Store Slack credentials
|
|
vault kv put secret/integrations/slack \
|
|
slack_bot_token="xoxb-YOUR-BOT-TOKEN" \
|
|
slack_webhook_url="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" \
|
|
configured=true
|
|
|
|
# Or using curl (if vault CLI not available)
|
|
curl -sk -X POST \
|
|
-H "X-Vault-Token: $VAULT_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"data": {
|
|
"slack_bot_token": "xoxb-YOUR-BOT-TOKEN",
|
|
"slack_webhook_url": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL",
|
|
"configured": true
|
|
}
|
|
}' \
|
|
"$VAULT_ADDR/v1/secret/data/integrations/slack"
|
|
```
|
|
|
|
### Environment Variable Override
|
|
|
|
```bash
|
|
export SLACK_BOT_TOKEN="xoxb-YOUR-BOT-TOKEN"
|
|
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
|
|
```
|
|
|
|
### Verify Configuration
|
|
|
|
```bash
|
|
# Test with Python
|
|
python3 -c "
|
|
from integrations.slack import SlackIntegration
|
|
slack = SlackIntegration()
|
|
print(f'Enabled: {slack.enabled}')
|
|
print(f'Connection test: {slack.test_connection()}')
|
|
"
|
|
```
|
|
|
|
---
|
|
|
|
## GitHub Integration
|
|
|
|
### Vault Path
|
|
```
|
|
secret/data/integrations/github
|
|
```
|
|
|
|
### Required Keys
|
|
|
|
| Key | Description | Format |
|
|
|-----|-------------|--------|
|
|
| `github_token` | Personal Access Token or App Token | `ghp_...` or `ghs_...` |
|
|
| `github_webhook_secret` | Webhook signature secret | Random string |
|
|
|
|
### How to Obtain
|
|
|
|
#### Personal Access Token (Classic)
|
|
1. Go to [github.com/settings/tokens](https://github.com/settings/tokens)
|
|
2. Click **Generate new token (classic)**
|
|
3. Select scopes:
|
|
- `repo` - Full repository access
|
|
- `write:org` - Organization webhooks (if needed)
|
|
- `admin:repo_hook` - Manage webhooks
|
|
4. Click **Generate token**
|
|
5. Copy the token immediately (shown only once)
|
|
|
|
#### Fine-Grained Personal Access Token (Recommended)
|
|
1. Go to [github.com/settings/tokens?type=beta](https://github.com/settings/tokens?type=beta)
|
|
2. Click **Generate new token**
|
|
3. Set token name and expiration
|
|
4. Select **Repository access** (specific repos or all)
|
|
5. Under **Permissions**, enable:
|
|
- Contents: Read and write
|
|
- Pull requests: Read and write
|
|
- Commit statuses: Read and write
|
|
- Webhooks: Read and write
|
|
6. Click **Generate token**
|
|
|
|
#### Webhook Secret
|
|
1. Generate a random secret:
|
|
```bash
|
|
openssl rand -hex 32
|
|
```
|
|
2. When creating GitHub webhooks, use this secret for signature verification
|
|
|
|
### Store in Vault
|
|
|
|
```bash
|
|
# Generate webhook secret
|
|
WEBHOOK_SECRET=$(openssl rand -hex 32)
|
|
|
|
# Store GitHub credentials
|
|
vault kv put secret/integrations/github \
|
|
github_token="ghp_YOUR-PERSONAL-ACCESS-TOKEN" \
|
|
github_webhook_secret="$WEBHOOK_SECRET" \
|
|
configured=true
|
|
|
|
# Or using curl
|
|
curl -sk -X POST \
|
|
-H "X-Vault-Token: $VAULT_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"data\": {
|
|
\"github_token\": \"ghp_YOUR-PERSONAL-ACCESS-TOKEN\",
|
|
\"github_webhook_secret\": \"$WEBHOOK_SECRET\",
|
|
\"configured\": true
|
|
}
|
|
}" \
|
|
"$VAULT_ADDR/v1/secret/data/integrations/github"
|
|
```
|
|
|
|
### Environment Variable Override
|
|
|
|
```bash
|
|
export GITHUB_TOKEN="ghp_YOUR-PERSONAL-ACCESS-TOKEN"
|
|
export GITHUB_WEBHOOK_SECRET="your-webhook-secret"
|
|
```
|
|
|
|
### Verify Configuration
|
|
|
|
```bash
|
|
python3 -c "
|
|
from integrations.github import GitHubIntegration
|
|
gh = GitHubIntegration()
|
|
print(f'Enabled: {gh.enabled}')
|
|
print(f'Connection test: {gh.test_connection()}')
|
|
"
|
|
```
|
|
|
|
---
|
|
|
|
## PagerDuty Integration
|
|
|
|
### Vault Path
|
|
```
|
|
secret/data/integrations/pagerduty
|
|
```
|
|
|
|
### Required Keys
|
|
|
|
| Key | Description | Format |
|
|
|-----|-------------|--------|
|
|
| `pagerduty_routing_key` | Events API v2 Integration Key | 32-char hex string |
|
|
| `pagerduty_api_token` | REST API Token (optional) | 20-char string |
|
|
| `pagerduty_service_id` | Service ID (optional) | `P...` format |
|
|
|
|
### How to Obtain
|
|
|
|
#### Routing Key (Events API v2) - Required
|
|
1. Log into [app.pagerduty.com](https://app.pagerduty.com)
|
|
2. Go to **Services** > Select your service
|
|
3. Click **Integrations** tab
|
|
4. Click **Add Integration**
|
|
5. Select **Events API v2**
|
|
6. Copy the **Integration Key** (this is your routing key)
|
|
|
|
#### REST API Token (Optional)
|
|
1. Go to **Configuration** > **API Access**
|
|
2. Click **Create New API Key**
|
|
3. Enter a description (e.g., "Agent Governance")
|
|
4. Choose **Read/Write** access
|
|
5. Copy the generated token
|
|
|
|
#### Service ID (Optional)
|
|
1. Go to **Services** > Select your service
|
|
2. The Service ID is in the URL: `app.pagerduty.com/services/PXXXXXX`
|
|
3. Or find it under **Settings** > **Service ID**
|
|
|
|
### Store in Vault
|
|
|
|
```bash
|
|
# Store PagerDuty credentials
|
|
vault kv put secret/integrations/pagerduty \
|
|
pagerduty_routing_key="YOUR-32-CHAR-ROUTING-KEY" \
|
|
pagerduty_api_token="YOUR-API-TOKEN" \
|
|
pagerduty_service_id="PXXXXXXX" \
|
|
configured=true
|
|
|
|
# Or using curl
|
|
curl -sk -X POST \
|
|
-H "X-Vault-Token: $VAULT_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"data": {
|
|
"pagerduty_routing_key": "YOUR-32-CHAR-ROUTING-KEY",
|
|
"pagerduty_api_token": "YOUR-API-TOKEN",
|
|
"pagerduty_service_id": "PXXXXXXX",
|
|
"configured": true
|
|
}
|
|
}' \
|
|
"$VAULT_ADDR/v1/secret/data/integrations/pagerduty"
|
|
```
|
|
|
|
### Environment Variable Override
|
|
|
|
```bash
|
|
export PAGERDUTY_ROUTING_KEY="your-32-char-routing-key"
|
|
export PAGERDUTY_API_TOKEN="your-api-token"
|
|
export PAGERDUTY_SERVICE_ID="PXXXXXXX"
|
|
```
|
|
|
|
### Verify Configuration
|
|
|
|
```bash
|
|
python3 -c "
|
|
from integrations.pagerduty import PagerDutyIntegration
|
|
pd = PagerDutyIntegration()
|
|
print(f'Enabled: {pd.enabled}')
|
|
print(f'Connection test: {pd.test_connection()}')
|
|
"
|
|
```
|
|
|
|
---
|
|
|
|
## Runtime Environment Variables
|
|
|
|
The following environment variables control integration behavior:
|
|
|
|
| Variable | Description | Default |
|
|
|----------|-------------|---------|
|
|
| `VAULT_ADDR` | Vault server address | `https://127.0.0.1:8200` |
|
|
| `VAULT_TOKEN` | Vault authentication token | Read from `/opt/vault/init-keys.json` |
|
|
| `USE_VAULT` | Enable Vault secret loading | `true` |
|
|
| `INTEGRATION_DRY_RUN` | Prevent actual API calls (testing) | `false` |
|
|
| `TESTING` | Enable mock mode for all secrets | `false` |
|
|
|
|
### Production Configuration
|
|
|
|
```bash
|
|
# /etc/environment or systemd unit file
|
|
VAULT_ADDR=https://vault.internal:8200
|
|
USE_VAULT=true
|
|
INTEGRATION_DRY_RUN=false
|
|
```
|
|
|
|
### Development Configuration
|
|
|
|
```bash
|
|
# .env or shell profile
|
|
export SLACK_BOT_TOKEN="xoxb-dev-token"
|
|
export GITHUB_TOKEN="ghp_dev-token"
|
|
export PAGERDUTY_ROUTING_KEY="dev-routing-key"
|
|
export INTEGRATION_DRY_RUN=true
|
|
```
|
|
|
|
---
|
|
|
|
## Verification Script
|
|
|
|
Run this script to verify all integrations are properly configured:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# verify-integrations.sh
|
|
|
|
cd /opt/agent-governance
|
|
|
|
echo "=== Integration Credential Verification ==="
|
|
echo ""
|
|
|
|
python3 << 'EOF'
|
|
import os
|
|
import sys
|
|
sys.path.insert(0, "/opt/agent-governance/integrations")
|
|
|
|
from common.secrets import SecretsManager
|
|
|
|
secrets = SecretsManager()
|
|
|
|
integrations = ["slack", "github", "pagerduty"]
|
|
|
|
for name in integrations:
|
|
result = secrets.validate_integration(name)
|
|
status = "READY" if result["ready"] else "MISSING KEYS"
|
|
print(f"\n[{name.upper()}] {status}")
|
|
if result["configured"]:
|
|
print(f" Configured: {', '.join(result['configured'])}")
|
|
if result["missing"]:
|
|
print(f" Missing: {', '.join(result['missing'])}")
|
|
if result["mock_mode"]:
|
|
print(f" (Running in mock mode)")
|
|
|
|
print("\n" + "=" * 45)
|
|
EOF
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### "No credentials found"
|
|
1. Check Vault is accessible: `curl -sk $VAULT_ADDR/v1/sys/health`
|
|
2. Verify token is valid: `vault token lookup`
|
|
3. Check secret path exists: `vault kv get secret/integrations/slack`
|
|
|
|
### "Connection test failed"
|
|
1. Verify credentials are correct (not placeholder values)
|
|
2. Check network connectivity to external services
|
|
3. Enable dry-run mode to test without making real API calls:
|
|
```bash
|
|
INTEGRATION_DRY_RUN=true python3 -c "..."
|
|
```
|
|
|
|
### "Rate limit exceeded"
|
|
1. The integration base class handles rate limiting (60 req/min default)
|
|
2. Check `_request_times` in the integration instance
|
|
3. Wait 60 seconds and retry
|
|
|
|
---
|
|
|
|
## Security Best Practices
|
|
|
|
1. **Never commit credentials** to version control
|
|
2. **Rotate tokens regularly** (GitHub: 90 days, PagerDuty: annually)
|
|
3. **Use least privilege** - only request scopes you need
|
|
4. **Enable Vault audit logging** for credential access tracking
|
|
5. **Use environment variables** only in development; production should use Vault
|
|
6. **Monitor for credential leaks** with GitHub secret scanning
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- [Architecture Overview](./ARCHITECTURE.md)
|
|
- [Integration Status](../integrations/STATUS.md)
|
|
- [Secrets Management Code](../integrations/common/secrets.py)
|
|
|
|
---
|
|
*Last updated: 2026-01-24*
|