[git_cl.py] Remove all usage and messages around netrc.

netrc was already legacy in 2017:
fe30f18fc5

The removed gerrit-init.sh script was written in 2013 and no longer
works.

R=yiwzhang@google.com

Bug: 336351842
Change-Id: Ia8e845899973eb5ead66aee2f54078c09d80ef28
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/5564197
Commit-Queue: Yiwei Zhang <yiwzhang@google.com>
Reviewed-by: Yiwei Zhang <yiwzhang@google.com>
Auto-Submit: Robbie Iannucci <iannucci@chromium.org>
changes/97/5564197/2
Robert Iannucci 11 months ago committed by LUCI CQ
parent 2f779d3061
commit 3ea849f363

@ -12,7 +12,6 @@ import contextlib
import httplib2 import httplib2
import json import json
import logging import logging
import netrc
import os import os
import random import random
import re import re
@ -118,7 +117,7 @@ class Authenticator(object):
class CookiesAuthenticator(Authenticator): class CookiesAuthenticator(Authenticator):
"""Authenticator implementation that uses ".netrc" or ".gitcookies" for token. """Authenticator implementation that uses ".gitcookies" for token.
Expected case for developer workstations. Expected case for developer workstations.
""" """
@ -131,15 +130,8 @@ class CookiesAuthenticator(Authenticator):
# something is broken. This allows 'creds-check' to proceed to actually # something is broken. This allows 'creds-check' to proceed to actually
# checking creds later, rigorously (instead of blowing up with a cryptic # checking creds later, rigorously (instead of blowing up with a cryptic
# error if they are wrong). # error if they are wrong).
self._netrc = self._EMPTY
self._gitcookies = self._EMPTY self._gitcookies = self._EMPTY
@property
def netrc(self):
if self._netrc is self._EMPTY:
self._netrc = self._get_netrc()
return self._netrc
@property @property
def gitcookies(self): def gitcookies(self):
if self._gitcookies is self._EMPTY: if self._gitcookies is self._EMPTY:
@ -167,52 +159,6 @@ class CookiesAuthenticator(Authenticator):
url = cls.get_new_password_url(host) url = cls.get_new_password_url(host)
return 'You can (re)generate your credentials by visiting %s' % url return 'You can (re)generate your credentials by visiting %s' % url
@classmethod
def get_netrc_path(cls):
path = '_netrc' if sys.platform.startswith('win') else '.netrc'
return os.path.expanduser(os.path.join('~', path))
@classmethod
def _get_netrc(cls):
# Buffer the '.netrc' path. Use an empty file if it doesn't exist.
path = cls.get_netrc_path()
if not os.path.exists(path):
return netrc.netrc(os.devnull)
st = os.stat(path)
if st.st_mode & (stat.S_IRWXG | stat.S_IRWXO):
print('WARNING: netrc file %s cannot be used because its file '
'permissions are insecure. netrc file permissions should be '
'600.' % path,
file=sys.stderr)
with open(path) as fd:
content = fd.read()
# Load the '.netrc' file. We strip comments from it because processing
# them can trigger a bug in Windows. See crbug.com/664664.
content = '\n'.join(l for l in content.splitlines()
if l.strip() and not l.strip().startswith('#'))
with tempdir() as tdir:
netrc_path = os.path.join(tdir, 'netrc')
with open(netrc_path, 'w') as fd:
fd.write(content)
os.chmod(netrc_path, (stat.S_IRUSR | stat.S_IWUSR))
return cls._get_netrc_from_path(netrc_path)
@classmethod
def _get_netrc_from_path(cls, path):
try:
return netrc.netrc(path)
except IOError:
print('WARNING: Could not read netrc file %s' % path,
file=sys.stderr)
return netrc.netrc(os.devnull)
except netrc.NetrcParseError as e:
print('ERROR: Cannot use netrc file %s due to a parsing error: %s' %
(path, e),
file=sys.stderr)
return netrc.netrc(os.devnull)
@classmethod @classmethod
def get_gitcookies_path(cls): def get_gitcookies_path(cls):
if os.getenv('GIT_COOKIES_PATH'): if os.getenv('GIT_COOKIES_PATH'):
@ -255,7 +201,7 @@ class CookiesAuthenticator(Authenticator):
for domain, creds in self.gitcookies.items(): for domain, creds in self.gitcookies.items():
if http.cookiejar.domain_match(host, domain): if http.cookiejar.domain_match(host, domain):
return (creds[0], None, creds[1]) return (creds[0], None, creds[1])
return self.netrc.authenticators(host) return None
def get_auth_header(self, host): def get_auth_header(self, host):
a = self._get_auth_for_host(host) a = self._get_auth_for_host(host)
@ -281,11 +227,6 @@ class CookiesAuthenticator(Authenticator):
return '%s@%s' % (username, domain) return '%s@%s' % (username, domain)
# Backwards compatibility just in case somebody imports this outside of
# depot_tools.
NetrcAuthenticator = CookiesAuthenticator
class GceAuthenticator(Authenticator): class GceAuthenticator(Authenticator):
"""Authenticator implementation that uses GCE metadata service for token. """Authenticator implementation that uses GCE metadata service for token.
""" """

