Merge pull request #1648 from coreos-inc/invalid-tag

Prevent invalid tags on builds
This commit is contained in:
josephschorr 2016-07-26 11:47:32 -07:00 committed by GitHub
commit bb2edc5ac4
5 changed files with 41 additions and 5 deletions

View file

@ -8,6 +8,7 @@ from data import model
from data.database import db from data.database import db
from auth.auth_context import get_authenticated_user from auth.auth_context import get_authenticated_user
from endpoints.notificationhelper import spawn_notification from endpoints.notificationhelper import spawn_notification
from util.names import escape_tag
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -160,7 +161,7 @@ class PreparedBuild(object):
if self._tags: if self._tags:
raise Exception('Property tags already set') raise Exception('Property tags already set')
self._tags = list(value) self._tags = [escape_tag(tag, default='latest') for tag in value]
@property @property
def build_name(self): def build_name(self):

View file

@ -24,6 +24,7 @@ from endpoints.v2.errors import (BlobUnknown, ManifestInvalid, ManifestUnknown,
from endpoints.trackhelper import track_and_log from endpoints.trackhelper import track_and_log
from endpoints.notificationhelper import spawn_notification from endpoints.notificationhelper import spawn_notification
from util.registry.replication import queue_storage_replication from util.registry.replication import queue_storage_replication
from util.names import VALID_TAG_PATTERN
from digest import digest_tools from digest import digest_tools
from data import model from data import model
from data.database import RepositoryTag from data.database import RepositoryTag
@ -31,8 +32,6 @@ from data.database import RepositoryTag
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
VALID_TAG_PATTERN = r'[\w][\w.-]{0,127}'
BASE_MANIFEST_ROUTE = '/<repopath:repository>/manifests/<regex("{0}"):manifest_ref>' BASE_MANIFEST_ROUTE = '/<repopath:repository>/manifests/<regex("{0}"):manifest_ref>'
MANIFEST_DIGEST_ROUTE = BASE_MANIFEST_ROUTE.format(digest_tools.DIGEST_PATTERN) MANIFEST_DIGEST_ROUTE = BASE_MANIFEST_ROUTE.format(digest_tools.DIGEST_PATTERN)
MANIFEST_TAGNAME_ROUTE = BASE_MANIFEST_ROUTE.format(VALID_TAG_PATTERN) MANIFEST_TAGNAME_ROUTE = BASE_MANIFEST_ROUTE.format(VALID_TAG_PATTERN)

View file

@ -50,3 +50,8 @@ class TestDigestPath(unittest.TestCase):
for digest, path in examples: for digest, path in examples:
self.assertEquals(content_path(digest), path) self.assertEquals(content_path(digest), path)
if __name__ == '__main__':
unittest.main()

20
test/test_names.py Normal file
View file

@ -0,0 +1,20 @@
import unittest
from util.names import escape_tag
class TestEscapeTag(unittest.TestCase):
def assertTag(self, input_tag, expected):
self.assertEquals(expected, escape_tag(input_tag))
def test_basic_tag(self):
self.assertTag('latest', 'latest')
self.assertTag('latest124', 'latest124')
self.assertTag('5de1e98d', '5de1e98d')
def test_invalid_tag(self):
self.assertTag('detailed_view#61', 'detailed_view_61')
self.assertTag('-detailed_view#61', '_detailed_view_61')
if __name__ == '__main__':
unittest.main()

View file

@ -1,15 +1,26 @@
import urllib import urllib
import re import re
from functools import wraps
from uuid import uuid4 from uuid import uuid4
REPOSITORY_NAME_REGEX = re.compile(r'^[\.a-zA-Z0-9_-]+$') REPOSITORY_NAME_REGEX = re.compile(r'^[\.a-zA-Z0-9_-]+$')
TAG_REGEX = re.compile(r'^[\w][\w\.-]{0,127}$') VALID_TAG_PATTERN = r'[\w][\w.-]{0,127}'
FULL_TAG_PATTERN = r'^[\w][\w.-]{0,127}$'
TAG_REGEX = re.compile(FULL_TAG_PATTERN)
TAG_ERROR = ('Invalid tag: must match [A-Za-z0-9_.-], NOT start with "." or "-", ' TAG_ERROR = ('Invalid tag: must match [A-Za-z0-9_.-], NOT start with "." or "-", '
'and can contain 1-128 characters') 'and can contain 1-128 characters')
def escape_tag(tag, default='latest'):
""" Escapes a Docker tag, ensuring it matches the tag regular expression. """
if not tag:
return default
tag = re.sub(r'^[^\w]', '_', tag)
tag = re.sub(r'[^\w\.-]', '_', tag)
return tag[0:127]
def parse_namespace_repository(repository, library_namespace, include_tag=False): def parse_namespace_repository(repository, library_namespace, include_tag=False):
parts = repository.rstrip('/').split('/', 1) parts = repository.rstrip('/').split('/', 1)