Skip to content

feat(WRCS): add webhook support - #1817

Draft
zachaller wants to merge 7 commits into
argoproj-labs:mainfrom
zachaller:wrcs-webhhook-support-1
Draft

zachaller wants to merge 7 commits into
argoproj-labs:mainfrom
zachaller:wrcs-webhhook-support-1

Conversation

@zachaller

Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI review requested due to automatic review settings July 24, 2026 18:37
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zachaller zachaller changed the title Wrcs webhhook support 1 feat(WRCS): add webhook support Jul 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR expands the in-process SCM webhook receiver to (1) verify inbound webhook authenticity using secrets stored on ScmProvider/ClusterScmProvider Secrets and (2) accelerate WebRequestCommitStatus (WRCS) reconciles by fanning out repository-scoped webhook events to matching WRCS resources, with optional per-WRCS payload filtering. It also updates generated API types/manifests/docs to reflect the new configuration and behavior, and bumps the dashboard’s react-router-dom.

Changes:

  • Add webhook signature/token verification (webhookSecret / webhookSignatureHeader) with an optional fail-closed “strict mode” configured via ControllerConfiguration.spec.webhookReceiver.strict.
  • Add WRCS webhook acceleration: repo identity parsing, repo→GitRepository→PromotionStrategy→WRCS fan-out, and optional mode.webhook.filter.expression evaluation.
  • Update generated CRDs/install bundles/applyconfigs/view types and documentation; bump react-router-dom to v7 and require Node >= 20 for the dashboard package.

Reviewed changes

Copilot reviewed 31 out of 44 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ui/shared/src/types/generated/view.gen.ts Updates generated View API TS types/docs for mode.webhook and webhook filter schemas.
ui/dashboard/package.json Bumps react-router-dom to v7 and adds engines.node >=20.
ui/dashboard/package-lock.json Locks dependency graph for the router v7 upgrade (and new transitive deps).
internal/webhookreceiver/signature.go Implements secret/header resolution and signature verification logic.
internal/webhookreceiver/signature_test.go Adds unit tests for signature verification, secret extraction, and filter evaluation.
internal/webhookreceiver/server.go Adds strict-mode reading, webhook auth gating, repo parsing, and WRCS fan-out/filtering.
internal/webhookreceiver/server_test.go Extends webhook receiver tests to cover WRCS fan-out, strict mode, and auth behavior.
internal/webhookreceiver/filter.go Adds compiled-expression caching and evaluation for webhook payload filters.
internal/utils/utils.go Adds exported helper to resolve ScmProvider+Secret from a GitRepository; validates secretRef presence.
internal/utils/gitrepository_repokey.go Adds normalized repo-key helpers for provider-agnostic matching/indexing.
internal/utils/gitrepository_repokey_test.go Adds unit tests for repo-key derivation across supported providers.
internal/settings/manager.go Adds settings accessor for ControllerConfiguration.spec.webhookReceiver.strict.
internal/controller/webrequestcommitstatus_controller.go Adds an external enqueue channel and exposes enqueue func for webhook-driven reconciles.
internal/controller/webrequestcommitstatus_controller_test.go Adds integration test asserting webhook fan-out triggers a WRCS reconcile/HTTP call.
internal/controller/testdata/WebRequestCommitStatus.yaml Documents mode.webhook.filter.expression usage in testdata YAML.
internal/controller/testdata/ControllerConfiguration.yaml Documents spec.webhookReceiver.strict in testdata config.
internal/controller/suite_test.go Wires WRCS enqueue func into the webhook receiver in controller test suite.
internal/controller/promotionstrategy_controller.go Adds field index for PromotionStrategy→GitRepository reference to support fan-out queries.
internal/controller/gitrepository_controller.go Adds field index for GitRepository repoKey to support repo-identity lookups.
internal/controller/fieldindex.go Introduces constants for new field-index paths used across controllers/receiver.
docs/security.md Documents webhook receiver hardening, secret keys, and strict mode behavior.
docs/roadmap.md Updates roadmap item wording to reflect broader verified webhook handling.
docs/getting-started.md Adds getting-started guidance to configure webhook secrets for production.
docs/gating-promotions/built-in-gates/web-request-commit-status/index.md Documents WRCS webhook acceleration and mode.webhook.filter.
docs/crd-specs.md Updates WRCS description to include the optional webhook filter/accelerator.
dist/install-without-ui.yaml Regenerates install bundle with new CRD schema and controller config defaults.
dist/install-with-dashboard-cert-manager.yaml Regenerates install bundle with new CRD schema and controller config defaults.
dist/install-with-dashboard-byo-cert.yaml Regenerates install bundle with new CRD schema and controller config defaults.
config/crd/bases/promoter.argoproj.io_webrequestcommitstatuses.yaml Regenerates WRCS CRD with mode.webhook.filter.expression schema.
config/crd/bases/promoter.argoproj.io_controllerconfigurations.yaml Regenerates ControllerConfiguration CRD with spec.webhookReceiver.strict.
config/config/controllerconfiguration.yaml Adds webhookReceiver.strict to the default ControllerConfiguration manifest.
cmd/main.go Wires WRCS enqueue func + settings manager into the webhook receiver in the main controller binary.
applyconfiguration/utils.go Extends applyconfiguration kind mapping for new webhook-related types.
applyconfiguration/api/v1alpha1/webhookreceiverconfiguration.go Adds generated applyconfiguration for webhook receiver config.
applyconfiguration/api/v1alpha1/webhookmodespec.go Adds generated applyconfiguration for WRCS webhook mode.
applyconfiguration/api/v1alpha1/webhookfilterspec.go Adds generated applyconfiguration for webhook filter spec.
applyconfiguration/api/v1alpha1/modespec.go Updates ModeSpec applyconfiguration to include the new webhook field/docs.
applyconfiguration/api/v1alpha1/controllerconfigurationspec.go Updates ControllerConfigurationSpec applyconfiguration with webhookReceiver.
api/view/v1alpha1/zz_generated.openapi.go Updates generated OpenAPI to include new webhook-related schemas/fields.
api/v1alpha1/zz_generated.model_name.go Adds OpenAPI model names for new webhook-related API types.
api/v1alpha1/zz_generated.deepcopy.go Adds deepcopy support for new webhook-related API types/fields.
api/v1alpha1/webrequestcommitstatus_types.go Adds mode.webhook and new webhook filter/mode structs to WRCS API.
api/v1alpha1/controllerconfiguration_types.go Adds spec.webhookReceiver to ControllerConfiguration API.
api/v1alpha1/constants.go Adds ScmProvider Secret key constants for inbound webhook verification.
Files not reviewed (9)
  • api/v1alpha1/zz_generated.deepcopy.go: Generated file
  • api/v1alpha1/zz_generated.model_name.go: Generated file
  • applyconfiguration/api/v1alpha1/controllerconfigurationspec.go: Generated file
  • applyconfiguration/api/v1alpha1/modespec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookfilterspec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookmodespec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookreceiverconfiguration.go: Generated file
  • applyconfiguration/utils.go: Generated file
  • ui/dashboard/package-lock.json: Generated file

