feat(docker-watcher): phase 5 - registry client & poller
Gitea registry client with tag listing and pattern matching, cron-based polling scheduler with first-poll safety, poll state persistence. DeployTriggerer interface for decoupled deploy triggering.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Phase 6: Webhook Handler
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Status:** ✅ Complete
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** backend
|
||||
|
||||
@@ -9,14 +9,14 @@ Implement the secret UUID-based webhook endpoint that receives image push notifi
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Task 1: Implement webhook HTTP handler — `POST /api/webhook/:secret-uuid`
|
||||
- [ ] Task 2: Validate incoming payload — extract image name and tag
|
||||
- [ ] Task 3: Look up project by image name in store — match against configured project images
|
||||
- [ ] Task 4: If known project: match tag to stage via tag patterns, determine if auto_deploy
|
||||
- [ ] Task 5: If unknown project: auto-create project with defaults from image inspection (EXPOSE port, labels)
|
||||
- [ ] Task 6: Generate and store webhook secret UUID in settings (on first launch)
|
||||
- [ ] Task 7: Implement webhook URL regeneration (new UUID, invalidates old one)
|
||||
- [ ] Task 8: Define webhook payload struct (`{"image": "registry/org/app:tag"}`)
|
||||
- [x] Task 1: Implement webhook HTTP handler — `POST /api/webhook/:secret-uuid`
|
||||
- [x] Task 2: Validate incoming payload — extract image name and tag
|
||||
- [x] Task 3: Look up project by image name in store — match against configured project images
|
||||
- [x] Task 4: If known project: match tag to stage via tag patterns, determine if auto_deploy
|
||||
- [x] Task 5: If unknown project: auto-create project with defaults from image inspection (EXPOSE port, labels)
|
||||
- [x] Task 6: Generate and store webhook secret UUID in settings (on first launch)
|
||||
- [x] Task 7: Implement webhook URL regeneration (new UUID, invalidates old one)
|
||||
- [x] Task 8: Define webhook payload struct (`{"image": "registry/org/app:tag"}`)
|
||||
|
||||
## Files to Modify/Create
|
||||
- `internal/webhook/handler.go` — webhook HTTP handler + payload parsing
|
||||
@@ -38,11 +38,41 @@ Implement the secret UUID-based webhook endpoint that receives image push notifi
|
||||
- Keep the handler thin — it matches and delegates
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] No information leak on invalid UUIDs
|
||||
- [ ] Payload validation rejects malformed input
|
||||
- [ ] Auto-creation uses safe defaults
|
||||
- [ ] Handler is stateless (delegates to store/deployer)
|
||||
- [x] All tasks completed
|
||||
- [x] No information leak on invalid UUIDs
|
||||
- [x] Payload validation rejects malformed input
|
||||
- [x] Auto-creation uses safe defaults
|
||||
- [x] Handler is stateless (delegates to store/deployer)
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Filled in by the implementation agent after completing this phase. -->
|
||||
|
||||
### Exported API
|
||||
|
||||
- `webhook.NewHandler(store, deployer, inspector)` — creates the HTTP handler
|
||||
- `webhook.Handler.Route()` — returns a `chi.Router` to mount at `/api/webhook`
|
||||
- `webhook.EnsureWebhookSecret(store)` — generates UUID on first launch, returns current secret
|
||||
- `webhook.RegenerateWebhookSecret(store)` — replaces secret with new UUID, invalidates old one
|
||||
- `webhook.ParseImageRef(ref)` — parses `registry/owner/name:tag` into components
|
||||
|
||||
### Interfaces Defined
|
||||
|
||||
- `webhook.DeployTriggerer` — `TriggerDeploy(ctx, projectID, stageID, imageTag) error` (mirrors `registry.DeployTriggerer`)
|
||||
- `webhook.ImageInspector` — `InspectImage(ctx, imageRef) (docker.ImageInfo, error)` (wraps `docker.Client`)
|
||||
|
||||
### Integration Points
|
||||
|
||||
- Mount the webhook router: `r.Mount("/api/webhook", webhookHandler.Route())`
|
||||
- Call `webhook.EnsureWebhookSecret(store)` at application startup to generate the secret on first launch
|
||||
- The deployer must implement `webhook.DeployTriggerer` (same signature as `registry.DeployTriggerer`)
|
||||
- The Docker client (`*docker.Client`) satisfies `webhook.ImageInspector` directly
|
||||
|
||||
### Auto-Create Behavior
|
||||
|
||||
- Unknown images create a project with name from image name, port from EXPOSE, healthcheck from image metadata
|
||||
- A default "dev" stage is created with `tag_pattern: "*"`, `auto_deploy: true`, `max_instances: 1`
|
||||
- If image inspection fails (not pulled locally), project is created with port=0 and empty healthcheck
|
||||
|
||||
### Tag Matching
|
||||
|
||||
- Uses `path.Match` (glob semantics) — same approach as the registry poller
|
||||
- Stages are checked in name-sorted order; first matching stage wins
|
||||
|
||||
Reference in New Issue
Block a user