feat: add Docker Hub integration#2831
Conversation
|
@rakesh0x thank you for your submission. Please attach the video recording as specified in the Bounty Details in the issue. |
Attached a video @AleksandarCole, check it out |
6b406b4 to
7850eb0
Compare
|
@rakesh0x the video shows Unit tests passing - which is great. However, we need the video of in-app usage of the integration and components. I tried running this in dev environment and I do not see either DockerHub integration appearing in UI or the components. |
oh yeah, i haven't imported the dockerhub package anywhere , so the package haven't loaded |
|
@rakesh0x how is the webhook setup working? Looks like DockerHub webhooks are per repository |
Docker Hub doesn't provide an API to programmatically create webhooks, they must be manually configured by users in the Docker Hub UI per repository. |
yup, now the integration appears in the list @AleksandarCole |
|
@lucaspin The 4 failing E2E tests are unrelated to docker hub integration , these appear to be pre existing flaky tests, could you please confirm , if these tests are known to be flaky |
@rakesh0x and how are users doing this? Which SuperPlane URL are you using to do that? |
When users set up the "On Image Pushed" trigger in SuperPlane, the system generates a unique webhook URL (like https://your-superplane.com/webhooks/abc123). Users then copy this URL and paste it into their Docker Hub repo settings under Webhooks. It's a manual step since Docker Hub doesn't have an API for creating webhooks programmatically. The URL is shown in the trigger configuration UI after setup. |
|
hey @lucaspin , can you please review and merge if everything is good |
web_src/src/pages/workflowv2/mappers/dockerhub/on_image_pushed.ts
Outdated
Show resolved
Hide resolved
|
@rakesh0x I checked out your changes, but I can't even open the application:
Also, CI is failing. |
3e7da08 to
634b7a2
Compare
i had to keep merging the branch again and again, so it created a merge conflicts |
ce5ca2d to
2ae3d7f
Compare
web_src/src/pages/workflowv2/mappers/dockerhub/on_image_pushed.ts
Outdated
Show resolved
Hide resolved
|
@lucaspin fixed the ci as well |
|
@rakesh0x tested and reviewed your PR. It's not there yet, but it has potential. Here's a list of things we need to address before being able to merge it. Missing icon on integrations page and on component sidebar
Do not authenticate every timeWe are calling
|
cf7f5d5 to
fb37e9c
Compare
| if payload.Repository.RepoName != expectedRepo { | ||
| // Not for this repository, ignore | ||
| return http.StatusOK, nil | ||
| } |
There was a problem hiding this comment.
Case-sensitive repository comparison may silently drop webhooks
Medium Severity
The webhook handler compares payload.Repository.RepoName against expectedRepo using case-sensitive string comparison. Docker Hub normalizes repository names to lowercase in webhook payloads, but the expectedRepo is constructed from config.Namespace and config.Repository which come from user input without normalization. If a user configures "MyOrg/MyApp" but Docker Hub sends "myorg/myapp" in the webhook, the comparison fails and events are silently ignored.
| } | ||
| // Default namespace is "library" for official images | ||
| return "library", repoName | ||
| } |
| export interface OnImagePushedConfiguration { | ||
| repository?: string; | ||
| tagFilter?: string; | ||
| } |
| next?: string; | ||
| previous?: string; | ||
| results?: Tag[]; | ||
| } |
web_src/src/pages/workflowv2/mappers/dockerhub/describe_image_tag.ts
Outdated
Show resolved
Hide resolved
ticket: Superplane 2131 Added Jira integration <img width="1511" height="807" alt="Screenshot 2026-02-03 at 09 52 49" src="https://github.com/user-attachments/assets/0ad4a199-f15b-4b32-8b23-0cbb57256759" /> <img width="1510" height="808" alt="Screenshot 2026-02-03 at 09 52 57" src="https://github.com/user-attachments/assets/e05d2024-2adb-4c0e-ba93-f8a756c51103" /> <img width="1000" height="801" alt="Screenshot 2026-02-05 at 13 21 38" src="https://github.com/user-attachments/assets/848ce4a2-ab70-45a1-94ce-6c43412f9423" /> <img width="450" height="718" alt="Screenshot 2026-02-05 at 13 21 21" src="https://github.com/user-attachments/assets/590d85ee-ed5e-4f1b-ac3b-d4d2098d21ad" /> --------- Signed-off-by: alabro-bm <atanas.labroski@brightmarbles.io> Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
…t Tags action This adds a new Docker Hub integration for SuperPlane with: - Docker Hub integration with username/access token authentication - Validates credentials on sync by testing Docker Hub API access - Receives Docker Hub webhook events when images are pushed - Supports optional tag filtering with wildcard patterns (e.g., 'v*', '*-latest') - Emits 'dockerhub.imagePushed' event with push details - Lists tags for a specified Docker Hub repository - Supports optional pageSize and nameFilter parameters - Emits 'dockerhub.tags' event with tag information - Added UI mappers for trigger and action components - Displays repository, tag, and pusher information Closes superplanehq#2243 Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
- Fix unreachable code: move contains wildcard check (*beta*) before prefix/suffix checks so it's properly matched - Fix trigger setup: compare config.Repository with metadata.Repository to detect configuration changes (previously only checked non-empty) - Remove unused GetRepository function from client.go - Remove unused verifyWebhookSignature function and related imports - Add tests for contains wildcard pattern matching - Add test for repository configuration change scenario Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
Add blank import for dockerhub package in server.go to trigger the init() function that registers the integration with the registry. This makes the Docker Hub integration appear in the UI. Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
The HandleRequest function was intercepting webhook requests and only logging them without routing to triggers. Changed to no-op pattern (like PagerDuty) so the framework routes webhooks directly to the OnImagePushed trigger's HandleWebhook method. Removed unused imports: encoding/json, io, net/http, strings Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
Moved metadata persistence to AFTER RequestWebhook succeeds. Previously, if RequestWebhook failed after metadata was saved, retries would see metadata matches config and skip the webhook request entirely. Now the order is: 1. Validate config 2. Check if already setup (metadata matches config) 3. Request webhook 4. Only if webhook succeeds, persist metadata Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
Each subtest now creates its own WaitSteps instance with the subtest's *testing.T, matching the pattern used in approvals_test.go. This fixes the 'subtest may have called FailNow on a parent test' error that occurred when require assertions failed. Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
Generated via scripts/generate_components_docs.go Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
- Rename listTags -> describeImageTag (single tag lookup) - Rename onImagePushed -> onImagePush (consistent naming) - Add namespace configuration field for repository selection - Use IntegrationResource with Parameters for repository field - Use AnyPredicateList for tag filtering (consistent with github.onPush) - Implement ctx.Webhook.Setup() for manual webhook URL generation - Verify repository exists on Setup() and store repo info in metadata - Add CustomFieldRenderer to display webhook URL with instructions - Update frontend mappers for new component names - Add dockerhub icon to integration icon maps Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
continuation of this superplanehq#2518 --------- Signed-off-by: Aleksandar Radosevic <aradosevicarchon@gmail.com> Signed-off-by: Igor Šarčević <igor@operately.com> Co-authored-by: Aleksandar Radosevic <aradosevicarchon@gmail.com> Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
**Summary** Adds full SendGrid integration support: base integration, Send Email action, On Email Event trigger, Create/Update Contact action, UI mappers, example payloads/docs, and webhook handling updates. **Key Changes** - **SendGrid integration (backend)** - New SendGrid integration with sync/verification, webhook setup/cleanup, signed webhook support, and tests. - New Send Email action with text/html/template modes, categories, failed channel handling, and tests. - New On Email Event trigger with filtering, signature verification, defaults, and tests. - New Create/Update Contact action (Marketing Contacts API) with list IDs/custom fields, failed channel handling, and tests. - Embedded JSON examples for SendGrid outputs/events. - **API / webhook handling** - Webhook route accepts `application/json` with optional charset (utf-8). - **Frontend/UI** - SendGrid icon + integration display name. - Workflow mapper support for Send Email, On Email Event, Create/Update Contact with failed state handling and metadata. - Building Blocks sidebar updates for SendGrid components/triggers. - **Docs** - Generated SendGrid component docs. <img width="862" height="728" alt="image" src="https://github.com/user-attachments/assets/6457989e-f8b3-4d09-85f0-21943966228f" /> https://github.com/user-attachments/assets/f271bfca-046a-4120-8701-1dd0e93d4642 --------- Signed-off-by: Pedro F. Leao <pedroforestileao@gmail.com> Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
## Summary - Adjusted SendGrid trigger run item title to `email · Event Type` with time-only subtitle - Ensured Details tab always includes a timestamp and places errors last for SendGrid actions - Hid default trigger metadata (all events, `*` category) and summarized long event lists - Displayed SendGrid contact list IDs as specs/badges instead of inline metadata <img width="298" height="224" alt="image" src="https://github.com/user-attachments/assets/c9c48f91-e912-480b-b476-c858b2cd4473" /> <img width="678" height="154" alt="image" src="https://github.com/user-attachments/assets/bbd790af-10d0-4e7b-9a4f-a2299ec6c474" /> Signed-off-by: Pedro F. Leao <pedroforestileao@gmail.com> Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
…assertion, example output) Signed-off-by: Rakes <niu-24-14815@niu.edu.in>
0469f2e to
515aec8
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 5 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| Default: "*", | ||
| Description: "Optional category filter (supports * wildcards)", | ||
| }, | ||
| {}, |
There was a problem hiding this comment.
Empty configuration field in OnEmailEvent Configuration
High Severity
The Configuration() method includes a trailing empty configuration.Field{} in the returned slice. This zero-value struct has no name, label, or type, and will likely render as a broken or blank field in the UI form for the "On Email Event" trigger configuration.
| --- | ||
| title: "SendGrid" | ||
| sidebar: | ||
| order: 15 |
There was a problem hiding this comment.
Duplicate sidebar order for Semaphore and SendGrid
Low Severity
Both Semaphore.mdx and SendGrid.mdx have order: 15 in their sidebar frontmatter. SendGrid appears after Semaphore alphabetically, so it needs order: 16, and Slack.mdx would need order: 17 to maintain proper ordering.
Additional Locations (1)
| return nil, fmt.Errorf( | ||
| "invalid private key format (expected PEM/OpenSSH block). Key length: %d, starts with: %q", | ||
| len(keyBytes), keyPreview, | ||
| ) |
There was a problem hiding this comment.
Private key material leaked in error message
Medium Severity
The getSigner method includes up to 50 characters of the raw private key bytes in its error message via keyPreview. This sensitive credential material could end up in logs, UI error displays, or monitoring systems. The error message already includes the key length, which is sufficient for debugging without exposing actual key content.
| command := spec.Command | ||
| if spec.WorkingDirectory != "" { | ||
| command = fmt.Sprintf("cd %s && %s", spec.WorkingDirectory, command) | ||
| } |
There was a problem hiding this comment.
Working directory not shell-quoted in SSH command
Medium Severity
The WorkingDirectory value is interpolated directly into the shell command without quoting. Paths containing spaces, shell metacharacters, or special characters will cause the cd to fail or behave unexpectedly. The directory path needs to be shell-quoted in the fmt.Sprintf call.
|
|
||
| var passphrase []byte | ||
| if spec.Authentication.Passphrase.IsSet() { | ||
| passphrase, _ = ctx.Secrets.GetKey(spec.Authentication.Passphrase.Secret, spec.Authentication.Passphrase.Key) |
There was a problem hiding this comment.
Missing error check on passphrase secret lookup
Medium Severity
When the user configures a passphrase secret reference and IsSet() returns true, the error from ctx.Secrets.GetKey is silently discarded with _. If the referenced secret or key doesn't exist, passphrase will be nil, and the SSH client will attempt to parse the encrypted key without a passphrase. This produces a misleading "failed to parse private key" error instead of a clear message about the missing passphrase credential — unlike the private key path directly above, which properly checks and wraps the error.







Summary
This PR adds a new Docker Hub integration for SuperPlane as described in #2243.
Changes
Base Integration
Trigger: On Image Pushed
Action: List Tags
Frontend
Screen.Recording.2026-02-04.at.12.02.00.AM.mp4
Testing
Closes #2243