Merge pull request #1648 from coreos-inc/invalid-tag
Prevent invalid tags on builds
This commit is contained in:
commit
bb2edc5ac4
5 changed files with 41 additions and 5 deletions
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
20
test/test_names.py
Normal 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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Reference in a new issue