Webhook receiver: Plane deliveries trigger a tick (PAD-7)
agentd webhook-serve (agentd/webhook.py, stdlib): verifies X-Plane-Signature
(HMAC-SHA256 hex of the body, constant-time; 401 on missing/bad), routes by
data.project to a configured tenant (others 202), coalesces deliveries within
3 s into one tick, runs one more tick when deliveries arrive during a tick,
and retries every 15 s for up to 2 min while the lock is held (tick command
exit 75: flock -E 75 in the cron scripts, cli tick on Busy). Ticks run in a
systemd scope so restarting the receiver never kills one. Log:
<log_dir>/webhook.log; GET /healthz.
Config: webhook section (key names only, PLANE_WEBHOOK_SECRET scrubbed from
child envs like the Plane tokens), notify: {kind: none} as a no-op hook
called on every state move; the unused per-project webhook_secret_key is
gone (Plane webhooks are workspace-level). systemd unit for the LXC and
tools/plane-webhook.py to create/rotate the Plane webhook as the workspace
admin (secret straight into the Vault, never printed).
This commit is contained in:
@@ -13,6 +13,18 @@ agentd:
|
||||
comment_max_chars: 6000
|
||||
cli_terminal: oregon # identity used by `agentd new/comment/state/assign`
|
||||
|
||||
# Plane webhook receiver (`agentd webhook-serve`, docs/runbook.md "Webhook"); leave the section out to run on cron only.
|
||||
webhook:
|
||||
bind: 127.0.0.1
|
||||
port: 8790
|
||||
path: /plane
|
||||
secret_key: PLANE_WEBHOOK_SECRET # Vault key name of the Plane webhook secret (workspace-level webhook)
|
||||
tick_command: [cron/agentd-tick.sh] # exits 75 when another tick holds the lock (flock -E 75)
|
||||
debounce_seconds: 3
|
||||
retry_seconds: 15
|
||||
retry_window_seconds: 120
|
||||
notify: {kind: none} # notification hook: only `none` (no-op) exists today
|
||||
|
||||
terminals:
|
||||
win10:
|
||||
transport: warpgate-ssh
|
||||
@@ -72,7 +84,6 @@ projects:
|
||||
GWENT:
|
||||
id: 79cb5a60-aa4f-4138-9864-1dd70426e665
|
||||
key_prefix: GW
|
||||
webhook_secret_key: PLANE_WEBHOOK_GWENT
|
||||
states: {backlog: Backlog, todo: Todo, running: In Progress, waiting: Waiting, review: Review, done: Done}
|
||||
reviewer: oregon # Plane user that gets [review] items
|
||||
answerer: oregon # Plane user that gets [question]/[blocked] and failures (default: reviewer)
|
||||
|
||||
+15
-1
@@ -13,6 +13,21 @@ agentd:
|
||||
comment_max_chars: 6000
|
||||
cli_terminal: oregon
|
||||
|
||||
# Plane webhook receiver (`agentd webhook-serve`, systemd plane-agentd-webhook.service; docs/runbook.md "Webhook").
|
||||
# One workspace-level Plane webhook (work items + comments) -> POST http://10.77.10.249:8790/plane -> one tick.
|
||||
webhook:
|
||||
bind: 10.77.10.249 # LAN only (Plane VM 10.77.10.68 is on the same /24)
|
||||
port: 8790
|
||||
path: /plane
|
||||
secret_key: PLANE_WEBHOOK_SECRET # Vault key name; the value is injected by agent-access.py exec --secret-env
|
||||
# the cron script holds `flock -n -E 75`; --scope moves the tick out of the receiver's cgroup, so restarting the
|
||||
# receiver never kills a running tick
|
||||
tick_command: [systemd-run, --scope, --quiet, --collect, /opt/plane-agentd/cron/agentd-tick-lxc.sh]
|
||||
debounce_seconds: 3 # deliveries within this window -> one tick
|
||||
retry_seconds: 15 # lock busy -> retry every 15 s ...
|
||||
retry_window_seconds: 120 # ... for up to 2 min; then the cron tick covers it
|
||||
notify: {kind: none} # notification hook, no-op (no ntfy service); core calls it on every state move
|
||||
|
||||
terminals:
|
||||
win10:
|
||||
transport: warpgate-ssh
|
||||
@@ -85,4 +100,3 @@ projects:
|
||||
timeout_hours: 4
|
||||
max_rounds_per_thread: 8
|
||||
max_progress_rounds: 12
|
||||
# notify (ntfy) is phase 3: left out on purpose
|
||||
|
||||
+24
-1
@@ -36,6 +36,30 @@
|
||||
"cli_terminal": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"webhook": {
|
||||
"type": "object",
|
||||
"required": ["secret_key", "tick_command"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"bind": {"type": "string"},
|
||||
"port": {"type": "integer", "minimum": 1},
|
||||
"path": {"type": "string"},
|
||||
"secret_key": {"type": "string"},
|
||||
"tick_command": {"type": "array", "minItems": 1, "items": {"type": "string"}},
|
||||
"tick_timeout_seconds": {"type": "integer", "minimum": 10},
|
||||
"debounce_seconds": {"type": "number", "minimum": 0},
|
||||
"retry_seconds": {"type": "number", "minimum": 1},
|
||||
"retry_window_seconds": {"type": "number", "minimum": 0}
|
||||
}
|
||||
},
|
||||
"notify": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"kind": {"enum": ["none"]},
|
||||
"on": {"$ref": "#/definitions/strings"}
|
||||
}
|
||||
},
|
||||
"terminals": {"type": "object", "minProperties": 1, "additionalProperties": {"$ref": "#/definitions/terminal"}},
|
||||
"executors": {"type": "object", "minProperties": 1, "additionalProperties": {"$ref": "#/definitions/executor"}},
|
||||
"projects": {"type": "object", "minProperties": 1, "additionalProperties": {"$ref": "#/definitions/project"}}
|
||||
@@ -101,7 +125,6 @@
|
||||
"properties": {
|
||||
"id": {"type": "string"},
|
||||
"key_prefix": {"type": "string"},
|
||||
"webhook_secret_key": {"type": "string"},
|
||||
"states": {
|
||||
"type": "object",
|
||||
"required": ["todo", "running", "waiting", "review", "done"],
|
||||
|
||||
Reference in New Issue
Block a user