GHSA-8vh3-g2qg-2h2c (CVSS 9.1, CWE-306): POST /webhooks/nextcloud had no
authentication when WEBHOOK_SECRET was unset (the default). The receiver
trusted the attacker-supplied user.uid and fed it to Qdrant, letting an
unauthenticated network caller delete or re-index any user's vector
embeddings.
Webhooks now require WEBHOOK_SECRET end-to-end:
- app.py: the /webhooks/nextcloud route is only mounted when WEBHOOK_SECRET
is set; otherwise it 404s and a startup warning notes vector sync falls
back to the polling scanner.
- webhook_receiver.py: removed the warn-and-accept fallback. No secret -> 503,
missing/invalid bearer -> 401; the payload is never processed unauthenticated.
- webhook_routes.py / api/webhooks.py: webhook_auth_pair() raises
WebhookSecretNotConfigured instead of returning authMethod="none"; both
registration entry points return a clear 503 so no dead unauthenticated
webhooks are created.
Also expose webhooks availability to the Astrolabe UI via GET /api/v1/status
("webhooks_enabled": bool), set WEBHOOK_SECRET on the docker-compose
semantic-search dev services, and update env.sample + ADR-010 / ADR-018 /
webhook-management-guide docs.
Vector sync still works without a secret via the polling scanner.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Manual testing of Nextcloud webhook_listeners app to validate webhook
payloads against ADR-010 expected schemas and document implementation
requirements for webhook-based vector synchronization.
## Changes
- Add test webhook endpoint at /webhooks/nextcloud in app.py
- Captures and logs webhook payloads for analysis
- Returns 200 OK immediately for webhook delivery confirmation
- Create webhook-testing-findings.md with comprehensive test results
- Captured payloads for 5/6 webhook event types
- Critical findings: missing node.id in deletions, type mismatches
- Implementation recommendations with code examples
- Update ADR-010 with Appendix A: Manual Webhook Testing Results
- Document actual vs expected webhook behavior
- Update event mapping table with tested webhook status
- Add 6 specific implementation recommendations
- Include testing implications for future development
## Testing Results
✅ NodeCreatedEvent - fires correctly, includes node.id (integer)
✅ NodeWrittenEvent - fires correctly, includes node.id (integer)
✅ NodeDeletedEvent - fires but missing node.id field (path only)
✅ CalendarObjectCreatedEvent - fires correctly with full iCal
✅ CalendarObjectUpdatedEvent - fires correctly with full iCal
❌ CalendarObjectDeletedEvent - does not fire (potential NC bug)
## Key Findings
1. NodeDeletedEvent missing node.id field - requires path-based fallback
2. node.id returns integer not string - needs casting for consistency
3. Multiple webhooks fire per operation - needs deduplication logic
4. Calendar deletion webhooks don't fire - reported as issue #53497
5. Calendar webhooks include full iCal content - enables rich parsing
## GitHub Issues
- Created issue #56371: NodeDeletedEvent missing node.id field
- Commented on issue #53497: CalendarObjectDeletedEvent not firing
Closes#283
---
_This commit was generated with the help of AI, and reviewed by a Human_
Add architecture decision record for integrating Nextcloud webhooks
into the vector database synchronization system.
Key features:
- Webhook endpoint at /webhooks/nextcloud receives push notifications
- Complements existing polling (ADR-007) without replacing it
- Optional authentication via WEBHOOK_SECRET
- Simple architecture: webhooks are just another DocumentTask producer
- Administrators can reduce polling frequency when webhooks are configured
Benefits:
- Reduced latency: seconds to minutes instead of up to 1 hour
- Lower API load: ~95% reduction when polling frequency is increased
- Better scalability: only process changed documents
- No changes required to scanner or processor components
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>