Skip to content

feat(server): enable authentication to webhook endpoint#1015

Draft
rene-oromtz wants to merge 11 commits intomainfrom
feat/enable-to-auth
Draft

feat(server): enable authentication to webhook endpoint#1015
rene-oromtz wants to merge 11 commits intomainfrom
feat/enable-to-auth

Conversation

@rene-oromtz
Copy link
Copy Markdown
Contributor

@rene-oromtz rene-oromtz commented Apr 13, 2026

Description

This PR add support for providing authentication to webhook endpoint via Charm definition.

  1. Add a typed config to make sure charm configures the webhook endpoint. As a bonus, the typed config is also applicable for all the other fields.
  2. Server code ensures only sending events to the "authorized" webhook url configured at charm level
  3. Add optional authentication (this is managed at deployment level)

This follows the pattern discussed and approved in MM to let TF be the source of auth with Test Observer

Resolved issues

Resolves CERTTF-985

Documentation

Web service API changes

@v1.post("/job/<job_id>/events") should remain backward compatibility on current production usage but now it is enforced that the specified webhook in job should match the one configured by server

Tests

Added additional unit tests on charm and server.

Pending to test in staging.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds server-side enforcement and optional authentication for the agent events webhook forwarding, configured via the charm and validated in the server API to prevent sending events (and auth tokens) to unexpected destinations.

Changes:

  • Add charm typed config (Pydantic) and new charm options for webhook_endpoint and optional webhook_auth.
  • Update /v1/job/<job_id>/events to validate job_id, verify job existence, enforce webhook scheme/host/path matching against WEBHOOK_ENDPOINT, and optionally forward WEBHOOK_AUTH as a Bearer token.
  • Expand unit tests for webhook forwarding, rejection cases, and auth header behavior.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
server/tests/test_v1.py Adds/updates server API unit tests around webhook endpoint enforcement and auth forwarding.
server/src/testflinger/database.py Introduces job_exists() helper used by the events endpoint.
server/src/testflinger/api/v1.py Implements webhook endpoint validation, auth header forwarding, and improved error handling for the events endpoint.
server/schemas/openapi.json Updates OpenAPI description to reflect new webhook behavior/docs.
server/charm/uv.lock Adds Pydantic to charm dependency lockfile.
server/charm/tests/unit/test_config.py New unit tests for typed charm config validation.
server/charm/src/config.py Adds TestflingerServerConfig Pydantic model and validators.
server/charm/src/charm.py Switches charm to typed config and exports WEBHOOK_ENDPOINT / WEBHOOK_AUTH to workload env.
server/charm/pyproject.toml Adds Pydantic dependency; minor formatting tweak.
server/charm/charmcraft.yaml Adds charm config options for webhook endpoint and auth token.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server/src/testflinger/api/v1.py Outdated
Comment thread server/src/testflinger/database.py
Comment thread server/charm/tests/unit/test_config.py Outdated
Comment thread server/charm/charmcraft.yaml Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 13, 2026

Codecov Report

❌ Patch coverage is 97.05882% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.61%. Comparing base (e5e7339) to head (79ebfd9).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1015      +/-   ##
==========================================
+ Coverage   75.48%   75.61%   +0.12%     
==========================================
  Files         112      113       +1     
  Lines       11082    11140      +58     
  Branches      941      951      +10     
==========================================
+ Hits         8365     8423      +58     
+ Misses       2505     2504       -1     
- Partials      212      213       +1     
Flag Coverage Δ *Carryforward flag
agent 75.78% <ø> (ø) Carriedforward from e5e7339
cli 90.40% <ø> (ø) Carriedforward from e5e7339
device 62.68% <ø> (ø) Carriedforward from e5e7339
server 87.24% <97.05%> (+0.37%) ⬆️

*This pull request uses carry forward flags. Click here to find out more.

Components Coverage Δ
Agent 75.78% <ø> (ø)
CLI 90.40% <ø> (ø)
Common ∅ <ø> (∅)
Device Connectors 62.68% <ø> (ø)
Server 87.24% <97.05%> (+0.37%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server/tests/test_v1.py Outdated
Comment thread server/src/testflinger/api/v1.py Outdated
Comment on lines +796 to +802
parsed_server_url = urlparse(webhook_url)
parsed_job_url = urlparse(job_webhook)
if (
parsed_server_url.scheme != parsed_job_url.scheme
or parsed_server_url.netloc != parsed_job_url.netloc
):
abort(HTTPStatus.FORBIDDEN, message="Unauthorized webhook URL")
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The webhook host check compares urlparse(...).netloc directly. This is overly strict and can incorrectly reject equivalent URLs (e.g., hostname case differences, or an explicit default port like :443 vs no port). Consider comparing normalized components instead (e.g., scheme.lower(), hostname.lower(), and effective port with scheme defaults) so legitimate webhooks aren’t rejected.

Copilot uses AI. Check for mistakes.
Comment thread server/src/testflinger/api/v1.py Outdated
Comment thread server/src/testflinger/api/v1.py Outdated
Comment thread server/src/testflinger/api/v1.py
@rene-oromtz rene-oromtz force-pushed the feat/enable-to-auth branch from edfa3b8 to 79ebfd9 Compare April 14, 2026 18:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants