diff --git a/data/interfaces/verbs.py b/data/interfaces/verbs.py
index f5758352e..5f1e02c70 100644
--- a/data/interfaces/verbs.py
+++ b/data/interfaces/verbs.py
@@ -9,6 +9,19 @@ from data import model
 from image.docker.v1 import DockerV1Metadata
 
 
+class Repository(namedtuple('Repository', ['id', 'name', 'namespace_name', 'description',
+                                           'is_public', 'kind'])):
+  """
+  Repository represents a namespaced collection of tags.
+  :type id: int
+  :type name: string
+  :type namespace_name: string
+  :type description: string
+  :type is_public: bool
+  :type kind: string
+  """
+
+
 class DerivedImage(namedtuple('DerivedImage', ['ref', 'blob', 'internal_source_image_db_id'])):
   """
   DerivedImage represents a user-facing alias for an image which was derived from another image.
@@ -43,9 +56,10 @@ class VerbsDataInterface(object):
   verbs.
   """
   @abstractmethod
-  def repository_is_public(self, namespace_name, repo_name):
+  def get_repository(self, namespace_name, repo_name):
     """
-    Returns a boolean for whether the repository with the given name and namespace is public.
+    Returns a repository tuple for the repository with the given name under the given namespace.
+    Returns None if no such repository was found.
     """
     pass
 
@@ -144,8 +158,8 @@ class PreOCIModel(VerbsDataInterface):
   before it was changed to support the OCI specification.
   """
 
-  def repository_is_public(self, namespace_name, repo_name):
-    return model.repository.repository_is_public(namespace_name, repo_name)
+  def get_repository(self, namespace_name, repo_name):
+    return _repository_for_repo(model.repository.get_repository(namespace_name, repo_name))
 
   def get_manifest_layers_with_blobs(self, repo_image):
     repo_image_record = model.image.get_image_by_id(repo_image.repository.namespace_name,
@@ -320,3 +334,14 @@ def _blob(blob_record):
     uploading=blob_record.uploading,
     locations=locations,
   )
+
+def _repository_for_repo(repo):
+  """ Returns a Repository object representing the Pre-OCI data model repo instance given. """
+  return Repository(
+    id=repo.id,
+    name=repo.name,
+    namespace_name=repo.namespace_user.username,
+    description=repo.description,
+    is_public=model.repository.is_repository_public(repo),
+    kind=model.repository.get_repo_kind_name(repo),
+  )
diff --git a/endpoints/verbs/__init__.py b/endpoints/verbs/__init__.py
index ff2c28f76..16453ed08 100644
--- a/endpoints/verbs/__init__.py
+++ b/endpoints/verbs/__init__.py
@@ -154,29 +154,35 @@ def _torrent_repo_verb(repo_image, tag, verb, **kwargs):
     abort(406)
 
   # Return the torrent.
-  public_repo = model.repository_is_public(repo_image.repository.namespace_name,
-                                           repo_image.repository.name)
-  torrent = _torrent_for_blob(derived_image.blob, public_repo)
+  repo = model.get_repository(repo_image.repository.namespace_name,
+                              repo_image.repository.name)
+  repo_is_public = repo is not None and repo.is_public
+  torrent = _torrent_for_blob(derived_image.blob, repo_is_public)
 
   # Log the action.
   track_and_log('repo_verb', repo_image.repository, tag=tag, verb=verb, torrent=True, **kwargs)
   return torrent
 
 
-def _verify_repo_verb(_, namespace, repository, tag, verb, checker=None):
-  permission = ReadRepositoryPermission(namespace, repository)
-  if not permission.can() and not model.repository_is_public(namespace, repository):
+def _verify_repo_verb(_, namespace, repo_name, tag, verb, checker=None):
+  permission = ReadRepositoryPermission(namespace, repo_name)
+  repo = model.get_repository(namespace, repo_name)
+  repo_is_public = repo is not None and repo.is_public
+  if not permission.can() and not repo_is_public:
     abort(403)
 
   # Lookup the requested tag.
-  tag_image = model.get_tag_image(namespace, repository, tag)
+  tag_image = model.get_tag_image(namespace, repo_name, tag)
   if tag_image is None:
     abort(404)
 
+  if repo.kind != 'image':
+    abort(405)
+
   # If there is a data checker, call it first.
   if checker is not None:
     if not checker(tag_image):
-      logger.debug('Check mismatch on %s/%s:%s, verb %s', namespace, repository, tag, verb)
+      logger.debug('Check mismatch on %s/%s:%s, verb %s', namespace, repo_name, tag, verb)
       abort(404)
 
   return tag_image
@@ -346,18 +352,23 @@ def get_squashed_tag(namespace, repository, tag):
 @parse_repository_name()
 def get_tag_torrent(namespace_name, repo_name, digest):
   permission = ReadRepositoryPermission(namespace_name, repo_name)
-  public_repo = model.repository_is_public(namespace_name, repo_name)
-  if not permission.can() and not public_repo:
+  repo = model.get_repository(namespace_name, repo_name)
+  repo_is_public = repo is not None and repo.is_public
+
+  if not permission.can() and not repo_is_public:
     abort(403)
 
   user = get_authenticated_user()
-  if user is None and not public_repo:
+  if user is None and not repo_is_public:
     # We can not generate a private torrent cluster without a user uuid (e.g. token auth)
     abort(403)
 
+  if repo.kind != 'image':
+    abort(405)
+
   blob = model.get_repo_blob_by_digest(namespace_name, repo_name, digest)
   if blob is None:
     abort(404)
 
   metric_queue.repository_pull.Inc(labelvalues=[namespace_name, repo_name, 'torrent', True])
-  return _torrent_for_blob(blob, public_repo)
+  return _torrent_for_blob(blob, repo_is_public)