CVE-2024-23344 (published 2024-02-06T16:15Z)

Tuleap is an Open Source Suite to improve management of software developments and collaboration. Some users might get access to restricted information when a process validates the permissions of multiple users (e.g. mail notifications). This issue has been patched in version 15.4.99.140 of Tuleap Community Edition.

CVSS v3 base score: 6.5, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N)

Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/Enalean/tuleap
commit_details: repo_url: https://github.com/Enalean/tuleap
author: Nicolas Terray
author_date: 2024-01-19 17:23:43+01:00
msg: fix: CCE user cannot update artifact sometimes

How to reproduce:
Have an artifact A with a comment containing a cross reference to another
artifact B like `See art #123`.
In the tracker of the artifact A, upload a Custom Code Execution module
in the administration.

There is an example module if you need one:
```
cd plugins/tracker_cce/wasm_modules/post-action-add-comment
nix-shell
cargo build --target wasm32-wasi --release
```
Then you can upload the generated file:
`plugins/tracker_cce/wasm_modules/post-action-add-comment/target/wasm32-wasi/release/post-action-add-comment.wasm`

The example module take an integer field `field_a`, an integer field
`field_b`, and fill a text field `field_sum`. You will need them for the
test. Or use your own module.

Now update the artifact A. The (async) execution of the module should be a
success and a new comment is added to the artifact by CCE user.

Closes request #35862: Artifact userCanView not properly cached
Part of story #35093: execute custom code as artifact post action

Change-Id: Id08ce6570c1dd2c7ebedcd70339f9d9d6b008d58
repository: repo_url: https://github.com/Enalean/tuleap
repo_name: Enalean/tuleap
description: Tuleap is an Open Source Suite to improve management of software developments and collaboration. With a single web-based solution, project managers, developers & quality managers can easily build, deploy software projects.
repo_language: PHP
owner: Enalean
file_changes: filename: PromotedMilestoneBuilderTest.php
change_type: ModificationType.MODIFY
diff: @@ -67,7 +67,7 @@ final class PromotedMilestoneBuilderTest extends TestCase
         $this->tracker     = TrackerTestBuilder::aTracker()->build();
         $this->artifact    = ArtifactTestBuilder::anArtifact(1)
             ->inTracker($this->tracker)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withChangesets($this->changeset)
             ->build();
         $this->title_field = TrackerFormElementStringFieldBuilder::aStringField(301)->build();
