Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

project_loader: handle invalid unicode chars #1941

Merged
merged 6 commits into from
Feb 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
File renamed without changes.
27 changes: 27 additions & 0 deletions patches/pyyaml-support-high-codepoints.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
diff --git a/yaml/emitter.py b/yaml/emitter.py
index 34cb145..1f8ed92 100644
--- a/yaml/emitter.py
+++ b/yaml/emitter.py
@@ -698,7 +698,8 @@ class Emitter:
line_breaks = True
if not (ch == '\n' or '\x20' <= ch <= '\x7E'):
if (ch == '\x85' or '\xA0' <= ch <= '\uD7FF'
- or '\uE000' <= ch <= '\uFFFD') and ch != '\uFEFF':
+ or '\uE000' <= ch <= '\uFFFD'
+ or '\U00010000' <= ch < '\U0010ffff') and ch != '\uFEFF':
unicode_characters = True
if not self.allow_unicode:
special_characters = True
diff --git a/yaml/reader.py b/yaml/reader.py
index f70e920..5764f2d 100644
--- a/yaml/reader.py
+++ b/yaml/reader.py
@@ -134,7 +134,7 @@ class Reader(object):
self.encoding = 'utf-8'
self.update(1)

- NON_PRINTABLE = re.compile('[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD]')
+ NON_PRINTABLE = re.compile('[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010ffff]')
def check_printable(self, data):
match = self.NON_PRINTABLE.search(data)
if match:
8 changes: 5 additions & 3 deletions snap/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ apps:
command: bin/snapcraft

parts:
ctypes:
source: ctypes_override
patches:
source: patches
plugin: dump
prime:
- -ctypes_init.diff
- -pyyaml-support-high-codepoints.diff
bash-completion:
source: debian
plugin: dump
Expand Down Expand Up @@ -47,6 +48,7 @@ parts:
TRIPLET_PATH="$SNAPCRAFT_PART_INSTALL/usr/lib/$(gcc -print-multiarch)"
LIBSODIUM=$(readlink -n $TRIPLET_PATH/libsodium.so.18)
ln -s $LIBSODIUM $TRIPLET_PATH/libsodium.so
patch -d $SNAPCRAFT_PART_INSTALL/lib/python3.6/site-packages -p1 < $SNAPCRAFT_STAGE/pyyaml-support-high-codepoints.diff
after: [python, apt]
Copy link
Contributor

@kyrofa kyrofa Feb 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably want to add patches to after here. It has python which has patches in ITS after... but that will break if it ever changes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the after for python includes this, so the chain is somewhat complete; I will sort of ignore this as we are going back to stage-packages as soon as our SRUed deb gets in with the fixes for classic

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch otherwise ;-)

patchelf:
source: https://github.com/NixOS/patchelf
Expand All @@ -64,7 +66,7 @@ parts:
- -usr/include
install: |
patch $SNAPCRAFT_PART_INSTALL/usr/lib/python3.6/ctypes/__init__.py $SNAPCRAFT_STAGE/ctypes_init.diff
after: [ctypes]
after: [patches]
apt:
source: https://github.com/Debian/apt
source-type: git
Expand Down
6 changes: 6 additions & 0 deletions snapcraft/internal/project_loader/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

import jsonschema
import yaml
import yaml.reader


import snapcraft
from snapcraft.internal import common, deprecations, remote_parts, states
Expand Down Expand Up @@ -268,6 +270,10 @@ def _snapcraft_yaml_load(yaml_file):
except yaml.scanner.ScannerError as e:
raise errors.YamlValidationError('{} on line {} of {}'.format(
e.problem, e.problem_mark.line + 1, yaml_file)) from e
except yaml.reader.ReaderError as e:
raise errors.YamlValidationError(
'Invalid character {!r} at position {} of {}: {}'.format(
chr(e.character), e.position + 1, yaml_file, e.reason)) from e


def _ensure_confinement_default(yaml_data, schema):
Expand Down
46 changes: 46 additions & 0 deletions tests/integration/general/test_global_properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright (C) 2018 Canonical Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
import os

import testscenarios

from tests import integration, fixture_setup


class UnicodePropertyTestCase(testscenarios.WithScenarios,
integration.TestCase):

scenarios = [
('summary',
dict(name='foo', summary='bar💩', description='baz')),
('description',
dict(name='foo', summary='bar', description='baz💩')),
]

def test_invalid_unicode_workaround(self):
if not (os.getenv('SNAPCRAFT_FROM_SNAP', False) or
os.getenv('SNAPCRAFT_FROM_DEB', False)):
self.skipTest('The yaml unicode patch is applied to the snap '
'and python3-yaml package, but not PyYAML in PyPI')

snapcraft_yaml = fixture_setup.SnapcraftYaml(
self.path, name=self.name,
summary=self.summary, description=self.description)
snapcraft_yaml.update_part('my-part', {
'plugin': 'nil',
})
self.useFixture(snapcraft_yaml)
self.run_snapcraft('pull')
17 changes: 17 additions & 0 deletions tests/unit/project_loader/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,23 @@ def test_invalid_yaml_missing_icon(self):
self.assertThat(raised.message,
Equals("Specified icon 'icon.png' does not exist"))

def test_invalid_yaml_invalid_unicode_chars(self):
fake_logger = fixtures.FakeLogger(level=logging.ERROR)
self.useFixture(fake_logger)

self.make_snapcraft_yaml("""name: foobar
version: "1"
summary: test\uffff
description: nothing
""")
raised = self.assertRaises(
errors.YamlValidationError,
_config.Config)

self.assertThat(raised.message, Equals(
"Invalid character '\\uffff' at position 40 "
"of snap/snapcraft.yaml: special characters are not allowed"))

def test_invalid_yaml_invalid_name_chars(self):
fake_logger = fixtures.FakeLogger(level=logging.ERROR)
self.useFixture(fake_logger)
Expand Down