Comment thread api/v1alpha1/controllerconfiguration_types.go Outdated
Comment thread internal/webhookreceiver/server.go Outdated
Copilot AI review requested due to automatic review settings July 24, 2026 19:08
@codecov-commenter

Copy link
Copy Markdown

Bundle Report

Bundle size has no change ✅

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 31 out of 44 changed files in this pull request and generated 2 comments.

Files not reviewed (9)
  • api/v1alpha1/zz_generated.deepcopy.go: Generated file
  • api/v1alpha1/zz_generated.model_name.go: Generated file
  • applyconfiguration/api/v1alpha1/controllerconfigurationspec.go: Generated file
  • applyconfiguration/api/v1alpha1/modespec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookfilterspec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookmodespec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookreceiverconfiguration.go: Generated file
  • applyconfiguration/utils.go: Generated file
  • ui/dashboard/package-lock.json: Generated file

Comment thread internal/webhookreceiver/server.go Outdated
Comment thread internal/webhookreceiver/server.go Outdated
@codecov-commenter

codecov-commenter commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.47761% with 52 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.44%. Comparing base (ee66b56) to head (4e5f578).

Files with missing lines Patch % Lines
internal/webhookreceiver/server.go 80.28% 28 Missing ⚠️
internal/webhookreceiver/verification.go 86.02% 13 Missing ⚠️
internal/controller/gitrepository_controller.go 66.66% 2 Missing ⚠️
...nternal/controller/promotionstrategy_controller.go 66.66% 2 Missing ⚠️
...al/controller/webrequestcommitstatus_controller.go 81.81% 2 Missing ⚠️
internal/utils/utils.go 50.00% 2 Missing ⚠️
internal/webhookreceiver/filter.go 91.66% 2 Missing ⚠️
internal/webhookreceiver/signature.go 95.65% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1817      +/-   ##
==========================================
+ Coverage   60.83%   61.44%   +0.60%     
==========================================
  Files         138      142       +4     
  Lines       11105    11404     +299     
  Branches      457      458       +1     
==========================================
+ Hits         6756     7007     +251     
- Misses       4274     4325      +51     
+ Partials       75       72       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Copilot AI review requested due to automatic review settings July 28, 2026 13:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 31 out of 44 changed files in this pull request and generated no new comments.

Files not reviewed (9)
  • api/v1alpha1/zz_generated.deepcopy.go: Generated file
  • api/v1alpha1/zz_generated.model_name.go: Generated file
  • applyconfiguration/api/v1alpha1/controllerconfigurationspec.go: Generated file
  • applyconfiguration/api/v1alpha1/modespec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookfilterspec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookmodespec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookreceiverconfiguration.go: Generated file
  • applyconfiguration/utils.go: Generated file
  • ui/dashboard/package-lock.json: Generated file
Comments suppressed due to low confidence (3)