@@ -93,7 +93,7 @@ final class PromotedMilestoneBuilderTest extends TestCase
     {
         $artifact = ArtifactTestBuilder::anArtifact(1)
             ->inTracker($this->tracker)
-            ->userCanView(false)
+            ->userCannotView($this->user)
             ->build();
 
         self::assertTrue($this->builder->build($artifact, $this->user, $this->project)->isNothing());

programming_language: PHP
filename: MilestoneFactoryGetBareMilestoneByArtifactIdTest.php
change_type: ModificationType.MODIFY
diff: @@ -118,7 +118,7 @@ final class MilestoneFactoryGetBareMilestoneByArtifactIdTest extends \Tuleap\Tes
             ->withTitle('title')
             ->inTracker($planning_tracker)
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->withAncestors([])

programming_language: PHP
filename: MilestoneFactoryGetMilestoneTest.php
change_type: ModificationType.MODIFY
diff: @@ -140,7 +140,7 @@ final class MilestoneFactoryGetMilestoneTest extends \Tuleap\Test\PHPUnit\TestCa
         $release_1_0   = ArtifactTestBuilder::anArtifact(1)
             ->withTitle('release_1_0')
             ->withChangesets(ChangesetTestBuilder::aChangeset('1')->build())
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->withAncestors([])
@@ -149,7 +149,7 @@ final class MilestoneFactoryGetMilestoneTest extends \Tuleap\Test\PHPUnit\TestCa
             ->withTitle('sprint_1')
             ->withChangesets(ChangesetTestBuilder::aChangeset('2')->build())
             ->inTracker($sprints_tracker)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->withAncestors([])
@@ -158,7 +158,7 @@ final class MilestoneFactoryGetMilestoneTest extends \Tuleap\Test\PHPUnit\TestCa
             ->withTitle('sprint_2')
             ->withChangesets(ChangesetTestBuilder::aChangeset('3')->build())
             ->inTracker($sprints_tracker)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->withAncestors([])
@@ -167,7 +167,7 @@ final class MilestoneFactoryGetMilestoneTest extends \Tuleap\Test\PHPUnit\TestCa
             ->withTitle('hackfest_2012')
             ->withChangesets(ChangesetTestBuilder::aChangeset('4')->build())
             ->inTracker($hackfests_tracker)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->withAncestors([])
@@ -228,7 +228,7 @@ final class MilestoneFactoryGetMilestoneTest extends \Tuleap\Test\PHPUnit\TestCa
             ->withTitle('release_1_0')
             ->withChangesets(ChangesetTestBuilder::aChangeset('1')->build())
             ->inTracker($tracker)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->withAncestors([])

programming_language: PHP
filename: MilestoneFactoryGetPaginatedMilestonesTest.php
change_type: ModificationType.MODIFY
diff: @@ -397,7 +397,7 @@ final class MilestoneFactoryGetPaginatedMilestonesTest extends \Tuleap\Test\PHPU
             ->withTitle('title')
             ->inTracker($milestone_tracker)
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->withAncestors([])

programming_language: PHP
filename: MilestoneFactoryGetTopMilestonesTest.php
change_type: ModificationType.MODIFY
diff: @@ -121,7 +121,7 @@ final class MilestoneFactoryGetTopMilestonesTest extends \Tuleap\Test\PHPUnit\Te
         $artifact_1 = ArtifactTestBuilder::anArtifact(1)
             ->inTracker($this->tracker)
             ->withChangesets(ChangesetTestBuilder::aChangeset('1')->build())
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->withAncestors([])
@@ -129,7 +129,7 @@ final class MilestoneFactoryGetTopMilestonesTest extends \Tuleap\Test\PHPUnit\Te
         $artifact_2 = ArtifactTestBuilder::anArtifact(2)
             ->inTracker($this->tracker)
             ->withChangesets(ChangesetTestBuilder::aChangeset('2')->build())
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->withAncestors([])
@@ -176,7 +176,7 @@ final class MilestoneFactoryGetTopMilestonesTest extends \Tuleap\Test\PHPUnit\Te
         $artifact_2 = ArtifactTestBuilder::anArtifact(2)
             ->inTracker($this->tracker)
             ->withChangesets(ChangesetTestBuilder::aChangeset('1')->build())
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->withAncestors([])

programming_language: PHP
filename: MilestoneFactoryTest.php
change_type: ModificationType.MODIFY
diff: @@ -209,7 +209,7 @@ class MilestoneFactoryTest extends \Tuleap\Test\PHPUnit\TestCase
         return ArtifactTestBuilder::anArtifact($id)
             ->inTracker($tracker)
             ->withChangesets(ChangesetTestBuilder::aChangeset('1')->build())
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->withStatus($status)
             ->isOpen($is_open)

programming_language: PHP
filename: IterationsRetrieverTest.php
change_type: ModificationType.MODIFY
diff: @@ -922,7 +922,7 @@ final class IterationsRetrieverTest extends \Tuleap\Test\PHPUnit\TestCase
                 )
             );
 
-        $iteration = $this->anArtifactWithoutChangesetValue(201, 'Title', $this->tracker, true);
+        $iteration = $this->anArtifactWithoutChangesetValue(201, 'Title', $this->tracker);
 
         $this->artifact_factory
             ->expects(self::once())
@@ -1293,7 +1293,7 @@ final class IterationsRetrieverTest extends \Tuleap\Test\PHPUnit\TestCase
                 )
             );
 
-        $iteration = $this->anArtifact(123, "Sprint W42", $this->tracker, true);
+        $iteration = $this->anArtifact(123, "Sprint W42", $this->tracker);
 
         $this->artifact_factory
             ->expects(self::once())
@@ -1353,7 +1353,7 @@ final class IterationsRetrieverTest extends \Tuleap\Test\PHPUnit\TestCase
             ->willReturn($db_result);
     }
 
-    private function anArtifact(int $id, string $title, Tracker $tracker, bool $readable): Artifact
+    private function anArtifact(int $id, string $title, Tracker $tracker): Artifact
     {
         $changeset       = $this->createMock(\Tracker_Artifact_Changeset::class);
         $changeset_value = $this->createMock(\Tracker_Artifact_ChangesetValue_Date::class);
@@ -1364,13 +1364,13 @@ final class IterationsRetrieverTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle($title)
             ->inTracker($tracker)
             ->withChangesets($changeset)
-            ->userCanView($readable)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();
     }
 
