Updated: Comment #16
Problem/Motivation
.info.yml parsing is fragile and error reporting does not help the user fix the problem. The installer also does not produce helpful error messages.
Steps to reproduce
- Edit shortcut.info.yml to have invalid YAML. For example, change
dependencies:
todependencies::::,
- If Drupal is not installed go to the installer
- Or go to admin/modules if it is
Proposed resolution
- Create an InfoParser class that throws InfoParserExceptions that detail the filename of the info.yml that is causing the issue
- Validate that the info.yml contains a name and type key
- Create an info_parser service
- Add tests for all logic in the class
Remaining tasks
Reviews
User interface changes
None
API changes
drupal_parse_info_file()
is deprecated.
Related Issues
Original report by @cweagans
Simply downloading a module that has a malformed modulename.info.yml file, and placing it in a module directory, causes this Exception: http://monosnap.com/image/6j1lRa8axNlxLRGymg3JcfvrX
Here's the modulename.info.yml file that caused the error:
name: Node access user reference
description: Gives content access permissions to users for content that references the users with User reference or Entity reference.
core = 8.x # <-- error due to muscle memory
dependencies:
- entityreference
I'm not anywhere I can roll a patch right now, but I'm thinking something like this:
function drupal_parse_info_file($filename) {
static $info = array();
if (!isset($info[$filename])) {
if (!file_exists($filename)) {
$info[$filename] = array();
}
else {
$parser = new Parser();
try {
$info[$filename] = $parser->parse(file_get_contents($filename));
}
catch (Exception $e) {
drupal_set_message(t('Malformed module metadata in %name', array('%name' => $filename)), 'error');
}
if (isset($info[$filename]['version']) && $info[$filename]['version'] === 'VERSION') {
$info[$filename]['version'] = VERSION;
}
}
}
return $info[$filename];
}
Comment | File | Size | Author |
---|---|---|---|
#21 | interdiff-19-21.txt | 2.71 KB | alexpott |
#21 | 2057259.21.patch | 25.35 KB | alexpott |
#19 | 2057259.19.patch | 25.14 KB | swentel |
#19 | interdiff.txt | 3.08 KB | swentel |
#16 | infoparserfixed.png | 83.51 KB | alexpott |
Comments
Comment #1
cweagansAnd I think this is major, if not critical, since a ton of things break in this scenario. We need to handle this nicely.
Comment #2
dlu CreditAttribution: dlu commentedMoved to profile.module per #2050763-16: Refine "base system" component (notes on refactoring of "base system" category here: https://docs.google.com/a/acquia.com/spreadsheet/ccc?key=0AusehVccVSq2dF...).
Comment #3
webchickHm. This definitely isn't about profile.module. Not sure where else to put it than base system.
Comment #4
swentel CreditAttribution: swentel commentedIf you can download such a module, you are dealing with a maintainer who pushed something that doesn't even work on his local machine then ...
Sure, it's annoying, but I fail to see why this would be major, other than a more friendly message - which already does a good job of indicating where something goes wrong.
(note, I hardly even see this as a bug: wrong format, you get an exception, done. Just like you get an PHP error when you type something wrong in your module file.)
Comment #5
cweagansWell, yes - that's obvious to you and I, but to a non-technical new user of Drupal who downloads a module that blows up their site on pretty much every page...well, this is not a good situation and they don't have any way of knowing that it's because they downloaded the module.
PHP errors in a module are one thing - they require the module to be enabled. The reason for this being major (if not, critical) is that the module doesn't even have to be enabled to break things. Plus, https://drupal.org/node/45111 specifically calls out this situation as being a "Major" ("An example would be a PHP error which is only triggered under rare circumstances or which affects only a small percentage of all users.")
I'm tempted to upgrade this to Critical, as this definitely fits the description of "Critical bugs either render a system unusable", but I don't want to bicker over metadata.
Instead, I'll just provide a patch and a test. Assigning to myself to work on it.
Comment #6
cweagansEh, the malformed yaml test seems not-so-great, but I'm not sure how else to approach it.
Comment #7
cweagansNow with one less "use"!
Comment #8
cweagans...this time, for reals.
Comment #9
swentel CreditAttribution: swentel commentedRight, still not convinced, but I won't fight it over as it's an easy 'fix'. :)
With that, maybe only one nitpick/question:
The previous exception contained the line on which it failed, should we try and see whether $exception contains that or not ?
Comment #10
webchickFWIW, given that a hapless end user can screw their entire site without even enabling a faulty module but just having it in the file tree, I'm in favour of doing some hardening around this. It's properly categorized as a "major" issue, though; we could certainly ship without it.
I wonder though if this check is in the proper place, or if it should be moved further up the chain to apply more generally to YAML parse faults. It seems like a = instead of a : shouldn't WSOD your site, no matter where it's coming from.
Comment #11
cweagansI think that's fair. There's this other issue about adding a YAML wrapper (so that we can default to libYAML when it's available): #1920902: Add a Drupal Yaml wrapper so we can default to PECL Yaml component if it is available. That might be a good place to put this hardening, however, I'm not sure that there are any other circumstances where malformed YAML can WSOD your site simply by being present in the file tree. Other scenarios where that might happen are very heavily developer-oriented (writing your services.yml or config yml files). This would be the same situation as writing bad PHP code - things will break.
I can do some testing with other YAML files to see if I can majorly break something with bad YAML syntax, though.
swentel, good call - I'll pick that up in the next patch.
Comment #12
dlu CreditAttribution: dlu commentedHowever if there is a way to catch where the problem is and pass it along to the developer (or any other interested parties) it sure would be nice. Catching the problem early on before it has a chance to break something means that we don't get surprised when we discover (or create) another nasty path.
Comment #13
xjmCrossposting: #2116377: Make .info.yml syntax errors tell you where they come from; also non-required modules shouldn't break the installer
Comment #14
cweagansNot sure how I missed this one. I don't do core anymore.
Comment #15
alexpottI think it is correct that a malformed info.yml file creates a fatal error as we have no idea what to do at this point - should the module still be enabled - what about data integrity etc. So I think we should refocus this issue to instead provide a helpful error message when this occurs.
The patch attached does the following:
This patch also fixes #2116377: Make .info.yml syntax errors tell you where they come from; also non-required modules shouldn't break the installer so that the installer also reports a decent error message.
Comment #16
alexpottBefore this patch if you have a broken .info.yml the installer would display an error like this:
With this patch:
So now at least the user can see where the error is occurring and has a chance of fixing it.
Comment #17
tim.plunkettLooks great! Just some weird spacing issues.
Double space before {
Space between parse and (
Extra blank line
empty() could be replaced with !
Missing blank line
Missing newline
Comment #19
swentel CreditAttribution: swentel commentedComment #20
dawehnerWe could directly go to String::format
This should be the full namespace, sorry this feels so nitpicky.
Just wondering, is there a reason we don't have the parser as service and just inject it directly?
I know this is out of scope but theoretically we also use it for profile .info.yml files.
I kind of like when people describe when their exceptions in thrown.
Good catch!
Is there a real reason why we don't write a real unit test already?
Comment #21
alexpottComment #22
tim.plunkettThis makes me twitch so bad. I guess it works as desired :)
I do this all the time, so I'm glad we're handling it better now.
This is great, the unit test is sound, RTBC!
Comment #23
webchickThis is the only thing I'm not crazy about. We're actually calling this in like 7 or 8 places. Seems like it probably belongs on the Drupal class as a top-level method. But since this is neither the first nor last place that we're doing this, it doesn't make sense to hold up this lovely, lovely patch on this.
AWESOME WORK folks! The before/after screenshots in #16 make my heart sing. :)
Committed and pushed to 8.x. Thanks!
Comment #23.0
webchickUpdated issue summary.