blob: b121adb50cb60142d05582cda0cf7759ecdb63a4 [file] [log] [blame]
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""API for SSO utility functions."""
import re
import urlparse
from recipe_engine import recipe_api
class SSOApi(recipe_api.RecipeApi):
"""API for SSO utility functions."""
def __init__(self, props, *args, **kwargs):
super(SSOApi, self).__init__(*args, **kwargs)
self._hosts_to_configure_insteadof = props.hosts_to_configure_insteadof
self._initialized = False
self._configured = set()
def initialize(self):
if self._initialized:
return
self._initialized = True
if self._hosts_to_configure_insteadof:
with self.m.step.nest("sso"):
for host in self._hosts_to_configure_insteadof:
url = "sso://{}".format(host)
self.configure_insteadof(url)
def configure_insteadof(self, sso_url):
"""Configure git to automatically rewrite an sso:// URL to https://.
If always calling git directly, transforming the URL ahead of time using
sso_to_https() is sufficient, but if Android Repo Tool manifests or
.gitmodules files reference sso:// URLs there's no good way to call
sso_to_https() on those paths ahead of time.
This would appear to affect future jobs on the same host because of the
"--global" flag, but the wrapper of git modifies files in
INFRA_GIT_WRAPPER_HOME instead, and that is cleaned up after each job.
Args:
host (str): An "sso://..." URL or a hostname.
"""
if not sso_url.startswith("sso://"):
sso_url = "sso://" + sso_url
host = urlparse.urlparse(sso_url).netloc
if not re.search(r"^[-a-z][-a-z.]+[-a-z]$", host):
raise self.m.step.StepFailure('bad hostname "{}"'.format(host))
# The argument might be a full path to a repository but it must be
# trimmed to only the host for duplicate checking.
sso = "sso://" + host
if sso in self._configured:
return
host, path = self._sso_to_https(sso)
# Using foo.googlesource.com/a/bar instead of foo.googlesource.com/bar
# The "/a/" forces authentication, which causes this request to use the
# correct quota bucket.
if not path.startswith("/a/"):
path = "/a" + path
https = host + path
self.m.git(
"git insteadof {}".format(sso),
"config",
"--global",
"--add",
"url.{}.insteadof".format(https),
sso,
)
self._configured.add(sso)
def _sso_to_https(self, remote):
url = urlparse.urlparse(remote)
host = url.netloc
# Sometimes URLs use '.git.corp.google.com' instead of
# '.googlesource.com', but '.git.corp.google.com' won't work with LUCI.
host = host.replace(".git.corp.google.com", ".googlesource.com")
# sso:// URLs do not usually contain '.googlesource.com' but can.
if not host.endswith(".googlesource.com"):
host += ".googlesource.com"
sso_host = "sso://{}".format(url.netloc)
https_host = "https://{}".format(host)
return (https_host, url.path)
def sso_to_https(self, remote):
"""Transform a remote URL of SSO scheme to its associated https version.
If not SSO, do nothing.
Args:
remote (str): SSO or https remote URL.
Returns:
str: input as SSO URL.
"""
remote = remote.replace(".git.corp.google.com", ".googlesource.com")
if not remote.startswith("sso://") and ".git.corp.google.com" not in remote:
return remote
host, path = self._sso_to_https(remote)
# Note that url.path contains a leading '/'.
return host + path