Feat v0.3.7 package audit (#20)
All checks were successful
All checks were successful
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #20.
This commit is contained in:
30
packages/webhook-notifier/README.md
Normal file
30
packages/webhook-notifier/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Webhook Notifier
|
||||
|
||||
Outbound webhook delivery with connection credentials and delivery logging.
|
||||
|
||||
## Features
|
||||
|
||||
- **Starlark `http.post`** — outbound HTTP with custom headers
|
||||
- **`connections.get`** — fallback to stored webhook connection credentials
|
||||
- **Delivery logging** — records URL, status code, event to `webhook_log` ext_data table
|
||||
- **Result review** — delivery status shown in final review stage
|
||||
|
||||
## Stage Flow
|
||||
|
||||
```
|
||||
[configure] → [fire-webhook] → [result]
|
||||
team automated review
|
||||
(http.post)
|
||||
```
|
||||
|
||||
## Starlark Hook
|
||||
|
||||
- **`on_fire(ctx)`** — Posts JSON payload to webhook URL, falls back to `connections.get("webhook")`, logs delivery to `webhook_log`
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
curl -X POST $BASE/api/v1/admin/packages/install \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-F "file=@packages/webhook-notifier"
|
||||
```
|
||||
79
packages/webhook-notifier/manifest.json
Normal file
79
packages/webhook-notifier/manifest.json
Normal file
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"id": "webhook-notifier",
|
||||
"title": "Webhook Notifier",
|
||||
"type": "workflow",
|
||||
"version": "0.1.0",
|
||||
"tier": "starlark",
|
||||
"icon": "🔔",
|
||||
"author": "Switchboard Core",
|
||||
"description": "Outbound webhook delivery with connection credential support and delivery logging.",
|
||||
"permissions": ["api.http", "connections.read", "db.write"],
|
||||
|
||||
"db_tables": {
|
||||
"webhook_log": {
|
||||
"columns": {
|
||||
"url": "text",
|
||||
"status_code": "text",
|
||||
"event": "text",
|
||||
"instance_id": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"workflow_definition": {
|
||||
"name": "Webhook Notifier",
|
||||
"slug": "webhook-notifier",
|
||||
"entry_mode": "team_only",
|
||||
"stages": [
|
||||
{
|
||||
"name": "configure",
|
||||
"ordinal": 0,
|
||||
"stage_mode": "form",
|
||||
"audience": "team",
|
||||
"stage_type": "simple",
|
||||
"auto_transition": false,
|
||||
"form_template": {
|
||||
"fieldsets": [
|
||||
{
|
||||
"label": "Webhook Configuration",
|
||||
"fields": [
|
||||
{ "key": "webhook_url", "label": "Webhook URL", "type": "text", "required": true },
|
||||
{ "key": "event_name", "label": "Event Name", "type": "text", "required": true },
|
||||
{ "key": "payload", "label": "Custom Payload (JSON)", "type": "textarea" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "fire-webhook",
|
||||
"ordinal": 1,
|
||||
"stage_mode": "automated",
|
||||
"audience": "system",
|
||||
"stage_type": "automated",
|
||||
"auto_transition": true,
|
||||
"starlark_hook": "webhook-notifier:on_fire"
|
||||
},
|
||||
{
|
||||
"name": "result",
|
||||
"ordinal": 2,
|
||||
"stage_mode": "review",
|
||||
"audience": "team",
|
||||
"stage_type": "simple",
|
||||
"auto_transition": false,
|
||||
"form_template": {
|
||||
"fieldsets": [
|
||||
{
|
||||
"label": "Delivery Result",
|
||||
"fields": [
|
||||
{ "key": "delivery_status", "label": "Status", "type": "text" },
|
||||
{ "key": "status_code", "label": "HTTP Status Code", "type": "text" },
|
||||
{ "key": "response_body", "label": "Response", "type": "textarea" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
41
packages/webhook-notifier/script.star
Normal file
41
packages/webhook-notifier/script.star
Normal file
@@ -0,0 +1,41 @@
|
||||
def on_fire(ctx):
|
||||
"""Fire outbound webhook with optional connection credentials."""
|
||||
data = ctx["stage_data"]
|
||||
url = data.get("webhook_url", "")
|
||||
|
||||
# Fallback to configured connection
|
||||
if not url:
|
||||
conn = connections.get("webhook")
|
||||
if conn:
|
||||
url = conn.get("url", "")
|
||||
|
||||
if not url:
|
||||
return {"error": "No webhook URL configured"}
|
||||
|
||||
payload = json.encode({
|
||||
"event": data.get("event_name", "workflow.notify"),
|
||||
"instance_id": ctx["instance_id"],
|
||||
"workflow_id": ctx["workflow_id"],
|
||||
"data": data,
|
||||
})
|
||||
|
||||
resp = http.post(url, body=payload, headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-Switchboard-Event": data.get("event_name", "workflow.notify"),
|
||||
})
|
||||
|
||||
# Log the delivery
|
||||
db.insert("webhook_log", {
|
||||
"url": url,
|
||||
"status_code": str(resp["status"]),
|
||||
"event": data.get("event_name", ""),
|
||||
"instance_id": ctx["instance_id"],
|
||||
})
|
||||
|
||||
status = "delivered" if int(resp["status"]) < 400 else "failed"
|
||||
|
||||
return {"advance": True, "data": {
|
||||
"delivery_status": status,
|
||||
"status_code": str(resp["status"]),
|
||||
"response_body": resp["body"][:500],
|
||||
}}
|
||||
Reference in New Issue
Block a user