@ -2339,10 +2339,9 @@ class Changelist(object):
([] if git_auth else [git_host])) ([] if git_auth else [git_host]))
DieWithError('Credentials for the following hosts are required:\n' DieWithError('Credentials for the following hosts are required:\n'
' %s\n' ' %s\n'
'These are read from %s (or legacy %s)\n' 'These are read from %s\n'
'%s' % '%s' %
('\n '.join(missing), cookie_auth.get_gitcookies_path(), ('\n '.join(missing), cookie_auth.get_gitcookies_path(),
cookie_auth.get_netrc_path(),
cookie_auth.get_new_password_message(git_host))) cookie_auth.get_new_password_message(git_host)))
def EnsureCanUploadPatchset(self, force): def EnsureCanUploadPatchset(self, force):
@ -3628,8 +3627,8 @@ def DownloadGerritHook(force):
class _GitCookiesChecker(object): class _GitCookiesChecker(object):
"""Provides facilities for validating and suggesting fixes to .gitcookies.""" """Provides facilities for validating and suggesting fixes to .gitcookies."""
def __init__(self): def __init__(self):
# Cached list of [host, identity, source], where source is either # Cached list of [host, identity, source], where source is
# .gitcookies or .netrc. # .gitcookies
self._all_hosts = None self._all_hosts = None
def ensure_configured_gitcookies(self): def ensure_configured_gitcookies(self):
@ -3679,11 +3678,6 @@ class _GitCookiesChecker(object):
@staticmethod @staticmethod
def _configure_gitcookies_path(default_path): def _configure_gitcookies_path(default_path):
netrc_path = gerrit_util.CookiesAuthenticator.get_netrc_path()
if os.path.exists(netrc_path):
print(
'You seem to be using outdated .netrc for git credentials: %s' %
netrc_path)
print( print(
'This tool will guide you through setting up recommended ' 'This tool will guide you through setting up recommended '
'.gitcookies store for git credentials.\n' '.gitcookies store for git credentials.\n'
@ -3695,21 +3689,17 @@ class _GitCookiesChecker(object):
RunGit(['config', '--global', 'http.cookiefile', default_path]) RunGit(['config', '--global', 'http.cookiefile', default_path])
print('Configured git to use .gitcookies from %s' % default_path) print('Configured git to use .gitcookies from %s' % default_path)
def get_hosts_with_creds(self, include_netrc=False): def get_hosts_with_creds(self):
if self._all_hosts is None: if self._all_hosts is None:
a = gerrit_util.CookiesAuthenticator() a = gerrit_util.CookiesAuthenticator()
self._all_hosts = [(h, u, s) for h, u, s in itertools.chain(( self._all_hosts = [(h, u, '.gitcookies')
(h, u, '.netrc') for h, (u, _, _) in a.netrc.hosts.items()), ( for h, (u, _) in a.gitcookies.items()
(h, u, '.gitcookies')
for h, (u, _) in a.gitcookies.items()))
if h.endswith(_GOOGLESOURCE)] if h.endswith(_GOOGLESOURCE)]
if include_netrc: return self._all_hosts
return self._all_hosts
return [(h, u, s) for h, u, s in self._all_hosts if s != '.netrc']
def print_current_creds(self, include_netrc=False): def print_current_creds(self):
hosts = sorted(self.get_hosts_with_creds(include_netrc=include_netrc)) hosts = sorted(self.get_hosts_with_creds())
if not hosts: if not hosts:
print('No Git/Gerrit credentials found') print('No Git/Gerrit credentials found')
return return
@ -3737,7 +3727,7 @@ class _GitCookiesChecker(object):
Chrome Infra recommends to use explicit ${host}.googlesource.com instead. Chrome Infra recommends to use explicit ${host}.googlesource.com instead.
""" """
for host, _, _ in self.get_hosts_with_creds(include_netrc=False): for host, _, _ in self.get_hosts_with_creds():
if host == '.' + _GOOGLESOURCE: if host == '.' + _GOOGLESOURCE:
return True return True
return False return False
@ -3870,8 +3860,8 @@ def CMDcreds_check(parser, args):
checker = _GitCookiesChecker() checker = _GitCookiesChecker()
checker.ensure_configured_gitcookies() checker.ensure_configured_gitcookies()
print('Your .netrc and .gitcookies have credentials for these hosts:') print('Your .gitcookies have credentials for these hosts:')
checker.print_current_creds(include_netrc=True) checker.print_current_creds()
if not checker.find_and_report_problems(): if not checker.find_and_report_problems():
print('\nNo problems detected in your .gitcookies file.') print('\nNo problems detected in your .gitcookies file.')

@ -1,216 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
set -e
http_port=8080
ssh_port=29418
while test $# -ne 0; do
case "$1" in
-v)
version="$2"
shift
;;
-d)
rundir="$2"
shift
;;
--http-port)
http_port="$2"
shift
;;
--ssh-port)
ssh_port="$2"
shift
;;
*)
rundir="$1"
;;
esac
shift
done
if [ -z "$rundir" ]; then
rundir=$(mktemp -d)
fi
this_dir=$(dirname $0)
gerrit_exe="$this_dir/gerrit.war"
account_id=101
full_name='Test Account'
maximum_page_size='25'
password='test-password'
preferred_email="test-username@test.org"
registered_on=$(date '+%Y-%m-%d %H:%M:%S.000%:::z')
username='test-username'
# The python code below for picking the "latest" gerrit release is cribbed and
# ported from the javascript at:
#
# http://gerrit-releases.storage.googleapis.com/index.html
url='https://www.googleapis.com/storage/v1/b/gerrit-releases/o?projection=noAcl'
curl --retry 30 --ssl-reqd -s $url | python <(cat <<EOF
# Receives Gerrit version via command line and reads json-encoded
# text from stdin in the format:
#
# {
# "items": [
# {
# "name": "gerrit-<version>.war",
# "md5Hash": "<base64 encoded md5sum>",
# },
# {
# "name": "gerrit-<version>.war",
# "md5Hash": "<base64 encoded md5sum>",
# },
# ...
# }
#
# ...and prints the name and md5sum of the corresponding *.war file.
from __future__ import print_function
import json
import re
import sys
requested_version = sys.argv[1] if len(sys.argv) > 1 else None
# Disable using -rc versions. This is a temporary hack to avoid
# picking up version 2.9-rc0, which requires java 7. These lines
# should be un-commented after this bug is fixed:
# https://code.google.com/p/chromium/issues/detail?id=346369
#gerrit_re = re.compile('gerrit(?:-full)?-([0-9.]+)(-rc[0-9]+)?[.]war')
gerrit_re = re.compile('gerrit(?:-full)?-([0-9.]+)[.]war')
j = json.load(sys.stdin)
items = [(x, gerrit_re.match(x['name'])) for x in j['items']]
#items = [(x, m.group(1), m.group(2)) for x, m in items if m]
items = [(x, m.group(1), '') for x, m in items if m]
def _cmp(a, b):
an = a[1].split('.')
bn = b[1].split('.')
while len(an) < len(bn):
an.append('0')
while len(bn) < len(an):
bn.append('0')
an.append(a[2][3:] if a[2] else '1000')
bn.append(b[2][3:] if b[2] else '1000')
for i in range(len(an)):
if an[i] != bn[i]:
return -1 if int(an[i]) > int(bn[i]) else 1
return 0
if requested_version:
for info, version in items:
if version == requested_version:
print('"%s" "%s"' % (info['name'], info['md5Hash']))
sys.exit(0)
print('No such Gerrit version: %s' % requested_version, file=sys.stderr)
sys.exit(1)
items.sort(cmp=_cmp)
for x in items:
print('"%s" "%s"' % (x[0]['name'], x[0]['md5Hash']))
sys.exit(0)
EOF
) "$version" | xargs | while read name md5; do
# Download the requested gerrit version if necessary, and verify the md5sum.
target="$this_dir/$name"
net_sum=$(echo -n $md5 | base64 -d | od -tx1 | head -1 | cut -d ' ' -f 2- |
sed 's/ //g')
if [ -f "$target" ]; then
file_sum=$(md5sum "$target" | awk '{print $1}' | xargs)
if [ "$file_sum" = "$net_sum" ]; then
ln -sf "$name" "$gerrit_exe"
break
else
rm -rf "$target"
fi
fi
curl --retry 30 --ssl-reqd -s -o "$target" \
"https://gerrit-releases.storage.googleapis.com/$name"
file_sum=$(md5sum "$target" | awk '{print $1}' | xargs)
if [ "$file_sum" != "$net_sum" ]; then
echo "ERROR: md5sum mismatch when downloading $name" 1>&2
rm -rf "$target"
exit 1
else
ln -sf "$name" "$gerrit_exe"
fi
done
if [ ! -e "$gerrit_exe" ]; then
echo "ERROR: No $gerrit_exe file or link present, and unable " 1>&2
echo " to download the latest version." 1>&2
exit 1
fi
# By default, gerrit only accepts https connections, which is a good thing. But
# for testing, it's convenient to enable plain http. Also, turn off all email
# notifications.
mkdir -p "${rundir}/etc"
cat <<EOF > "${rundir}/etc/gerrit.config"
[auth]
type = DEVELOPMENT_BECOME_ANY_ACCOUNT
gitBasicAuth = true
[gerrit]
canonicalWebUrl = http://$(hostname):${http_port}/
[httpd]
listenUrl = http://*:${http_port}/
[sshd]
listenAddress = *:${ssh_port}
[sendemail]
enable = false
[container]
javaOptions = -Duser.home=${rundir}/tmp
EOF
# Initialize the gerrit instance.
java -jar "$gerrit_exe" init --no-auto-start --batch --install-plugin=download-commands -d "${rundir}"
# Create SSH key pair for the first user.
mkdir -p "${rundir}/tmp"
ssh-keygen -t rsa -q -f "${rundir}/tmp/id_rsa" -N ""
ssh_public_key="$(cat ${rundir}/tmp/id_rsa.pub)"
# Set up the first user, with admin privileges.
cat <<EOF | java -jar "$gerrit_exe" gsql -d "${rundir}" > /dev/null
INSERT INTO ACCOUNTS (FULL_NAME, MAXIMUM_PAGE_SIZE, PREFERRED_EMAIL, REGISTERED_ON, ACCOUNT_ID) VALUES ('${full_name}', ${maximum_page_size}, '${preferred_email}', '${registered_on}', ${account_id});
INSERT INTO ACCOUNT_EXTERNAL_IDS (ACCOUNT_ID, EXTERNAL_ID) VALUES (${account_id}, 'gerrit:${username}');
INSERT INTO ACCOUNT_EXTERNAL_IDS (ACCOUNT_ID, EXTERNAL_ID) VALUES (${account_id}, 'username:${username}');
INSERT INTO ACCOUNT_EXTERNAL_IDS (ACCOUNT_ID, EMAIL_ADDRESS, PASSWORD) VALUES (${account_id}, '${preferred_email}', '${password}');
INSERT INTO ACCOUNT_GROUP_MEMBERS (ACCOUNT_ID, GROUP_ID) VALUES (${account_id}, 1);
INSERT INTO ACCOUNT_SSH_KEYS (ACCOUNT_ID, SSH_PUBLIC_KEY, VALID, SEQ) VALUES (${account_id}, '${ssh_public_key}', 'Y', 0);
EOF
# Create a netrc file to authenticate as the first user.
cat <<EOF > "${rundir}/tmp/.netrc"
machine localhost login ${username} password ${password}
EOF
# Create a .git-credentials file, to enable password-less push.
cat <<EOF > "${rundir}/tmp/.git-credentials"
http://${username}:${password}@localhost:${http_port}
EOF
cat <<EOF
To start gerrit server:
${rundir}/bin/gerrit.sh start
To use the REST API:
curl --netrc-file ${rundir}/tmp/.netrc http://localhost:${http_port}/<endpoint>
To use SSH API:
ssh ${username}@localhost -p ${ssh_port} -i ${rundir}/tmp/id_rsa gerrit
To enable 'git push' without a password prompt:
git config credential.helper 'store --file=${rundir}/tmp/.git-credentials'
To stop the server:
${rundir}/bin/gerrit.sh stop
EOF

