patchwork: enhance integration#253
Conversation
|
Overall looks pretty good to me, thanks! It's in the draft state, anything big before it can be merged? Has it been tested with the real patchwork instance? |
|
@rgushchin pushed it up before leaving for vacation so haven't had real time to test it when I get back I'll plan to grab those credentials from you and run some trials with --no-ai. Hopefully Mauro's PR to change the scoping of PW tokens will have been merged as well. |
e02a56a to
3972b6d
Compare
|
v2: The PatchworkWorker now resolves tokens from the email policy config (and adds a min_severity field to the patchwork policy. Findings below the configured |
|
@matttbe requesting your review. tested on following series: test methodology:
each patch was then polled at the prod sashiko instance.
sample email policy: @rgushchin could you lend me your eyes one more time for a review on this V2? thanks! logs from manual cURL confirmation: Please send me any other candidates you think are worthwhile to test :) |
|
Some comments from AI, look reasonable to me (especially the first one):
|
|
Thank you for working on that, that looks good! Regarding the descriptions that are sent, how is it going to cover the "pre-existing issues"? Personally, I think it would be good to:
But this suggestion can also be changed later, I don't want to block this PR. |
3972b6d to
b10ae09
Compare
|
v2->v3: overview of changes
|
Add support for two patchwork check delivery modes configured per-subsystem in email_policy.toml: - API mode: direct REST API calls via a new database-backed patchwork_outbox table with non-blocking retry-queuing. Failed entries are scheduled for retry via a next_retry_at timestamp with exponential backoff (5s/30s/180s) so the worker loop continues processing other entries immediately. Replaces the previous fire-and-forget tokio::spawn approach. - Email mode: structured plain-text notification emails queued through the existing email_outbox for downstream tools like pw_tools to parse and post checks. Both modes can be enabled simultaneously per-subsystem. Config changes: - Add email field to PatchworkPolicy for email-based mode - Add min_severity for per-subsystem severity filtering - Add fail_severity (default: High) for configurable check state mapping: new findings at or above threshold produce fail, below produce warning, pre-existing findings never affect state - Add SASHIKO_PATCHWORK_TOKEN env var override for secure token injection without storing secrets in TOML on disk - Add URL normalization on config load with non-localhost http:// security warning Check description format: - Per-severity breakdown: Critical: 1 . High: 2 (1 pre-existing) - Zero-count severities dropped - Pre-existing findings shown in description but do not affect check state - Missing/null preexisting flag treated as new Schema changes: - Add patchwork_outbox table with next_retry_at column for non-blocking retry scheduling - Tokens NOT stored in the database; resolved from config at delivery time Code changes: - Add PatchworkCheckResult builder in patchwork.rs that computes check state and description from policy + findings - Add PatchworkWorker with non-blocking retry loop, config-based token resolution, and max_retries from settings - Refactor post_patchwork_check() to return Result, accept a shared reqwest::Client, URL-encode message-IDs, and warn on multiple patch results - Add compose_patchwork_email() for structured email format - Add insert_patchwork_notification() using NULL patch_id - Fix EmailOutboxRow.patch_id from i64 to Option<i64> - Rewire reviewer queue_notifications() to use PatchworkCheckResult and outbox inserts Assisted-by: Claude claude-opus-4-6 Signed-off-by: derekbarbosa <derekasobrab@gmail.com>
Document both patchwork delivery modes (API and email) in the configuration reference with: - API mode and email mode setup with example TOML blocks - Severity filtering (min_severity) and check state mapping (fail_severity) with edge case behaviors documented - Per-severity description format with pre-existing awareness - SASHIKO_PATCHWORK_TOKEN environment variable - Structured email notification format spec for downstream parsers - Annotated examples showing API-only, email-only, dual-mode, and severity filtering configurations Assisted-by: Claude claude-opus-4-6 Signed-off-by: derekbarbosa <derekasobrab@gmail.com>
b10ae09 to
3ab4b9d
Compare
|
rebased on latest |
Patchwork Policy Modes: API and Email-Based Check Updates
Summary
This PR adds dual-mode patchwork integration to sashiko, allowing
subsystem maintainers to report review results as patchwork checks
via either direct API calls or structured email notifications.
Motivation
Patchwork's permission model is coarse-grained -- an API token that
can post checks can also change patch states, delegate patches, and
perform other maintainer operations. Some subsystems (like linux-media)
are not comfortable giving sashiko a write token with that scope.
This PR provides two delivery modes so each subsystem can choose the
integration that fits their security posture:
for direct, low-latency check delivery
structured email that a local script (like pw_tools) parses and
posts using the maintainer's own credentials
What changed
Config (
email_policy.rs):patchwork.emailfield for email-based modepatchwork.min_severityfor per-subsystem severity filteringpatchwork.fail_severity(default:"High") for configurablecheck state mapping: new findings at or above threshold produce
fail, below producewarning, pre-existing findings neveraffect state
SASHIKO_PATCHWORK_TOKENenv var fills in tokens where the TOMLomits them (explicit TOML tokens take precedence)
validation, non-localhost http:// security warning
Schema (
schema.sql):patchwork_outboxtable with status index andnext_retry_atcolumn for non-blocking retry scheduling
the config file at delivery time
Runtime (
patchwork.rs,worker/patchwork.rs,reviewer.rs):PatchworkCheckResult::from_policy()builder computes check stateand per-severity description from policy config and findings,
keeping PatchworkPolicy as a pure config struct
counts in parentheses, dropping zero-count severities (e.g.
Critical: 1 · High: 2 (1 pre-existing))PatchworkWorkerpolls the outbox, resolves the API token fromthe email policy config by matching
api_url, posts checks,retries on failure with non-blocking exponential backoff via
next_retry_attimestamps (5s/30s/180s), reclaims ghost entriesafter 10 minutes, uses
max_retriesfrom settingsfire-and-forget
tokio::spawnpost_patchwork_check()refactored to returnResult, accept ashared
reqwest::Client, URL-encode message-IDs, and warn onambiguous multi-patch results
Bugfix (
db.rs):EmailOutboxRow.patch_idchanged fromi64toOption<i64>tomatch the schema which allows NULL. Required for patchwork email
notifications that use
patch_id = NULLto avoid the dedup guard.Docs (
configuration.md,examples/email_policy.toml):filtering, check state mapping, edge case behaviors, token env
var, and structured email format specification
Patchwork API interaction
Two endpoints, executed sequentially by the PatchworkWorker:
GET {api_url}/patches/?msgid={encoded_msgid}-- resolve theemail message-ID to a patchwork patch ID
POST {api_url}/patches/{patch_id}/checks/-- submit the checkresult (
state,description,target_url,context)Email mode skips both endpoints. It sends a parseable plain-text
email that a downstream tool converts into these same API calls
using the maintainer's own token.
Design tradeoffs
Database-backed outbox with polling worker over inline retry in
tokio::spawn. The outbox survives crashes; ghost sweep recovers stuck
entries; the table is queryable for ops visibility.
Non-blocking retry via next_retry_at timestamps over sleeping in
the worker loop. Failed entries are immediately returned to Pending
with a future timestamp. The worker skips them until the backoff
expires and continues processing other entries.
Tokens resolved from config at delivery time over storing tokens
in the outbox table. The PatchworkWorker loads the email policy config
and matches by api_url to resolve the correct token. No secrets in
the database. Token rotation takes effect immediately.
PatchworkCheckResult builder pattern over inline computation in
reviewer.rs. Separates config (PatchworkPolicy) from computed output
(state + description). Keeps the policy struct as pure deserialized
config.
Check state from new findings only with configurable threshold.
Pre-existing findings are shown in the description for context but
never trigger
failorwarning. This prevents noise frompre-existing technical debt affecting the patch review signal.
Separate patchwork_outbox table over extending email_outbox.
Different semantics (retry with backoff vs one-shot), different
columns, cleaner separation.
Email mode reuses email_outbox with NULL patch_id over a separate
table. Reuses the existing EmailWorker and SMTP infrastructure.
Env var fills token gaps, does not overwrite over always
overriding TOML. Preserves per-subsystem token differentiation.
Known limitations
Ghost sweep recovers in-flight entries after 10 minutes. Patchwork
dedups by context so duplicate check posts are harmless.
assumes trusted config file authors. We add scheme validation
(https preferred, http:// warned for non-localhost) but no host
filtering.
Email mode exists as the mitigation for subsystems that can't
accept the broad token scope.
server. Validated manually against production patchwork.kernel.org
MPTCP instance (6-patch series, all checks posted successfully).
Unit tests cover all components individually.
reads email_policy.toml from disk each time it resolves a token.
Same pattern the reviewer already uses. Negligible I/O at the
expected volume.
Pre-existing issues fixed opportunistically
EmailOutboxRow.patch_idtype mismatch (i64 vs nullable schema)Testing
pre-existing handling, severity filtering, config deserialization,
URL normalization, token override, email composition)
6 patches posted via PatchworkWorker code path (4 success,
2 warning), all verified via authenticated API GET
make check-prpasses (301 unit + 17 integration, all green)