-    private function anArtifactWithoutChangesetValue(int $id, string $title, Tracker $tracker, bool $readable): Artifact
+    private function anArtifactWithoutChangesetValue(int $id, string $title, Tracker $tracker): Artifact
     {
         $changeset       = $this->createMock(\Tracker_Artifact_Changeset::class);
         $changeset_value = $this->createMock(\Tracker_Artifact_ChangesetValue_Date::class);
@@ -1381,7 +1381,7 @@ final class IterationsRetrieverTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle($title)
             ->inTracker($tracker)
             ->withChangesets($changeset)
-            ->userCanView($readable)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();

programming_language: PHP
filename: RoadmapTasksRetrieverTest.php
change_type: ModificationType.MODIFY
diff: @@ -666,7 +666,7 @@ final class RoadmapTasksRetrieverTest extends \Tuleap\Test\PHPUnit\TestCase
 
         $task_201 = $this->anArtifact(201, 'Do this', $tracker, true, $semantic_timeframe);
         $task_202 = $this->anArtifact(202, 'Do that', $tracker, false, $semantic_timeframe);
-        $task_203 = $this->anArtifactWithoutStartDate(203, 'Do those', $tracker, true, $semantic_timeframe);
+        $task_203 = $this->anArtifactWithoutStartDate(203, 'Do those', $tracker, $semantic_timeframe);
         $task_204 = $this->anArtifact(204, 'Done more than 1 year ago', $tracker, true, $semantic_timeframe);
 
         $this->mockEffort($total_effort_field, [201 => 8, 203 => 3]);
@@ -806,7 +806,7 @@ final class RoadmapTasksRetrieverTest extends \Tuleap\Test\PHPUnit\TestCase
 
         $task_201 = $this->anArtifact(201, 'Do this', $tracker, true, $semantic_timeframe);
         $task_202 = $this->anArtifact(202, 'Do that', $tracker, false, $semantic_timeframe);
-        $task_203 = $this->anArtifactWithoutStartDate(203, 'Do those', $tracker, true, $semantic_timeframe);
+        $task_203 = $this->anArtifactWithoutStartDate(203, 'Do those', $tracker, $semantic_timeframe);
         $task_204 = $this->anArtifact(204, 'Done more than 1 year ago', $tracker, true, $semantic_timeframe);
 
         $this->mockEffort($total_effort_field, [201 => 8, 203 => 3]);
@@ -1079,7 +1079,7 @@ final class RoadmapTasksRetrieverTest extends \Tuleap\Test\PHPUnit\TestCase
             });
 
         $task_201 = $this->anArtifact(201, 'Do this', $tracker, true, $semantic_timeframe_tracker);
-        $task_203 = $this->anArtifactWithoutStartDate(203, 'Do those', $another_tracker, true, $semantic_timeframe_another_tracker);
+        $task_203 = $this->anArtifactWithoutStartDate(203, 'Do those', $another_tracker, $semantic_timeframe_another_tracker);
 
 
         $artifacts = [$task_201, $task_203];
@@ -1222,17 +1222,19 @@ final class RoadmapTasksRetrieverTest extends \Tuleap\Test\PHPUnit\TestCase
             );
         }
 
-        return ArtifactTestBuilder::anArtifact($id)
+        $artifact_test_builder = ArtifactTestBuilder::anArtifact($id)
             ->withTitle($title)
             ->inTracker($tracker)
             ->withChangesets($changeset)
-            ->userCanView($readable)
             ->withParent(null)
-            ->isOpen(true)
-            ->build();
+            ->isOpen(true);
+
+        return $readable
+            ? $artifact_test_builder->userCanView($this->user)->build()
+            : $artifact_test_builder->userCannotView($this->user)->build();
     }
 
