- Add package name validation with strict regex patterns - Convert all Process::run() calls to array syntax - Support Composer and NPM package name formats - Add comprehensive shell injection tests (20 attack patterns) - Update security docs and changelog Fixes P2 shell injection vulnerability from security audit. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
7.1 KiB
| title | description | updated |
|---|---|---|
| Webhooks | Webhook configuration and integration guide | 2026-01-29 |
Webhooks
The Uptelligence module can receive webhooks from vendor release systems to automatically track new versions.
Supported Providers
| Provider | Event Types | Signature Method |
|---|---|---|
| GitHub | Release published/created | HMAC-SHA256 |
| GitLab | Release created, tag push | Token header |
| npm | Package published | HMAC-SHA256 |
| Packagist | Package updated | HMAC-SHA1 |
| Custom | Flexible | HMAC-SHA256 |
Endpoint URL
Each webhook has a unique endpoint:
POST /api/uptelligence/webhook/{uuid}
The UUID is generated when the webhook is created and serves as the identifier.
Configuring Webhooks
GitHub
- Go to repository Settings > Webhooks > Add webhook
- Set Payload URL to:
https://your-domain.com/api/uptelligence/webhook/{uuid} - Set Content type to:
application/json - Set Secret to the webhook's secret (visible in admin panel)
- Select "Let me select individual events"
- Check "Releases" only
- Save webhook
Expected headers:
X-Hub-Signature-256: sha256={signature}X-GitHub-Event: release
GitLab
- Go to project Settings > Webhooks
- Set URL to:
https://your-domain.com/api/uptelligence/webhook/{uuid} - Set Secret token to the webhook's secret
- Check "Releases events" and optionally "Tag push events"
- Save webhook
Expected headers:
X-Gitlab-Token: {secret}X-Gitlab-Event: Release HookorTag Push Hook
npm
npm webhooks are configured per package via the npm CLI or website.
npm hook add @scope/package https://your-domain.com/api/uptelligence/webhook/{uuid} {secret}
Expected headers:
X-Npm-Signature: {signature}
Packagist
Packagist webhooks are configured in the package settings on packagist.org.
- Go to package page > Edit
- Add webhook URL:
https://your-domain.com/api/uptelligence/webhook/{uuid} - Set secret if required
Expected headers:
X-Hub-Signature: sha1={signature}
Custom
For custom integrations, send a POST request with:
Headers:
Content-Type: application/jsonX-Signature: sha256={hmac_sha256_of_body}(optional)
Body:
{
"version": "1.2.3",
"tag_name": "v1.2.3",
"name": "Release Name",
"body": "Release notes...",
"prerelease": false,
"published_at": "2026-01-29T12:00:00Z"
}
Signature Verification
HMAC-SHA256 (GitHub, npm, Custom)
$expectedSignature = hash_hmac('sha256', $payload, $secret);
$valid = hash_equals($expectedSignature, $providedSignature);
The signature header may have a sha256= prefix which is stripped before comparison.
Token Comparison (GitLab)
$valid = hash_equals($secret, $providedToken);
Direct constant-time comparison of the token.
HMAC-SHA1 (Packagist)
$expectedSignature = hash_hmac('sha1', $payload, $secret);
$valid = hash_equals($expectedSignature, $providedSignature);
Secret Management
Creating a Webhook
When a webhook is created, a 64-character random secret is automatically generated.
Rotating Secrets
Secrets can be rotated with a grace period:
$webhook->rotateSecret();
This:
- Moves current secret to
previous_secret - Generates new 64-character secret
- Sets
secret_rotated_atto current time
During the grace period (default 24 hours), both old and new secrets are accepted.
Regenerating Without Grace
To immediately invalidate the old secret:
$webhook->regenerateSecret();
This:
- Generates new secret
- Clears
previous_secret - Clears
secret_rotated_at
Delivery Processing
Flow
- Receive - Webhook received at endpoint
- Validate - Check webhook is active, verify signature
- Log - Create
UptelligenceWebhookDeliveryrecord - Queue - Dispatch
ProcessUptelligenceWebhookjob - Parse - Extract version and metadata from payload
- Process - Create/update version release record
- Notify - Send notifications to subscribed users
Delivery Statuses
| Status | Description |
|---|---|
pending |
Queued for processing |
processing |
Currently being processed |
completed |
Successfully processed |
failed |
Processing failed |
skipped |
Not a release event or unable to parse |
Retry Logic
Failed deliveries are retried with exponential backoff:
- Attempt 1: Immediate
- Attempt 2: After 30 seconds
- Attempt 3: After 60 seconds (2^2 * 30)
- Attempt 4: After 120 seconds (2^3 * 30)
Maximum 3 retries by default.
Circuit Breaker
To prevent continuous processing of failing webhooks:
- After 10 consecutive failures, the webhook is automatically disabled
- Status changes to "Circuit Open"
- Manual intervention required to re-enable
Reset the circuit breaker:
$webhook->update(['is_active' => true, 'failure_count' => 0]);
Monitoring
Admin Dashboard
The Webhook Manager component shows:
- Webhook status (Active, Disabled, Circuit Open)
- Last received timestamp
- Failure count
- Recent deliveries with status
Deliveries Log
Each delivery records:
- Event type
- Provider
- Version extracted
- Payload (full JSON)
- Parsed data (normalised)
- Source IP
- Signature status
- Processing time
- Error message (if failed)
Rate Limiting
Webhooks are rate-limited to prevent abuse:
- 60 requests/minute per webhook UUID
- 30 requests/minute per IP (fallback for unknown webhooks)
Rate limit exceeded returns 429 Too Many Requests.
Testing Webhooks
Test Endpoint
POST /api/uptelligence/webhook/{uuid}/test
Returns webhook configuration status without processing:
{
"status": "ok",
"webhook_id": "uuid-here",
"vendor_id": 1,
"provider": "github",
"is_active": true,
"signature_status": "valid",
"has_secret": true
}
Manual Testing
Use curl to test a webhook:
# Generate signature
SECRET="your-webhook-secret"
PAYLOAD='{"tag_name":"v1.0.0","name":"Test Release"}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)
# Send request
curl -X POST \
-H "Content-Type: application/json" \
-H "X-Hub-Signature-256: sha256=$SIGNATURE" \
-d "$PAYLOAD" \
https://your-domain.com/api/uptelligence/webhook/{uuid}
Troubleshooting
"Invalid signature" Response
- Verify the secret matches between provider and webhook config
- Check that the payload is sent as raw JSON (not form-encoded)
- Ensure the signature algorithm matches the provider
- Check for encoding issues (UTF-8 BOM, etc.)
"Webhook disabled" Response
- Check if circuit breaker has tripped (failure_count >= 10)
- Verify
is_activeis true in database - Re-enable via admin panel or API
Deliveries Not Processing
- Check queue worker is running:
php artisan queue:work --queue=uptelligence-webhooks - Check for failed jobs:
php artisan queue:failed - Review delivery status in admin panel
Missing Release Record
- Verify the event type is supported (release/publish, not push)
- Check parsed_data in delivery record
- Ensure version extraction succeeded
- Check if version already exists (duplicate webhooks are de-duplicated)