Needs work
Project:
Drupal.org security advisory coverage applications
Component:
module
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
15 Sep 2026 at 16:22 UTC
Updated:
15 Oct 2026 at 16:42 UTC
Jump to comment: Most recent
Comments
Comment #2
avpadernoComment #3
avpadernoThank you for applying!
Before giving links helpful to understand how the review process works, what to expect from a review, and what to do to avoid a review takes more time than needed, I would like to thank all the reviewers for the work they do.
These applications are volunters-driven, which also means it is not possible to predict when an application will be marked fixed and the applicant will get the permission to opt projects into security advisory policy. While we aim to make an application as quick as possible, it is also important for us that more people review the project used for an application. In this way, we make sure applications do not miss some important points that should be instead reported.
Applications are not meant to be complete debugging sessions that eliminate every existing bug, though. I apologize if sometimes applications seem to go into too-detailed reviews.
Please read Review process for security advisory coverage: What to expect for more details and Security advisory coverage application checklist to understand what reviewers look for. Tips for ensuring a smooth review gives some hints for a smoother review.
The important notes are the following.
Keep in mind that once the project is opted into security advisory coverage, only Security Team members may change coverage.
To the reviewers
Please read How to review security advisory coverage applications, Application workflow, What to cover in an application review, and Tools to use for reviews.
The important notes are the following.
For new reviewers, I would also suggest to first read In which way the issue queue for coverage applications is different from other project queues.
Comment #4
avpadernoAs a side note, this application was unpublished by the anti-spam system that runs on drupal.org. That is why the first comment has been posted today.
Comment #5
vishal.kadam1. FILE: wxrks_tmgmt.module
For a new module that aims to be compatible with Drupal 10 and Drupal 11, I would rather implement hooks as class methods as described in Support for object oriented hook implementations using autowired services.
2. FILE: src/Plugin/QueueWorker/WxrksApiFetchQueueWorker.php, src/Plugin/QueueWorker/WxrksApiJobQueueWorker.php
Projects that are compatible with Drupal 10 or higher versions should use attributes instead of annotations.
Comment #6
guilhermesimbalista commentedThanks for the review. Both points are fixed in the 1.0.x branch:
src/Hook/WxrksTmgmtHooks.phpusing#[Hook]. For Drupal 10,wxrks_tmgmt.modulekeeps procedural functions marked#[LegacyHook]that only delegate to that class.#[QueueWorker]. The Views field plugins and the translator plugin now use attributes too.Comment #7
guilhermesimbalista commentedComment #8
shaker-gspikes commentedManual review of 1.0.x at 7a4c2ec (9 October 2026). GitLab CI on that commit is green, phpcs (Drupal, DrupalPractice) is clean locally, and all commits are by the applicant. The fixes from #5 are in: hooks live in
src/Hook/WxrksTmgmtHooks.phpwith#[LegacyHook]wrappers, and the queue workers, Views fields and translator use attributes.Good things first: the module defines no routes or webhooks, TLS verification is never disabled, the auth token stays in memory and is never logged, remote UUIDs are validated before they are used in file paths, delivered ZIPs go to
private://(ortemporary://) with size limits, the download URL is checked and fetched withallow_redirects => FALSE, the Views fields use#plain_text, and the XML is parsed withLIBXML_NONET.Points to fix:
1. Credentials end up in exported configuration (src/WxrksTranslatorUi.php, config/schema/wxrks_tmgmt.schema.yml):
accesskeyandsecretAccesskeyare plain settings of thetmgmt.translator.*config entity, sodrush config:exportwrites the secret key to the sync directory and into the site's repository. The usual workaround, a$config['tmgmt.translator.wxrks']['settings']['secretAccesskey']override in settings.php, does not survive either:validateConfigurationForm()refills an empty password field fromloadUnchangedTranslator(), which callsloadUnchanged(), and that applies config overrides. The next save of the translator form copies the overridden secret into active configuration. Store the key through the Key module (as other TMGMT providers do), or at least read the stored value withloadOverrideFree()and document the settings.php override in the README.2. Aborting a job can fail half-way (src/Plugin/tmgmt/Translator/WxrksTranslator.php, abortTranslation()):
foreach ($job_items as $job_item) { $job_item->abortTranslation(); }In TMGMT,
JobItem::abortTranslation()throwsTMGMTException('Cannot abort job item.')unless the item is active or needs review, while the job itself is still abortable. A job with one accepted item (common with auto-accept) therefore ends on an error page with some items aborted, the job state unchanged and the wxrks project never cancelled. Skip items where$job_item->isAbortable()is FALSE, and cancel the remote project regardless.3. Connection errors are not caught (WxrksTranslator.php, doRequest() and the login request): both only catch
BadResponseException, andgetLanguagePairs()only catchesTMGMTException. A DNS failure, refused connection or timeout throws a GuzzleConnectExceptionout ofgetSupportedTargetLanguages(), which TMGMT calls while checking out a job, so the checkout page returns a 500 error when the wxrks API is unreachable. CatchGuzzleExceptionand rethrow it asTMGMTException; it would also help to set explicitconnect_timeout/timeoutoptions on these requests.4. The cron queue worker can block cron for minutes (src/Plugin/QueueWorker/WxrksApiFetchQueueWorker.php): the worker declares
cron: ['time' => 30], but cron only checks that budget between items. A single item goes throughimportTranslation()→downloadFilesAsync(), which polls for up to$maxTime = 180000ms and then downloads with'timeout' => 150. With automated cron that runs inside a visitor's request and can exceedmax_execution_time, leaving the cron lock and the claimed item stuck. The "Fetch translations" button runs the same path in a normal web request. ThrowingDelayedRequeueExceptionwhile the export is still being prepared (instead of sleeping in a loop), and using the Batch API for the button, would keep each step short.5. Pending re-translations are kept in the cache (src/Helper/QueueGateKeeper.php, cacheForFutureRequeue()): the list of nodes to re-queue is stored in
cache.defaultwithCACHE_PERMANENT. Anydrush cache:rebuild(every deployment) silently drops it, and the read-modify-write without a lock loses entries when two workers run at the same time. This is state, not cache: the State API or a key/value collection fits better.6. Continuous-job submissions are lost when the API call fails (src/Plugin/QueueWorker/WxrksApiJobQueueWorker.php): the worker saves a new job item, calls
requestJobItemTranslation()(which catches every exception and only logs it), then removes the node from future re-queues, andprocessItem()also catches\Throwable. If the login fails, the queue item is deleted, the job item stays inactive and the change is never retried. Let the failure reach the queue asRequeueExceptionorSuspendQueueExceptionwhen the API is down.Minor:
-
wxrks_tmgmt.info.ymldepends ontmgmt:tmgmtwithout a version, whilecomposer.jsonrequires^1.18(the first release with theTranslatorPluginattribute).tmgmt:tmgmt (>=8.x-1.18)keeps tarball installs from enabling it on an older TMGMT.-
QueueGateKeeperqueues every active or in-review job item for the fetch queue, not only items of wxrks translators, so the queue also fills with other providers' items.-
hook_uninstall()does not delete the two queues or the module's cache entries.Status: Needs work (points 1 to 3).