Content translation access manager may use the wrong revision

Created on 12 July 2023, over 1 year ago
Updated 22 December 2023, 11 months ago

Problem/Motivation

The content translation manager sometimes looks for existing translations on the wrong revision ("active" instead of "latest") of an entity. This assumes content moderation is active for the entity, and there are at least two languages it can be translated into.

The access manager does not use the latest revision of the entity being checked for translation access if the source translation is in a draft state, and the target translation had a later draft which was just removed. This means the "active" revision of the source language is the revision before the source draft was created. If that active revision has a translation into the target language, linking to the add-translation page is technically not allowed (but no access check is currently performed for the operation).

Note that this only affects links, you can still access the actual form because it already handles loading the latest revision to work around this issue (see the top off ContentTranslationController::add().

Steps to reproduce

This was found while working on #2473873-111: Views entity operations lack cacheability support, resulting in incorrect dropbuttons β†’ because the test ContentTranslationRevisionTranslationDeletionTest::testOverview() failed. The test performs the steps below, which normally pass, but the patch from that issue now runs an access check on each operation link before rendering them.
(This is iteration 2 of the test, with the editor role. Iteration 1 passes because access checks are bypassed.)

  1. Create an English published node "Test 2.1 EN"
    Verify translations can be added.
  2. Add an Italian draft "Test 2.2 IT".
    Verify the draft can not be deleted because it's unpublished.
  3. Publish the Italian translation "Test 2.3 IT"
    Verify it can be deleted.
  4. Create an English draft "Test 2.4 EN".
    Verify Italian translation still exists.
  5. Delete the Italian translation.
    Verify the 'Add' operation for Italian reappears. This failed
  6. Publish the English draft "Test 2.6 EN".
    Verify the Italian translation does not reappear.
  7. Add an Italian published translation "Test 2.t IT".
    Verify it can be deleted.
  8. Create an Italian draft "Test 2.8 IT".
    Verify it can not be deleted.
  9. Delete the Italian draft.
    Verify it can be deleted again.
  10. Delete the Italian translation.
    Verify it can be added again.

When the Italian translation is deleted in step 5 the English draft "Test 2.4 EN" is the latest revision and no longer has a translation. The access manager gets its argument from the route match for the translation route, which has load_latest_revision = TRUE, but it loads the latest "active" revision - which the entity repository says is the last one which was translation affected.

The last English revision which was translation affected (titled "Test 2.1 EN") still had "Test 2.3 IT" as a translation, as the deletion created a new revision without any translations affected.

The result is that the 'Add' operation is missing for Italian on line 142 of that test. Editors still had access to the translate form if the current interface language was either Italian or French, but not in English. While the Add operation points to the Italian version of the translation form it being added depended on an access check performed on the "active" revision - which already has an Italian translation - so the link no longer show up because the URL is inaccessible.

As mentioned earlier, the page itself is still accessible in Italian or French (but not English)
There is a secondary issue in ContentTranslationController::add() which also causes problems for other links, like those in the language switcher block if you have that enabled, when testing this manually.
As the controller actually adds the target translation to the entity it will always exist for the latest revision when anything performing the same access checks after the form has loaded. The easiest way around that is to simply clone the entity for the purpose of the form so the rest of the system can rely on it being in the correct current state. Without this change the access checks only work before the form has been loaded as the latest revision is statically cached once loaded.

Proposed resolution

The access manager should use the latest revision when looking for existing translations, not the "active" revision, as already done by ContentTranslationController::add().

Remaining tasks

None

User interface changes

None

API changes

None

Data model changes

None

πŸ› Bug report
Status

Needs work

Version

11.0 πŸ”₯

Component
Content translationΒ  β†’

Last updated 2 days ago

No maintainer
Created by

πŸ‡ΈπŸ‡ͺSweden twod Sweden

Live updates comments and jobs are added and updated live.
  • Needs subsystem maintainer review

    It is used to alert the maintainer(s) of a particular core subsystem that an issue significantly impacts their subsystem, and their signoff is needed (see the governance policy draft for more information). Also, if you use this tag, make sure the issue component is set to the correct subsystem. If an issue significantly impacts more than one subsystem, use needs framework manager review instead.

  • Needs manual testing

    The change/bugfix cannot be fully demonstrated by automated testing, and thus requires manual testing in a variety of environments.

Sign in to follow issues

Merge Requests

Comments & Activities

Production build 0.71.5 2024