PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/application/migrations/030200/Workflow.php

https://bitbucket.org/openfisma-ondemand/openfisma
PHP | 310 lines | 243 code | 16 blank | 51 comment | 4 complexity | 908eb368d96b164695f02d001e61667e MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, GPL-3.0, Apache-2.0, EPL-1.0
  1. <?php
  2. /**
  3. * Copyright (c) 2013 Endeavor Systems, Inc.
  4. *
  5. * This file is part of OpenFISMA.
  6. *
  7. * OpenFISMA is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
  8. * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
  9. * version.
  10. *
  11. * OpenFISMA is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  12. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  13. * details.
  14. *
  15. * You should have received a copy of the GNU General Public License along with OpenFISMA. If not, see
  16. * {@link http://www.gnu.org/licenses/}.
  17. */
  18. /**
  19. * @author Duy K. Bui <duy.bui@endeavorsystems.com>
  20. * @copyright (c) Endeavor Systems, Inc. 2013 {@link http://www.endeavorsystems.com}
  21. * @license http://www.openfisma.org/content/license GPLv3
  22. * @package Migration
  23. */
  24. class Application_Migration_030200_Workflow extends Fisma_Migration_Abstract
  25. {
  26. /**
  27. * Migrate.
  28. */
  29. public function migrate()
  30. {
  31. $helper = $this->getHelper();
  32. $this->message('Drop foreign keys');
  33. $helper->dropForeignKeys('finding', 'finding_currentevaluationid_evaluation_id');
  34. $helper->dropForeignKeys('evaluation', 'evaluation_nextid_evaluation_id');
  35. $helper->dropForeignKeys('finding_evaluation', 'finding_evaluation_evaluationid_evaluation_id');
  36. $this->message('Migrating Workflow, WorkflowStep');
  37. $this->message('Add tables');
  38. $helper->createTable(
  39. 'workflow',
  40. array(
  41. 'id' => 'bigint(20) NOT NULL AUTO_INCREMENT',
  42. 'createdts' => 'datetime NOT NULL',
  43. 'modifiedts' => 'datetime NOT NULL',
  44. 'name' => 'varchar(255)',
  45. 'description' => 'text',
  46. 'isdefault' => 'tinyint(1) NOT NULL DEFAULT 0',
  47. 'module' => "enum('finding','incident','vulnerability') NOT NULL",
  48. 'creatorid' => 'bigint(20)'
  49. ),
  50. 'id'
  51. );
  52. $helper->createTable(
  53. 'workflow_step',
  54. array(
  55. 'id' => 'bigint(20) NOT NULL AUTO_INCREMENT',
  56. 'createdts' => 'datetime NOT NULL',
  57. 'modifiedts' => 'datetime NOT NULL',
  58. 'cardinality' => 'bigint(20)',
  59. 'name' => 'varchar(255)',
  60. 'label' => 'varchar(255)',
  61. 'description' => 'text',
  62. 'isresolved' => 'tinyint(1) NOT NULL DEFAULT 0',
  63. 'allottedtime' => "enum('unlimited','days','ecd','custom') DEFAULT 'unlimited'",
  64. 'allotteddays' => 'bigint(20)',
  65. 'autotransition' => 'tinyint(1) NOT NULL DEFAULT 0',
  66. 'autotransitiondestination' => 'bigint(20)',
  67. 'attachmenteditable' => 'tinyint(1) NOT NULL DEFAULT 1',
  68. 'prerequisites' => 'text',
  69. 'restrictedfields' => 'text',
  70. 'transitions' => 'text',
  71. 'workflowid' => 'bigint(20)'
  72. ),
  73. 'id'
  74. );
  75. //Add foreign key
  76. $helper->addForeignKey('workflow', 'creatorid', 'user', 'id');
  77. $helper->addForeignKey('workflow_step', 'workflowid', 'workflow', 'id');
  78. $this->message('Create default records');
  79. $workflows = $this->_getWorkflowArray();
  80. foreach ($workflows as $workflow) {
  81. $helper->insert('workflow', $workflow);
  82. }
  83. $workflowSteps = $this->_getWorkflowStepArray();
  84. foreach ($workflowSteps as $workflowStep) {
  85. $helper->insert('workflow_step', $workflowStep);
  86. }
  87. //WorkflowStepUser
  88. //Create table
  89. $helper->createTable(
  90. 'workflow_step_user',
  91. array(
  92. 'userid' => 'bigint(20) NOT NULL DEFAULT 0',
  93. 'stepid' => 'bigint(20) NOT NULL DEFAULT 0'
  94. ),
  95. array('userid', 'stepid')
  96. );
  97. //Add foreign keys
  98. $helper->addForeignKey('workflow_step_user', 'stepid', 'workflow_step', 'id');
  99. $helper->addForeignKey('workflow_step_user', 'userid', 'user', 'id');
  100. $helper->addIndex('workflow_step_user', 'stepid', 'workflow_step_user_stepid_workflow_step_id');
  101. $helper->dropIndexes('workflow_step_user', array('stepid_idx', 'userid_idx'));
  102. $this->message('Migrating Finding table');
  103. //Add isResolved, completedSteps, currentStepId
  104. $helper->addColumn('finding', 'isresolved', 'tinyint(1) NOT NULL DEFAULT 0', 'legacyfindingkey');
  105. $helper->addColumn('finding', 'completedsteps', 'text', 'isresolved');
  106. $helper->addColumn('finding', 'currentstepid', 'bigint(20) DEFAULT NULL', 'completedsteps');
  107. //Remove actualCompletionDate, cvssBaseScore, cvssVector
  108. $helper->dropColumns('finding', array('actualcompletiondate', 'cvssbasescore', 'cvssvector'));
  109. //if status = CLOSED set isresolved = 1, check type and send to destination step
  110. $helper->update(
  111. 'finding',
  112. array('isresolved' => 1, 'currentstepid' => 14),
  113. array('status' => 'CLOSED', 'type' => 'CAP')
  114. );
  115. $helper->update(
  116. 'finding',
  117. array('isresolved' => 1, 'currentstepid' => 18),
  118. array('status' => 'CLOSED', 'type' => 'FP')
  119. );
  120. $helper->update(
  121. 'finding',
  122. array('isresolved' => 1, 'currentstepid' => 16),
  123. array('status' => 'CLOSED', 'type' => 'AR')
  124. );
  125. //save old evaluations => completedsteps
  126. $evaluations = $helper->query(
  127. "SELECT * from finding_evaluation fe " .
  128. "INNER JOIN evaluation e on fe.evaluationid = e.id " .
  129. "ORDER BY fe.findingid, fe.createdts"
  130. );
  131. $findingId = 0;
  132. $completedSteps = array();
  133. foreach ($evaluations as $evaluation) {
  134. if ($findingId > 0 && $evaluation->findingid != $findingId) {
  135. $helper->exec(
  136. "UPDATE finding SET completedsteps = ? WHERE id = ?",
  137. array(serialize($completedSteps), $findingId)
  138. );
  139. $completedSteps = array();
  140. }
  141. $findingId = $evaluation->findingid;
  142. $completedSteps[] = array(
  143. 'workflow' => array(
  144. 'name' => 'Legacy',
  145. 'description' => 'Migrated finding workflow'
  146. ),
  147. 'step' => array(
  148. 'name' => $evaluation->name,
  149. 'label' => $evaluation->nickname,
  150. 'description' => $evaluation->description
  151. ),
  152. 'transitionName' => $evaluation->decision,
  153. 'comment' => $evaluation->comment,
  154. 'expirationDate' => '0',
  155. 'userId' => $evaluation->userid,
  156. 'timestamp' => $evaluation->createdts
  157. );
  158. }
  159. if (!empty($completedSteps)) {
  160. $helper->exec(
  161. "UPDATE finding SET completedsteps = ? WHERE id = ?",
  162. array(serialize($completedSteps), $findingId)
  163. );
  164. $completedSteps = array();
  165. }
  166. //send NEW/DRAFT, MSA, EN, EA to Remediation
  167. $helper->update(
  168. 'finding',
  169. array('currentstepid' => 10),
  170. array('status' => 'NEW')
  171. );
  172. $helper->update(
  173. 'finding',
  174. array('currentstepid' => 10),
  175. array('status' => 'DRAFT')
  176. );
  177. $helper->update(
  178. 'finding',
  179. array('currentstepid' => 11),
  180. array('status' => 'MSA')
  181. );
  182. $helper->update(
  183. 'finding',
  184. array('currentstepid' => 12),
  185. array('status' => 'EN')
  186. );
  187. $helper->update(
  188. 'finding',
  189. array('currentstepid' => 13),
  190. array('status' => 'EA')
  191. );
  192. //send everything without type to Acceptance (this will override some NEW/DRAFT findings above)
  193. $helper->update(
  194. 'finding',
  195. array('currentstepid' => 5),
  196. array('type' => 'NONE')
  197. );
  198. //Remove type, status, denormalizedStatus, currentEvaluationId
  199. $helper->dropColumns('finding', array('type', 'status', 'denormalizedstatus', 'currentevaluationid'));
  200. //Add foreign key
  201. $helper->addForeignKey('finding', 'currentstepid', 'workflow_step', 'id');
  202. $this->message('Remove Evaluation, Comment, FindingEvaluation');
  203. $helper->dropTable('comment');
  204. $helper->dropTable('evaluation');
  205. $helper->dropTable('finding_evaluation');
  206. $this->message('Migrating Events');
  207. //Remove all with category evaluation
  208. //Remove finding MITIGATION_APPROVED, MITIGATION_REJECTED, EVIDENCE_REJECTED
  209. $helper->exec(
  210. "DELETE from `event` WHERE " .
  211. "`category` = 'evaluation' OR " .
  212. "`name` like 'MITIGATION_%' OR " .
  213. "`name` like 'EVIDENCE_%'" .
  214. ";"
  215. );
  216. //Add WORKFLOW_COMPLETED
  217. $newEventId = $helper->insert('event', array(
  218. 'defaultActive' => true,
  219. 'name' => 'WORKFLOW_COMPLETED',
  220. 'description' => 'new items arrive in a workflow step I watch',
  221. 'category' => 'user'
  222. ));
  223. $helper->exec(
  224. "INSERT into `user_event` (`userid`, `eventid`) (" .
  225. "SELECT id, {$newEventId} from `user` WHERE `deleted_at` IS NULL" .
  226. ");"
  227. );
  228. //Privilege (done in Privilege.php)
  229. //Add {resource:finding, action:update}, {resource:workflow, action:manage}
  230. //delete from role_privilege
  231. //Remove {resource:finding, action:[update_*|upload_evidence|mitigation_*|evidence_*]}
  232. //Remove {resource:evaluation}
  233. //Remove {resource:vulnerability_resolution}
  234. $this->message('Migrating Vulnerability table');
  235. //Add isResolved, completedSteps, currentStepId, nextDueDate
  236. $helper->addColumn('vulnerability', 'isresolved', 'tinyint(1) NOT NULL DEFAULT 0', 'closedts');
  237. $helper->addColumn('vulnerability', 'completedsteps', 'text', 'pocid');
  238. $helper->addColumn('vulnerability', 'currentstepid', 'bigint(20) DEFAULT NULL', 'completedsteps');
  239. $helper->addColumn('vulnerability', 'nextduedate', 'date DEFAULT NULL', 'currentstepid');
  240. //if status != OPEN set isresolved = 1, check status and send to destination step
  241. $helper->update(
  242. 'vulnerability',
  243. array('isresolved' => 1, 'currentstepid' => 2),
  244. array('status' => 'WONTFIX')
  245. );
  246. $helper->update(
  247. 'vulnerability',
  248. array('isresolved' => 1, 'currentstepid' => 4),
  249. array('status' => 'FIXED')
  250. );
  251. $helper->update(
  252. 'vulnerability',
  253. array('currentstepid' => 1),
  254. array('status' => 'OPEN')
  255. );
  256. //Remove columns
  257. $helper->dropForeignKeys('vulnerability', 'vulnerability_resolutionid_vulnerability_resolution_id');
  258. $helper->dropColumn('vulnerability', 'status');
  259. $helper->dropColumn('vulnerability', 'resolutionid');
  260. $helper->dropTable('vulnerability_resolution');
  261. //Add foreign key
  262. $helper->addForeignKey('vulnerability', 'currentstepid', 'workflow_step', 'id');
  263. $this->message('Updating Configuration');
  264. //Add workflowTransition backgroundTask enabled 1, number 1, unit day, time 02:00:00
  265. $bt = $helper->query("SELECT backgroundtasks from configuration");
  266. $bt = unserialize($bt[0]->backgroundtasks);
  267. $bt['workflowTransition'] = array(
  268. 'enabled' => '1',
  269. 'number' => '1',
  270. 'unit' => 'day',
  271. 'time' => '02:00:00'
  272. );
  273. $helper->update(
  274. 'configuration',
  275. array('backgroundtasks' => serialize($bt))
  276. );
  277. }
  278. private function _getWorkflowArray()
  279. {
  280. $now = self::now();
  281. $rootId = $this->getHelper()->query("SELECT id from user where username = 'root'");
  282. $rootId = $rootId[0]->id;
  283. $workflow = array();
  284. include(realpath(dirname(__FILE__) . '/workflow.inc'));
  285. return $workflow;
  286. }
  287. private function _getWorkflowStepArray()
  288. {
  289. $now = self::now();
  290. $workflowStep = array();
  291. include(realpath(dirname(__FILE__) . '/workflow_step.inc'));
  292. return $workflowStep;
  293. }
  294. }