Skip to main content

Module hooks

Module hooks 

Source
Expand description

External trigger core (design D-F, ticket trigger-ci-pr-fix-mission): parse an authenticated GitHub webhook into a ticket-draft decision, dedupe by trigger identity, and write the provenance-carrying ticket.

D-F’s rule is that external triggers create AUDITED work, never prompt loops. Everything this module produces enters the normal ticket pipeline — draft → plan approval → queue → kranz work — so spend gates and plan approval stay exactly where they are. The module performs no git operations at all: its only action set is TRIGGER_ACTIONS (draft, or draft+queue when the operator pre-consented via the queue label), and a regression test scans this file to keep it free of any git-mutation path.

The webhook HTTP surface lives in kranz-server (POST /api/hooks/github); this module is the pure, surface-agnostic core so any surface can drive the same decisions.

Structs§

HooksConfig
Webhook trigger configuration — the hooks key of .kranz/config.json (additive; absent ⇒ the route refuses closed, never open-accepts).
Trigger
One accepted trigger, normalized out of the webhook payload. Every field that lands in the ticket is already bounded and scrubbed.

Enums§

Consent
The consent state recorded into the ticket body (D-F: never bypassed).
TriggerDraft
Outcome of drafting a trigger ticket.
TriggerKind
Which external trigger opened the ticket (the trigger: frontmatter provenance field).

Constants§

ACCEPTED_EVENTS
X-GitHub-Event values the hook route acts on. Everything else is 202-ignored with a decision log line.
DEFAULT_FIX_LABEL
Default comment label that drafts a fix ticket.
DEFAULT_QUEUE_LABEL
Default comment label that additionally pre-consents to queueing the drafted plan (plan approval itself is never skipped).
TRIGGER_ACTIONS
The only actions a trigger may drive (D-F: draft, or draft+queue on recorded pre-consent). There is deliberately no run/land action: a trigger ticket reaches execution only through the existing approval path. A regression test pins this set.

Functions§

draft_trigger_ticket
Write the trigger’s ticket, deduped by slug: an existing ticket file for the same workflow run / PR is a no-op (TriggerDraft::Duplicate). Performs no git operations; the ticket enters the normal pipeline at state New, exactly like a human-authored one.
github_full_name_from_remote
Derive owner/repo from a GitHub remote URL (git@github.com:o/r.git, ssh://git@github.com/o/r.git, https://github.com/o/r[.git]). Any other host or shape is None — the caller refuses closed when it cannot establish the served repository’s identity.
hmac_sha256_hex
Hex-encoded HMAC-SHA256 (RFC 2104) of message under key. Implemented over the workspace’s existing sha2 dependency — no crypto crate is added. Tested against the RFC 4231 vectors.
load_hooks
Read the hooks key out of the same layered config files (config::load reads): defaults, then the global file, then the project file, later layers winning key-wise. Files without a hooks key are skipped; a present-but-invalid hooks value is a config error naming the layer. Absent everywhere ⇒ HooksConfig::default (no secret ⇒ the caller refuses closed).
parse_trigger
Parse a webhook payload into a Trigger, or None when the event does not match a trigger rule (the caller 202-ignores it with a decision log). event is the X-GitHub-Event header value; anything outside ACCEPTED_EVENTS is None here too, keeping the allowlist meaningful at the core as well as at the route.
repo_full_name_from_payload
The repository.full_name (owner/repo) a GitHub webhook payload claims.
trigger_slug
Deterministic ticket slug for a trigger: trigger-ci-<run id> / trigger-pr-<number>. The dedup identity is numeric in both accepted payloads; the filter keeps the slug valid even if a future payload shape changes that.
trigger_ticket_template
The trigger ticket’s markdown: the standard four sections plus the additive trigger: frontmatter field and a provenance block in ## Context (source url, actor, consent state, bounded scrubbed excerpt). Parses back cleanly through Ticket::parse.
verify_signature
Verify a GitHub X-Hub-Signature-256 header value (sha256=<hex>) against the raw request body. Constant-time on the digest bytes, and the secret is never logged. A missing or malformed header never verifies.