api/v1alpha1/controllerconfiguration_types.go:95

  • ControllerConfigurationSpec.WebhookReceiver is added as a required, non-omitempty field. That makes upgrading potentially breaking for existing ControllerConfiguration manifests that don’t include spec.webhookReceiver, because they will fail validation on the next apply/update. If strict defaults to false, consider making this field optional (pointer + omitempty) or adding a structural default for the object itself (e.g. +kubebuilder:default={}) so older manifests remain valid without edits.
	// WebhookReceiver contains configuration for the inbound SCM webhook receiver
	// (signature verification and related fail-closed behavior).
	// +required
	WebhookReceiver WebhookReceiverConfiguration `json:"webhookReceiver"`
}

internal/webhookreceiver/signature.go:38

  • webhookSignatureHeader is read directly from Secret data without trimming whitespace. If the Secret value is created from a file or copy/paste with a trailing newline/space, header lookup will never match and valid webhooks will be rejected with 401. Trim surrounding whitespace on the header name before falling back to the default.
    internal/webhookreceiver/server.go:47
  • The field-index path strings are duplicated here to avoid an import cycle. This creates a silent drift risk: if internal/controller renames any of these index paths, webhook verification / WRCS fan-out will stop matching resources with no compile-time signal. Consider moving these index-path constants to a small shared package (e.g. internal/indexfields or api/v1alpha1) that both controller and webhookreceiver can import, so they stay in sync.

Copilot AI review requested due to automatic review settings July 28, 2026 14:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 31 out of 44 changed files in this pull request and generated 1 comment.

Files not reviewed (9)
  • api/v1alpha1/zz_generated.deepcopy.go: Generated file
  • api/v1alpha1/zz_generated.model_name.go: Generated file
  • applyconfiguration/api/v1alpha1/controllerconfigurationspec.go: Generated file
  • applyconfiguration/api/v1alpha1/modespec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookfilterspec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookmodespec.go: Generated file
  • applyconfiguration/api/v1alpha1/webhookreceiverconfiguration.go: Generated file
  • applyconfiguration/utils.go: Generated file
  • ui/dashboard/package-lock.json: Generated file
Comments suppressed due to low confidence (3)

internal/webhookreceiver/server.go:693

  • enqueueWRCSForRepo logs an Info-level message for every WRCS enqueued. On busy repos or many WRCS, this can generate high-volume logs from every webhook delivery and make signal/noise worse. Consider lowering this to a debug verbosity (or sampling) and keep Info for exceptional conditions only.
    docs/gating-promotions/built-in-gates/web-request-commit-status/index.md:94
  • This sentence claims deliveries without a parseable repository identity are rejected with 401 when any webhookSecret is configured. In the implementation, missing repository identity is only rejected when ControllerConfiguration.spec.webhookReceiver.strict is enabled; otherwise the delivery can still be accepted (and the CTP SHA path may still run). The docs here should match the strict vs non-strict behavior described in docs/security.md.
When at least one ScmProvider Secret for the webhook’s repository has `webhookSecret` set, the receiver requires a valid signature (or shared token) before enqueueing WRCS or ChangeTransferPolicy work. Values with a `sha256=` prefix are verified as HMAC-SHA256 of the raw body; other values are compared as a shared token (constant-time). If no matching Secret configures `webhookSecret`, verification is skipped for backward compatibility. Deliveries without a parseable repository identity cannot be verified or fan out to WRCS; when any `webhookSecret` is configured they are rejected with **401** so CTP is not enqueued either. See [Webhook receiver hardening](../../../security.md#webhook-receiver-hardening).

internal/utils/utils.go:108

  • The new secretRef is required... error message is using secretNamespace (which is the namespace the Secret would live in), not the ScmProvider object's own namespace. For ClusterScmProvider this can be confusing because the provider itself is cluster-scoped, while the secret lives in controllerNamespace. Consider reporting the ScmProvider object identity in the message, and (optionally) include the expected secret namespace separately.

Comment thread internal/webhookreceiver/server.go Outdated
@zachaller zachaller mentioned this pull request Aug 18, 2026
Extend the SCM webhook receiver to verify inbound deliveries using
Provider secret keys (webhookSecret, webhookSignatureHeader) when
ScmProvider.inboundWebhookVerification is RequireVerification, and to
fan out repository-scoped webhooks to matching WebRequestCommitStatus
resources with optional mode.webhook.filter expression filtering.

Retain webhook secret keys in the Secret informer transform so
verification works against the cached client used in production.

Signed-off-by: Zach Aller <zachaller@users.noreply.github.com>
@zachaller
zachaller force-pushed the wrcs-webhhook-support-1 branch from 06fb828 to b931188 Compare August 27, 2026 21:04
Signed-off-by: Zach Aller <zachaller@users.noreply.github.com>
…wrcs-webhhook-support-1

Signed-off-by: Zach Aller <zachaller@users.noreply.github.com>
Signed-off-by: Zach Aller <zachaller@users.noreply.github.com>
Signed-off-by: Zach Aller <zachaller@users.noreply.github.com>
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.

3 participants