More updates to stop using dev or alpha or beta versions.
[yaffs-website] / web / modules / contrib / security_review / security_review.drush.inc
1 <?php
2
3 /**
4  * @file
5  * Drush commands for Security Review module.
6  */
7
8 use Drupal\security_review\CheckResult;
9
10 /**
11  * Implements hook_drush_command().
12  */
13 function security_review_drush_command() {
14   $items = [];
15
16   $items['security-review'] = [
17     'aliases' => ['secrev'],
18     'callback' => 'security_review_drush',
19     'description' => "Run the Security Review checklist",
20     'options' => [
21       'store' => 'Write results to the database',
22       'log' => 'Log results of each check to watchdog, defaults to off',
23       'lastrun' => 'Do not run the checklist, just print last results',
24       'check' => 'Comma-separated list of specified checks to run. See README.txt for list of options',
25       'skip' => 'Comma-separated list of specified checks not to run. This takes precedence over --check.',
26       'short' => "Short result messages instead of full description (e.g. 'Text formats')",
27       'results' => 'Show the incorrect settings for failed checks',
28     ],
29     'examples' => [
30       'secrev' => 'Run the checklist and output the results',
31       'secrev --store' => 'Run the checklist, store, and output the results',
32       'secrev --lastrun' => 'Output the stored results from the last run of the checklist',
33     ],
34     'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
35     'outputformat' => [
36       'default' => 'table',
37       'pipe-format' => 'csv',
38       'fields-default' => ['message', 'status'],
39       'field-labels' => [
40         'message' => 'Message',
41         'status' => 'Status',
42         'findings' => 'Findings',
43       ],
44       'output-data-type' => 'format-table',
45     ],
46   ];
47
48   return $items;
49 }
50
51 /**
52  * Implements hook_drush_help().
53  */
54 function security_review_drush_help($section) {
55   switch ($section) {
56     case 'drush:security-review':
57       return dt("Run configuration security checks on your Drupal site.");
58   }
59 }
60
61 /**
62  * Runs a checklist and displays results.
63  */
64 function security_review_drush() {
65   /** @var \Drupal\security_review\SecurityReview $security_review */
66   $security_review = Drupal::service('security_review');
67
68   /** @var \Drupal\security_review\Checklist $checklist */
69   $checklist = Drupal::service('security_review.checklist');
70
71   $store = drush_get_option('store');
72   $log = drush_get_option('log');
73   $last_run = drush_get_option('lastrun');
74   $run_checks = drush_get_option_list('check');
75   $skip_checks = drush_get_option_list('skip');
76   $short_titles = drush_get_option('short');
77   $show_findings = drush_get_option('results');
78
79   // Set temporary logging.
80   $log = in_array($log, [TRUE, 1, 'TRUE']);
81   $security_review->setLogging($log, TRUE);
82
83   if (!empty($short_titles)) {
84     $short_titles = TRUE;
85   }
86   else {
87     $short_titles = FALSE;
88   }
89
90   $results = [];
91   if (!$last_run) {
92     // Do a normal security review run.
93     /** @var \Drupal\security_review\Check[] $checks */
94     $checks = [];
95     /** @var \Drupal\security_review\Check[] $to_skip */
96     $to_skip = [];
97
98     // Fill the $checks array.
99     if (!empty($run_checks)) {
100       // Get explicitly specified checks.
101       foreach ($run_checks as $check) {
102         $checks[] = _security_review_drush_get_check($check);
103       }
104     }
105     else {
106       // Get the whole checklist.
107       $checks = $checklist->getChecks();
108     }
109
110     // Mark checks listed after --skip for removal.
111     if (!empty($skip_checks)) {
112       foreach ($skip_checks as $skip_check) {
113         $to_skip[] = _security_review_drush_get_check($skip_check);
114       }
115     }
116
117     // If storing, mark skipped checks for removal.
118     if ($store) {
119       foreach ($checks as $check) {
120         if ($check->isSkipped()) {
121           $to_skip[] = $check;
122         }
123       }
124     }
125
126     // Remove the skipped checks from $checks.
127     foreach ($to_skip as $skip_check) {
128       foreach ($checks as $key => $check) {
129         if ($check->id() == $skip_check->id()) {
130           unset($checks[$key]);
131         }
132       }
133     }
134
135     // If $checks is empty at this point, return with an error.
136     if (empty($checks)) {
137       return drush_set_error('EMPTY_CHECKLIST', dt("No checks to run. Run 'drush help secrev' for option use or consult the drush section of API.txt for further help."));
138     }
139
140     // Run the checks.
141     $results = $checklist->runChecks($checks, TRUE);
142
143     // Store the results.
144     if ($store) {
145       $checklist->storeResults($results);
146     }
147   }
148   else {
149     // Show the latest stored results.
150     foreach ($checklist->getChecks() as $check) {
151       $last_result = $check->lastResult($show_findings);
152       if ($last_result instanceof CheckResult) {
153         $results[] = $last_result;
154       }
155     }
156   }
157
158   return _security_review_drush_format_results($results, $short_titles, $show_findings);
159 }
160
161 /**
162  * Helper function for parsing input check name strings.
163  *
164  * @param string $check_name
165  *   The check to get.
166  *
167  * @return \Drupal\security_review\Check|null
168  *   The found Check.
169  */
170 function _security_review_drush_get_check($check_name) {
171   /** @var \Drupal\security_review\Checklist $checklist */
172   $checklist = Drupal::service('security_review.checklist');
173
174   // Default namespace is Security Review.
175   $namespace = 'security_review';
176   $title = $check_name;
177
178   // Set namespace and title if explicitly defined.
179   if (strpos($check_name, ':') !== FALSE) {
180     list($namespace, $title) = explode(':', $check_name);
181   }
182
183   // Return the found check if any.
184   return $checklist->getCheck($namespace, $title);
185 }
186
187 /**
188  * Helper function to compile Security Review results.
189  *
190  * @param \Drupal\security_review\CheckResult[] $results
191  *   An array of CheckResults.
192  * @param bool $short_titles
193  *   Whether to use short message (check title) or full check success or failure
194  *   message.
195  * @param bool $show_findings
196  *   Whether to print failed check results.
197  *
198  * @return array
199  *   The results of the security review checks.
200  */
201 function _security_review_drush_format_results(array $results, $short_titles = FALSE, $show_findings = FALSE) {
202   $output = [];
203
204   foreach ($results as $result) {
205     if ($result instanceof CheckResult) {
206       if (!$result->isVisible()) {
207         // Continue with the next check.
208         continue;
209       }
210
211       $check = $result->check();
212       $message = $short_titles ? $check->getTitle() : $result->resultMessage();
213       $status = 'notice';
214
215       // Set log level according to check result.
216       switch ($result->result()) {
217         case CheckResult::SUCCESS:
218           $status = 'success';
219           break;
220
221         case CheckResult::FAIL:
222           $status = 'failed';
223           break;
224
225         case CheckResult::WARN:
226           $status = 'warning';
227           break;
228
229         case CheckResult::INFO:
230           $status = 'info';
231           break;
232       }
233
234       // Attach findings.
235       if ($show_findings) {
236         $findings = trim($result->check()->evaluatePlain($result));
237         if ($findings != '') {
238           $message .= "\n" . $findings;
239         }
240       }
241
242       $output[$check->id()] = [
243         'message' => (string) $message,
244         'status' => $status,
245         'findings' => $result->findings(),
246       ];
247     }
248   }
249
250   return $output;
251 }