Merge branch 'next' into newarchitecture#7428
Merge branch 'next' into newarchitecture#7428ar2rsawseen wants to merge 1 commit intonewarchitecturefrom
Conversation
# Conflicts: # api/parts/mgmt/apps.js # package-lock.json # package.json # plugins/hooks/package-lock.json # plugins/hooks/package.json # plugins/hooks/tests/crud.js # plugins/pluginManager.js # plugins/push/api/api-auto.js # plugins/push/api/api-message.js # plugins/push/api/jobs/util/connector.js # plugins/push/api/send/data/message.js # plugins/push/api/send/platforms/h.js # plugins/push/package-lock.json # plugins/reports/api/reports.js # plugins/web/api/api.js # ui-tests/cypress/support/commands.js # ui-tests/cypress/support/e2e.js
There was a problem hiding this comment.
Pull request overview
This PR primarily merges next into newarchitecture, bringing in a broad set of changes across core server, plugins, UI, tests, Docker build assets, and dependency updates.
Changes:
- Update/expand feature work across multiple plugins (notably Hooks SSRF protection, Web client-hints parsing, Push Huawei platform handling).
- Improve UI test stability and diagnostics (Cypress upgrades, scrolling/loading helpers, global failure formatter, updated selectors).
- Update core/frontend UX strings and some internal utilities (Mongo connection string handling, response headers for Client Hints).
Reviewed changes
Copilot reviewed 55 out of 64 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| ui-tests/package.json | Bumps Cypress version used for UI tests. |
| ui-tests/package-lock.json | Lockfile updates for Cypress and transitive dependencies. |
| ui-tests/cypress/support/elements/onboarding/initialSetup.js | Updates data-test-id selectors for onboarding initial setup. |
| ui-tests/cypress/support/elements/dashboard/manage/alerts/alerts.js | Updates data-test-id selectors for alerts drawer fields. |
| ui-tests/cypress/support/e2e.js | Adds global fail formatter + debug context reset per test. |
| ui-tests/cypress/support/debugContext.js | Adds shared debug context helpers for richer failures. |
| ui-tests/cypress/support/commands.js | Refines click/body helpers and adds checkLoading() command. |
| ui-tests/cypress/lib/dashboard/messaging/messaging.js | Forces click on a tab to improve test reliability. |
| ui-tests/cypress/lib/dashboard/manage/sdk/stats.js | Adds scrolling and forces tab clicks for stability. |
| ui-tests/cypress/lib/dashboard/home/home.js | Adds scroll steps before verifying elements. |
| ui-tests/cypress/lib/dashboard/feedback/ratings/widgets.js | Adjusts navigation click behavior and adds loading wait. |
| ui-tests/cypress/lib/dashboard/crashes/crashes.js | Adds scroll to bottom before verifying chart elements. |
| ui-tests/cypress/lib/dashboard/analytics/events/events.js | Updates compared event name and forces option click. |
| ui-tests/cypress/e2e/dashboard/manage/apps/apps.cy.js | Removes stray whitespace line in test. |
| ui-tests/cypress.config.sample.js | Comments out retries setting in sample config. |
| plugins/web/tests.js | Adds API tests for UA + Client Hints parsing behavior. |
| plugins/web/api/ingestor.js | Implements Client Hints parsing and uses /sdk/pre hook to set metrics. |
| plugins/system-utility/package-lock.json | Updates dependencies for system-utility plugin. |
| plugins/star-rating/frontend/public/templates/feedback-popup.html | Makes asset URLs respect subdirectory base path and adds countlyPath usage. |
| plugins/star-rating/frontend/public/templates/drawer.html | Adjusts default logo image path in drawer UI. |
| plugins/star-rating/frontend/public/stylesheets/ratings-iframe.scss | Removes hardcoded asset URLs (moved to template inline style). |
| plugins/star-rating/frontend/app.js | Passes countlyPath to popup template renderer. |
| plugins/reports/api/reports.js | Switches reports secret key defaulting to a generated value. |
| plugins/push/package-lock.json | Large dependency updates for push plugin. |
| plugins/push/api/send/platforms/h.js | Adds Huawei Push Kit platform implementation. |
| plugins/push/api/jobs/util/connector.js | Adds connector stream for push job processing and connection management. |
| plugins/pluginManager.ts | Reworks Mongo connection string DB replacement via mongodb-connection-string-url. |
| plugins/hooks/tests/ssrf.js | Adds SSRF protection tests for Hooks HTTPEffect. |
| plugins/hooks/tests/index.js | Aggregates hooks tests (crud + ssrf). |
| plugins/hooks/tests/crud.js | Fixes require paths and formatting for hooks CRUD tests. |
| plugins/hooks/package.json | Adds ipaddr.js dependency for SSRF protection. |
| plugins/hooks/package-lock.json | Lockfile updates for hooks deps (incl. isolated-vm bump + ipaddr.js). |
| plugins/hooks/frontend/public/templates/vue-drawer.html | Enables async submit behavior for drawer. |
| plugins/hooks/frontend/public/localization/hooks.properties | Adds localization key for hook test failure. |
| plugins/hooks/frontend/public/javascripts/countly.views.js | Updates drawer submit to async callback pattern. |
| plugins/hooks/frontend/public/javascripts/countly.models.js | Makes saveHook return a Promise and improves error messaging; adds testHook error handler. |
| plugins/hooks/api/ssrf-protection.js | Introduces SSRF validation utilities (DNS/IP checks + redirect disabling). |
| plugins/hooks/api/parts/effects/http.js | Enforces SSRF revalidation after template expansion before outbound calls. |
| plugins/hooks/api/api.js | Switches HTTPEffect URL validation to SSRF module (save + test). |
| plugins/data-manager/frontend/public/templates/event-group-drawer.html | Replaces <el-select> with cly-select-x multi selector + validation styling. |
| plugins/data-manager/frontend/public/templates/create-events-drawer.html | Improves cly-select-x sizing behavior for category selector. |
| plugins/data-manager/frontend/public/localization/data-manager.properties | Adds localization key and formatting fix. |
| plugins/dashboards/api/parts/dashboards.js | Decodes HTML for event segment meta values. |
| plugins/crashes/api/api.js | Tightens args parsing, app_id consistency checks, and parameter validation for crash comments. |
| package.json | Updates multiple dependencies; adds mongodb-connection-string-url. |
| frontend/express/public/localization/dashboard/dashboard.properties | Adds download/link text and image generated message. |
| frontend/express/public/javascripts/countly/vue/components/input.js | Adjusts test-id slug generation and adds a test id to remove icon. |
| frontend/express/public/javascripts/countly/vue/components/form.js | Makes form-field header test-id incorporate label slug. |
| frontend/express/public/core/home/javascripts/countly.views.js | Updates home image-download notification to new localized copy. |
| Dockerfile-frontend | Pins global npm version to npm@10. |
| Dockerfile-centos-frontend | Switches raven-release install flow and pins npm@10. |
| Dockerfile-centos-api | Switches raven-release install flow and pins npm@10. |
| Dockerfile-api | Pins global npm version to npm@10. |
| CHANGELOG.md | Adds release notes for multiple 25.03.x versions and dependency bumps. |
| bin/scripts/timezones/package.json | Bumps moment-timezone. |
| bin/scripts/timezones/package-lock.json | Lockfile for moment-timezone bump. |
| bin/countly.install_rhel.sh | Changes font/raven-release install flow for RHEL/CentOS. |
| api/utils/countly-request/package-lock.json | Updates minimatch/brace-expansion versions. |
| api/utils/common.js | Adds Accept-CH/Critical-CH headers (Client Hints) and X-Countly header. |
| api/parts/mgmt/apps.js | Adds metric_changes collection drop + index creation during reset. |
| .github/workflows/release_notice.yml | Updates Slack GitHub Action version. |
| .github/workflows/docker-image.yml | Updates pinned SHAs for Docker login/build actions. |
| .github/workflows/deploy.yml | Updates pinned SHA for Docker login/build actions. |
Files not reviewed (5)
- api/utils/countly-request/package-lock.json: Language not supported
- plugins/hooks/package-lock.json: Language not supported
- plugins/push/package-lock.json: Language not supported
- plugins/system-utility/package-lock.json: Language not supported
- ui-tests/package-lock.json: Language not supported
| replaceDatabaseString(str: string, db: string = 'countly'): string { | ||
| const connectionString = new ConnectionString(str); | ||
| connectionString.pathname = '/' + db; | ||
| return connectionString.toString(); |
There was a problem hiding this comment.
replaceDatabaseString() now unconditionally parses the URI with new ConnectionString(str) and overwrites pathname, but it no longer preserves/ensures authSource=admin when the original URL used /admin without an explicit authSource. This can break auth for common MongoDB URIs like mongodb://user:pass@host/admin. Consider preserving existing authSource, and if the original path was admin and no authSource is provided, explicitly set authSource=admin on the resulting connection string. Also consider wrapping parsing in try/catch to avoid crashing on malformed/legacy connection strings and fall back to the previous behavior or return the original string.
| /** | ||
| * Generates a cryptographically secure random string of the given length. | ||
| * @param {number} length - desired string length | ||
| * @returns {string} random hex string truncated to the given length | ||
| */ | ||
| function generateRandomString(length) { | ||
| return crypto.randomBytes(Math.ceil(length / 2)).toString('hex').slice(0, length); | ||
| } | ||
|
|
||
| plugins.setConfigs("reports", { | ||
| secretKey: countlyApiConfig?.encryption?.reports_key || generateRandomString(32), | ||
| }); |
There was a problem hiding this comment.
plugins.setConfigs("reports", { secretKey: ... }) uses generateRandomString(32) as a fallback, but setConfigs only sets an in-memory default. If countlyApiConfig.encryption.reports_key is missing, the secret will change on every process start, which can break decrypt/verify for any persisted report/email data relying on this key. Prefer requiring an explicit configured key, or generating once and persisting it (e.g., into config on install/migration or a dedicated persistent settings store) rather than regenerating at runtime.
| // Hostname is a domain name — resolve it to check the IP | ||
| try { | ||
| const address = await new Promise((resolve, reject) => { | ||
| dns.lookup(hostname, (err, addr) => { | ||
| if (err) { | ||
| reject(err); | ||
| } | ||
| else { | ||
| resolve(addr); | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| if (isBlockedIP(address)) { | ||
| return { safe: false, error: `Hostname "${hostname}" resolves to private/reserved IP "${address}"` }; | ||
| } | ||
| } |
There was a problem hiding this comment.
isUrlSafe() only checks a single DNS result via dns.lookup(hostname, ...). This can miss hosts that resolve to multiple A/AAAA records where some are private/reserved. Consider using dns.lookup(hostname, { all: true }) and rejecting if any resolved address is blocked. Also, to prevent DNS-rebinding between validation and the actual outbound request, consider passing a custom lookup/dnsLookup function to the HTTP client so the connection uses the same validated resolution (or re-checks every address actually used).
| <div class="ratings-drawer__rp-footer" data-test-id="ratings-drawer-ratingspopup-poweredby-label"> | ||
| <img v-if="imageSrc && drawerScope.editedObject.logoType === 'custom'" class="ratings-drawer__image" :src="imageSrc"> | ||
| <img v-if="drawerScope.editedObject.logoType === 'default'" src="/star-rating/images/star-rating/powered-by-countly.svg"> | ||
| <img v-if="drawerScope.editedObject.logoType === 'default'" src="star-rating/images/star-rating/powered-by-countly.svg"> | ||
| </div> |
There was a problem hiding this comment.
The default logo image src was changed from an absolute path (/star-rating/...) to a relative path (star-rating/...). In the dashboard (non-iframe) context this will resolve relative to the current route and can 404. Use an absolute path (and, if Countly is served from a subdirectory, incorporate that base path consistently) to ensure the asset always loads.
| return this.sendRequest(JSON.stringify(content)).then(resp => { | ||
| try { | ||
| if (typeof resp === 'string' && resp[0] === '"' && resp[resp.length - 1] === '"') { | ||
| resp = resp.substring(1, resp.length - 2); | ||
| } | ||
| resp = JSON.parse(resp); |
There was a problem hiding this comment.
resp.substring(1, resp.length - 2) removes two characters from the end. If the response is a quoted JSON string (e.g. "{...}"), this truncates the last character and will make JSON.parse fail or corrupt the payload. Use slice(1, -1) (or substring(1, resp.length - 1)) to strip only the surrounding quotes.
| import 'cypress-file-upload'; | ||
| import { setDebugContext, clearDebugContext } from './debugContext'; | ||
| const helper = require('./helper'); |
There was a problem hiding this comment.
setDebugContext / clearDebugContext are imported but not used in this file. If eslint is enabled for ui-tests, this will fail linting; otherwise it adds noise. Remove the unused imports or start using them to annotate assertions/steps for the new global fail formatter.
| curl -L -O -J "https://box.tools.count.ly/public.php/dav/files/Wj8opzNdyE5DyDX/?accept=zip" && \ | ||
| yum install -y raven-release.el8.noarch.rpm && \ | ||
| yum install -y ipa-gothic-fonts && \ | ||
| yum install -y wget openssl-devel make git libsqlite* sqlite unzip bzip2 && \ |
There was a problem hiding this comment.
The build now downloads .../?accept=zip and then tries to yum install an RPM filename (raven-release.el8.noarch.rpm) without extracting anything. If the URL actually returns a ZIP archive (as the query parameter suggests), the RPM won’t exist and the Docker build will fail. Consider downloading the RPM directly (no zip), or unzip the archive and install the extracted RPM with the correct filename.
| curl -L -O -J "https://box.tools.count.ly/public.php/dav/files/Wj8opzNdyE5DyDX/?accept=zip" && \ | ||
| yum install -y raven-release.el8.noarch.rpm && \ | ||
| yum install -y ipa-gothic-fonts && \ | ||
| yum install -y wget openssl-devel make git sqlite libsqlite* unzip bzip2 && \ |
There was a problem hiding this comment.
The build now downloads .../?accept=zip and then tries to yum install an RPM filename (raven-release.el8.noarch.rpm) without extracting anything. If the URL returns a ZIP archive, the RPM won’t exist and the Docker build will fail. Consider downloading the RPM directly or extracting the archive before installing.
Conflicts:
api/parts/mgmt/apps.js
package-lock.json
package.json
plugins/hooks/package-lock.json
plugins/hooks/package.json
plugins/hooks/tests/crud.js
plugins/pluginManager.js
plugins/push/api/api-auto.js
plugins/push/api/api-message.js
plugins/push/api/jobs/util/connector.js
plugins/push/api/send/data/message.js
plugins/push/api/send/platforms/h.js
plugins/push/package-lock.json
plugins/reports/api/reports.js
plugins/web/api/api.js
ui-tests/cypress/support/commands.js
ui-tests/cypress/support/e2e.js