-    private function anArtifactWithoutStartDate(int $id, string $title, Tracker $tracker, bool $readable, SemanticTimeframe $semantic_timeframe): Artifact
+    private function anArtifactWithoutStartDate(int $id, string $title, Tracker $tracker, SemanticTimeframe $semantic_timeframe): Artifact
     {
         $changeset   = ChangesetTestBuilder::aChangeset('1')->build();
         $start_field = $semantic_timeframe->getStartDateField();
@@ -1252,7 +1254,7 @@ final class RoadmapTasksRetrieverTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle($title)
             ->inTracker($tracker)
             ->withChangesets($changeset)
-            ->userCanView($readable)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();

programming_language: PHP
filename: Artifact.php
change_type: ModificationType.MODIFY
diff: @@ -242,10 +242,13 @@ class Artifact implements Recent_Element_Interface, Tracker_Dispatchable_Interfa
      * @var DBTransactionExecutor
      */
     private $transaction_executor;
-    private bool | null $user_permission_cache = null;
-    private ?Artifact $parent                  = null;
-    private bool $has_set_parent               = false;
-    private bool | null $is_open               = null;
+    /**
+     * @var array<int, bool>
+     */
+    private array $user_permission_cache = [];
+    private ?Artifact $parent            = null;
+    private bool $has_set_parent         = false;
+    private bool | null $is_open         = null;
 
     /**
      * Constructor
@@ -309,7 +312,10 @@ class Artifact implements Recent_Element_Interface, Tracker_Dispatchable_Interfa
         return $this->use_artifact_permissions;
     }
 
-    public function setUserCanView(bool $user_can_view): void
+    /**
+     * @param array<int, bool> $user_can_view
+     */
+    public function setUserCanView(array $user_can_view): void
     {
         $this->user_permission_cache = $user_can_view;
     }
@@ -323,8 +329,8 @@ class Artifact implements Recent_Element_Interface, Tracker_Dispatchable_Interfa
      */
     public function userCanView(?PFUser $user = null)
     {
-        if ($this->user_permission_cache !== null) {
-            return $this->user_permission_cache;
+        if ($user && isset($this->user_permission_cache[(int) $user->getId()])) {
+            return $this->user_permission_cache[(int) $user->getId()];
         }
 
         $user_manager       = $this->getUserManager();
@@ -342,10 +348,11 @@ class Artifact implements Recent_Element_Interface, Tracker_Dispatchable_Interfa
         if ($user === null) {
             $user = $user_manager->getCurrentUser();
         }
+        if (! isset($this->user_permission_cache[(int) $user->getId()])) {
+            $this->user_permission_cache[(int) $user->getId()] = PermissionsCache::userCanView($this, $user, $permission_checker);
+        }
 
-        $this->user_permission_cache = PermissionsCache::userCanView($this, $user, $permission_checker);
-
-        return $this->user_permission_cache;
+        return $this->user_permission_cache[(int) $user->getId()];
     }
 
     public function userCanUpdate(PFUser $user): bool

programming_language: Perl
filename: ArtifactTestBuilder.php
change_type: ModificationType.MODIFY
diff: @@ -47,7 +47,11 @@ final class ArtifactTestBuilder
      * @var \Tracker_ArtifactFactory | null
      */
     private $artifact_factory;
-    private bool|null $user_can_view = null;
+
+    /**
+     * @var array<int, bool>
+     */
+    private array $user_can_view = [];
 
     /**
      * @var \Project|null
@@ -136,9 +140,15 @@ final class ArtifactTestBuilder
         return $this;
     }
 
-    public function userCanView(bool $user_can_view): self
+    public function userCanView(PFUser $user): self
+    {
+        $this->user_can_view[$user->getId()] = true;
+        return $this;
+    }
+
+    public function userCannotView(PFUser $user): self
     {
-        $this->user_can_view = $user_can_view;
+        $this->user_can_view[$user->getId()] = false;
         return $this;
     }
 
@@ -206,9 +216,7 @@ final class ArtifactTestBuilder
         if ($this->last_changeset) {
             $artifact->setLastChangeset($this->last_changeset);
         }
-        if ($this->user_can_view !== null) {
-            $artifact->setUserCanView($this->user_can_view);
-        }
+        $artifact->setUserCanView($this->user_can_view);
         if ($this->has_parent) {
             $artifact->setParent($this->parent);
         }

programming_language: PHP
filename: ArtifactTest.php
change_type: ModificationType.ADD
diff: @@ -0,0 +1,45 @@
+<?php
+/**
+ * Copyright (c) Enalean, 2024 - Present. All Rights Reserved.
+ *
+ * This file is a part of Tuleap.
+ *
+ * Tuleap is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Tuleap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Tuleap. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace Tuleap\Tracker\Artifact;
+
+use Tuleap\Test\Builders\UserTestBuilder;
+use Tuleap\Test\PHPUnit\TestCase;
+
+final class ArtifactTest extends TestCase
+{
+    public function testUserCanViewCache(): void
+    {
+        $artifact = new Artifact(1, 2, 3, 4, false);
+
+        $bob   = UserTestBuilder::anActiveUser()->withId(1)->build();
+        $alice = UserTestBuilder::anActiveUser()->withId(2)->build();
+
+        $artifact->setUserCanView([
+            $bob->getId() => false,
+            $alice->getId() => true,
+        ]);
+
+        self::assertFalse($artifact->userCanView($bob));
+        self::assertTrue($artifact->userCanView($alice));
+    }
+}

programming_language: PHP
filename: TimeframeNotConfiguredTest.php
change_type: ModificationType.MODIFY
diff: @@ -117,18 +117,20 @@ final class TimeframeNotConfiguredTest extends TestCase
 
     public function testItReturnsAnEmptyDatePeriodWithAnErrorMessageForArtifactREST(): void
     {
+        $user = UserTestBuilder::anActiveUser()->build();
+
         $changeset = $this->createMock(\Tracker_Artifact_Changeset::class);
         $artifact  = ArtifactTestBuilder::anArtifact(1)
             ->withTitle('release_1_0')
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($user)
             ->build();
         $tracker   = TrackerTestBuilder::aTracker()->withName('User story')->build();
         $changeset->expects(self::once())->method('getTracker')->willReturn($tracker);
 
         $date_period = $this->timeframe->buildDatePeriodWithoutWeekendForChangesetForREST(
             $artifact->getLastChangeset(),
-            UserTestBuilder::anActiveUser()->build(),
+            $user,
             new NullLogger()
         );
 
@@ -143,11 +145,13 @@ final class TimeframeNotConfiguredTest extends TestCase
 
     public function testItThrowsAnExceptionWhenInChartContext(): void
     {
+        $user = UserTestBuilder::anActiveUser()->build();
+
         $changeset = $this->createMock(\Tracker_Artifact_Changeset::class);
         $artifact  = ArtifactTestBuilder::anArtifact(1)
             ->withTitle('release_1_0')
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($user)
             ->build();
         $tracker   = TrackerTestBuilder::aTracker()->withName('User story')->build();
 
@@ -157,7 +161,7 @@ final class TimeframeNotConfiguredTest extends TestCase
 
         $this->timeframe->buildDatePeriodWithoutWeekendForChangesetChartRendering(
             $artifact->getLastChangeset(),
-            UserTestBuilder::anActiveUser()->build(),
+            $user,
             new NullLogger()
         );
     }

programming_language: PHP
filename: TimeframeWithDurationTest.php
change_type: ModificationType.MODIFY
diff: @@ -482,7 +482,7 @@ final class TimeframeWithDurationTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle('title')
             ->inTracker($this->tracker)
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();
@@ -503,7 +503,7 @@ final class TimeframeWithDurationTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle('title')
             ->inTracker($this->tracker)
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();
@@ -524,7 +524,7 @@ final class TimeframeWithDurationTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle('title')
             ->inTracker($this->tracker)
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();
@@ -540,7 +540,7 @@ final class TimeframeWithDurationTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle('title')
             ->inTracker($this->tracker)
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();

programming_language: PHP
filename: TimeframeWithEndDateTest.php
change_type: ModificationType.MODIFY
diff: @@ -482,7 +482,7 @@ final class TimeframeWithEndDateTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle('title')
             ->inTracker(TrackerTestBuilder::aTracker()->build())
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();
@@ -503,7 +503,7 @@ final class TimeframeWithEndDateTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle('title')
             ->inTracker(TrackerTestBuilder::aTracker()->build())
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();
@@ -524,7 +524,7 @@ final class TimeframeWithEndDateTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle('title')
             ->inTracker(TrackerTestBuilder::aTracker()->build())
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();
@@ -540,7 +540,7 @@ final class TimeframeWithEndDateTest extends \Tuleap\Test\PHPUnit\TestCase
             ->withTitle('title')
             ->inTracker(TrackerTestBuilder::aTracker()->build())
             ->withChangesets($changeset)
-            ->userCanView(true)
+            ->userCanView($this->user)
             ->withParent(null)
             ->isOpen(true)
             ->build();

programming_language: PHP