3 final class DiffusionUpdateObjectAfterCommitWorker
4 extends PhabricatorWorker
{
8 protected function getViewer() {
9 return PhabricatorUser
::getOmnipotentUser();
12 protected function doWork() {
13 $viewer = $this->getViewer();
14 $data = $this->getTaskData();
16 $commit_phid = idx($data, 'commitPHID');
18 throw new PhabricatorWorkerPermanentFailureException(
19 pht('No "commitPHID" in task data.'));
22 $commit = id(new DiffusionCommitQuery())
24 ->withPHIDs(array($commit_phid))
25 ->needIdentities(true)
28 throw new PhabricatorWorkerPermanentFailureException(
30 'Unable to load commit "%s".',
34 $object_phid = idx($data, 'objectPHID');
36 throw new PhabricatorWorkerPermanentFailureException(
37 pht('No "objectPHID" in task data.'));
40 $object = id(new PhabricatorObjectQuery())
42 ->withPHIDs(array($object_phid))
45 throw new PhabricatorWorkerPermanentFailureException(
47 'Unable to load object "%s".',
51 $properties = idx($data, 'properties', array());
52 $this->properties
= $properties;
54 if ($object instanceof ManiphestTask
) {
55 $this->updateTask($commit, $object);
56 } else if ($object instanceof DifferentialRevision
) {
57 $this->updateRevision($commit, $object);
61 protected function getUpdateProperty($key, $default = null) {
62 return idx($this->properties
, $key, $default);
65 protected function getActingPHID(PhabricatorRepositoryCommit
$commit) {
66 if ($commit->hasCommitterIdentity()) {
67 return $commit->getCommitterIdentity()->getIdentityDisplayPHID();
70 if ($commit->hasAuthorIdentity()) {
71 return $commit->getAuthorIdentity()->getIdentityDisplayPHID();
74 return id(new PhabricatorDiffusionApplication())->getPHID();
77 protected function loadActingUser($acting_phid) {
78 // If we we were able to identify an author or committer for the commit, we
79 // try to act as that user when affecting other objects, like tasks marked
82 // This helps to prevent mistakes where a user accidentally writes the
83 // wrong task IDs and affects tasks they can't see (and thus can't undo the
84 // status changes for).
86 // This is just a guard rail, not a security measure. An attacker can still
87 // forge another user's identity trivially by forging author or committer
90 // We also let commits with unrecognized authors act on any task to make
91 // behavior less confusing for new installs, and any user can craft a
92 // commit with an unrecognized author and committer.
94 $viewer = $this->getViewer();
96 $user_type = PhabricatorPeopleUserPHIDType
::TYPECONST
;
97 if (phid_get_type($acting_phid) === $user_type) {
98 $acting_user = id(new PhabricatorPeopleQuery())
100 ->withPHIDs(array($acting_phid))
110 private function updateTask(
111 PhabricatorRepositoryCommit
$commit,
112 ManiphestTask
$task) {
114 $acting_phid = $this->getActingPHID($commit);
115 $acting_user = $this->loadActingUser($acting_phid);
117 $commit_phid = $commit->getPHID();
121 $xactions[] = $this->newEdgeTransaction(
124 ManiphestTaskHasCommitEdgeType
::EDGECONST
);
126 $status = $this->getUpdateProperty('status');
128 $xactions[] = $task->getApplicationTransactionTemplate()
129 ->setTransactionType(ManiphestTaskStatusTransaction
::TRANSACTIONTYPE
)
130 ->setMetadataValue('commitPHID', $commit_phid)
131 ->setNewValue($status);
134 $content_source = $this->newContentSource();
136 $editor = $task->getApplicationTransactionEditor()
137 ->setActor($acting_user)
138 ->setActingAsPHID($acting_phid)
139 ->setContentSource($content_source)
140 ->setContinueOnNoEffect(true)
141 ->setContinueOnMissingFields(true)
142 ->addUnmentionablePHIDs(array($commit_phid));
144 $editor->applyTransactions($task, $xactions);
147 private function updateRevision(
148 PhabricatorRepositoryCommit
$commit,
149 DifferentialRevision
$revision) {
151 $acting_phid = $this->getActingPHID($commit);
152 $acting_user = $this->loadActingUser($acting_phid);
154 // See T13625. The "Acting User" is the author of the commit based on the
155 // author string, or the Diffusion application PHID if we could not
156 // identify an author.
158 // This user may not be able to view the commit or the revision, and may
159 // also be unable to make API calls. Here, we execute queries and apply
160 // transactions as the omnipotent user.
162 // It would probably be better to use the acting user everywhere here, and
163 // exit gracefully if they can't see the revision (this is how the flow
164 // on tasks works). However, without a positive indicator in the UI
165 // explaining "no revision was updated because the author of this commit
166 // can't see anything", this might be fairly confusing, and break workflows
167 // which have worked historically.
169 // This isn't, per se, a policy violation (you can't get access to anything
170 // you don't already have access to by making commits that reference
171 // revisions, even if you can't see the commits or revisions), so just
174 $viewer = $this->getViewer();
176 // Reload the revision to get the active diff, which is currently required
177 // by "updateRevisionWithCommit()".
178 $revision = id(new DifferentialRevisionQuery())
180 ->withIDs(array($revision->getID()))
181 ->needActiveDiffs(true)
186 $xactions[] = $this->newEdgeTransaction(
189 DifferentialRevisionHasCommitEdgeType
::EDGECONST
);
191 $match_data = $this->getUpdateProperty('revisionMatchData');
193 $type_close = DifferentialRevisionCloseTransaction
::TRANSACTIONTYPE
;
194 $xactions[] = $revision->getApplicationTransactionTemplate()
195 ->setTransactionType($type_close)
197 ->setMetadataValue('isCommitClose', true)
198 ->setMetadataValue('revisionMatchData', $match_data)
199 ->setMetadataValue('commitPHID', $commit->getPHID());
201 $extraction_engine = id(new DifferentialDiffExtractionEngine())
203 ->setAuthorPHID($acting_phid);
205 $content_source = $this->newContentSource();
207 $extraction_engine->updateRevisionWithCommit(
214 private function newEdgeTransaction(
216 PhabricatorRepositoryCommit
$commit,
219 $commit_phid = $commit->getPHID();
221 return $object->getApplicationTransactionTemplate()
222 ->setTransactionType(PhabricatorTransactions
::TYPE_EDGE
)
223 ->setMetadataValue('edge:type', $edge_type)
227 $commit_phid => $commit_phid,