@ -41,9 +41,6 @@ import subprocess2
# TODO: Should fix these warnings. # TODO: Should fix these warnings.
# pylint: disable=line-too-long # pylint: disable=line-too-long
NETRC_FILENAME = '_netrc' if sys.platform == 'win32' else '.netrc'
def callError(code=1, cmd='', cwd='', stdout=b'', stderr=b''): def callError(code=1, cmd='', cwd='', stdout=b'', stderr=b''):
return subprocess2.CalledProcessError(code, cmd, cwd, stdout, stderr) return subprocess2.CalledProcessError(code, cmd, cwd, stdout, stderr)
@ -145,7 +142,7 @@ class AuthenticatorMock(object):
def CookiesAuthenticatorMockFactory(hosts_with_creds=None, same_auth=False): def CookiesAuthenticatorMockFactory(hosts_with_creds=None, same_auth=False):
"""Use to mock Gerrit/Git credentials from ~/.netrc or ~/.gitcookies. """Use to mock Gerrit/Git credentials from ~/.gitcookies.
Usage: Usage:
>>> self.mock(git_cl.gerrit_util, "CookiesAuthenticator", >>> self.mock(git_cl.gerrit_util, "CookiesAuthenticator",
@ -166,10 +163,6 @@ def CookiesAuthenticatorMockFactory(hosts_with_creds=None, same_auth=False):
def get_gitcookies_path(cls): def get_gitcookies_path(cls):
return os.path.join('~', '.gitcookies') return os.path.join('~', '.gitcookies')
@classmethod
def get_netrc_path(cls):
return os.path.join('~', NETRC_FILENAME)
def _get_auth_for_host(self, host): def _get_auth_for_host(self, host):
if same_auth: if same_auth:
return same_auth return same_auth
@ -2538,12 +2531,10 @@ class TestGitCl(unittest.TestCase):
self.assertEqual( self.assertEqual(
'Credentials for the following hosts are required:\n' 'Credentials for the following hosts are required:\n'
' chromium-review.googlesource.com\n' ' chromium-review.googlesource.com\n'
'These are read from ~%(sep)s.gitcookies ' 'These are read from ~%(sep)s.gitcookies\n'
'(or legacy ~%(sep)s%(netrc)s)\n'
'You can (re)generate your credentials by visiting ' 'You can (re)generate your credentials by visiting '
'https://chromium.googlesource.com/new-password\n' % { 'https://chromium.googlesource.com/new-password\n' % {
'sep': os.sep, 'sep': os.sep,
'netrc': NETRC_FILENAME,
}, sys.stderr.getvalue()) }, sys.stderr.getvalue())
def test_gerrit_ensure_authenticated_conflict(self): def test_gerrit_ensure_authenticated_conflict(self):
@ -3109,25 +3100,19 @@ class TestGitCl(unittest.TestCase):
'host.googlesource.com': ('user', 'pass'), 'host.googlesource.com': ('user', 'pass'),
'host-review.googlesource.com': ('user', 'pass'), 'host-review.googlesource.com': ('user', 'pass'),
} }
self.netrc = self
self.netrc.hosts = {
'github.com': ('user2', None, 'pass2'),
'host2.googlesource.com': ('user3', None, 'pass'),
}
mock.patch('git_cl.gerrit_util.CookiesAuthenticator', mock.patch('git_cl.gerrit_util.CookiesAuthenticator',
CookiesAuthenticatorMock).start() CookiesAuthenticatorMock).start()
git_cl._GitCookiesChecker().print_current_creds(include_netrc=True) git_cl._GitCookiesChecker().print_current_creds()
self.assertEqual(list(sys.stdout.getvalue().splitlines()), [ self.assertEqual(list(sys.stdout.getvalue().splitlines()), [
' Host\t User\t Which file', ' Host\tUser\t Which file',
'============================\t=====\t===========', '============================\t====\t===========',
'host-review.googlesource.com\t user\t.gitcookies', 'host-review.googlesource.com\tuser\t.gitcookies',
' host.googlesource.com\t user\t.gitcookies', ' host.googlesource.com\tuser\t.gitcookies',
' host2.googlesource.com\tuser3\t .netrc',
]) ])
sys.stdout.seek(0) sys.stdout.seek(0)
sys.stdout.truncate(0) sys.stdout.truncate(0)
git_cl._GitCookiesChecker().print_current_creds(include_netrc=False) git_cl._GitCookiesChecker().print_current_creds()
self.assertEqual(list(sys.stdout.getvalue().splitlines()), [ self.assertEqual(list(sys.stdout.getvalue().splitlines()), [
' Host\tUser\t Which file', ' Host\tUser\t Which file',
'============================\t====\t===========', '============================\t====\t===========',
@ -3141,7 +3126,7 @@ class TestGitCl(unittest.TestCase):
if dirname == os.path.expanduser('~'): if dirname == os.path.expanduser('~'):
dirname = '~' dirname = '~'
base = os.path.basename(path) base = os.path.basename(path)
if base in (NETRC_FILENAME, '.gitcookies'): if base == '.gitcookies':
return self._mocked_call('os.path.exists', return self._mocked_call('os.path.exists',
os.path.join(dirname, base)) os.path.join(dirname, base))
# git cl also checks for existence other files not relevant to this # git cl also checks for existence other files not relevant to this
@ -3156,10 +3141,9 @@ class TestGitCl(unittest.TestCase):
def test_creds_check_gitcookies_not_configured(self): def test_creds_check_gitcookies_not_configured(self):
self._common_creds_check_mocks() self._common_creds_check_mocks()
mock.patch('git_cl._GitCookiesChecker.get_hosts_with_creds', mock.patch('git_cl._GitCookiesChecker.get_hosts_with_creds',
lambda _, include_netrc=False: []).start() lambda _: []).start()
self.calls = [ self.calls = [
((['git', 'config', '--global', 'http.cookiefile'], ), CERR1), ((['git', 'config', '--global', 'http.cookiefile'], ), CERR1),
(('os.path.exists', os.path.join('~', NETRC_FILENAME)), True),
(('ask_for_data', 'Press Enter to setup .gitcookies, ' (('ask_for_data', 'Press Enter to setup .gitcookies, '
'or Ctrl+C to abort'), ''), 'or Ctrl+C to abort'), ''),
(([ (([
@ -3168,15 +3152,13 @@ class TestGitCl(unittest.TestCase):
], ), ''), ], ), ''),
] ]
self.assertEqual(0, git_cl.main(['creds-check'])) self.assertEqual(0, git_cl.main(['creds-check']))
self.assertTrue(sys.stdout.getvalue().startswith(
'You seem to be using outdated .netrc for git credentials:'))
self.assertIn('\nConfigured git to use .gitcookies from', self.assertIn('\nConfigured git to use .gitcookies from',
sys.stdout.getvalue()) sys.stdout.getvalue())
def test_creds_check_gitcookies_configured_custom_broken(self): def test_creds_check_gitcookies_configured_custom_broken(self):
self._common_creds_check_mocks() self._common_creds_check_mocks()
mock.patch('git_cl._GitCookiesChecker.get_hosts_with_creds', mock.patch('git_cl._GitCookiesChecker.get_hosts_with_creds',
lambda _, include_netrc=False: []).start() lambda _: []).start()
custom_cookie_path = ('C:\\.gitcookies' if sys.platform == 'win32' else custom_cookie_path = ('C:\\.gitcookies' if sys.platform == 'win32' else
'/custom/.gitcookies') '/custom/.gitcookies')
self.calls = [ self.calls = [

Loading…
Cancel
Save