Skip to content

LOU-D13: Trigger hardening: webhook authentication and real cron expressions - #47

Merged
LinuxDevil merged 4 commits into
mainfrom
lou-d13-trigger-hardening
Oct 1, 2026
Merged

LinuxDevil merged 4 commits into
mainfrom
lou-d13-trigger-hardening

Conversation

@LinuxDevil

Copy link
Copy Markdown
Owner

What

  • WebhookTriggerAdapter gets auth: { type: 'hmac' | 'bearer' | 'custom' }. HMAC verifies the RAW body bytes (header/algorithm/prefix configurable, optional timestampHeader + toleranceSeconds replay protection signing ${timestamp}.${body}), bearer and HMAC compares are constant-time, custom takes verify(req, rawBody). Failures return a generic 401 {"error":"Unauthorized"} and are logged via the SDK Logger (new logger option) without secrets/signatures. No auth on a non-loopback host logs a one-time warning.
  • CronTriggerAdapter accepts cron (5-field expression or @hourly/@daily/@weekly/@monthly, plus timezone) alongside the existing intervalMs. New dependency-free src/triggers/cronExpression.ts (parseCronExpression(expr, tz).nextRun(after), CronExpressionError), exported from @loushy/build-ai-agent/triggers.
  • Docs: new "Triggers" section in docs/api-overview.md with a security note.

Why

Audit findings: the webhook adapter accepted unauthenticated requests and cron only supported a fixed interval (eve has defineSchedule({ cron })).

How verified

Run on the result of merging origin/main (85c436d):

  • npx tsc --noEmit: clean
  • npm run lint: 0 errors (432 pre-existing warnings; none in src/triggers)
  • npm run build + create-loushy-agent build: success
  • npm run test:coverage: 97 files passed, 1250 tests passed, 3 skipped, thresholds met
  • npm run fallow: exit 0 (0 above threshold)
  • npm run docs:verify-snippets: all 34 snippets type-check, 5 run cleanly

Notes for reviewer

  • The ticket said to reuse Slack's signature verification, but SlackTriggerAdapter does not verify signatures (it only posts replies), so there was nothing to share; the HMAC helpers live in src/triggers/webhookAuth.ts. Slack inbound verification could reuse them in a follow-up.
  • hmac.prefix defaults to ${algorithm}= (so sha1= with sha1; sha256= as specified for the default).
  • DST: a wall time inside a spring-forward gap is skipped that day; a fall-back repeated time fires once for fixed hours, while * hours keep hourly cadence (documented + tested).
  • CronTriggerAdapterOptions is now a union (intervalMs xor cron); existing interval usage is unchanged.

🤖 Generated with Claude Code

@LinuxDevil
LinuxDevil merged commit 89d199f into main Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant