From 3ea849f3635f136526317e3eb46b97dcaad38491 Mon Sep 17 00:00:00 2001 From: Robert Iannucci Date: Thu, 23 May 2024 21:36:19 +0000 Subject: [PATCH] [git_cl.py] Remove all usage and messages around netrc. netrc was already legacy in 2017: https://chromium.googlesource.com/chromium/tools/depot_tools/+/fe30f18fc57552e3c8a3acdb8fcaa213ad752a41 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 Reviewed-by: Yiwei Zhang Auto-Submit: Robbie Iannucci --- gerrit_util.py | 63 +--------- git_cl.py | 34 ++---- testing_support/gerrit-init.sh | 216 --------------------------------- tests/git_cl_test.py | 40 ++---- 4 files changed, 25 insertions(+), 328 deletions(-) delete mode 100755 testing_support/gerrit-init.sh diff --git a/gerrit_util.py b/gerrit_util.py index 609f0b33a..35c206f80 100644 --- a/gerrit_util.py +++ b/gerrit_util.py @@ -12,7 +12,6 @@ import contextlib import httplib2 import json import logging -import netrc import os import random import re @@ -118,7 +117,7 @@ class Authenticator(object): class CookiesAuthenticator(Authenticator): - """Authenticator implementation that uses ".netrc" or ".gitcookies" for token. + """Authenticator implementation that uses ".gitcookies" for token. Expected case for developer workstations. """ @@ -131,15 +130,8 @@ class CookiesAuthenticator(Authenticator): # something is broken. This allows 'creds-check' to proceed to actually # checking creds later, rigorously (instead of blowing up with a cryptic # error if they are wrong). - self._netrc = 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 def gitcookies(self): if self._gitcookies is self._EMPTY: @@ -167,52 +159,6 @@ class CookiesAuthenticator(Authenticator): url = cls.get_new_password_url(host) 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 def get_gitcookies_path(cls): if os.getenv('GIT_COOKIES_PATH'): @@ -255,7 +201,7 @@ class CookiesAuthenticator(Authenticator): for domain, creds in self.gitcookies.items(): if http.cookiejar.domain_match(host, domain): return (creds[0], None, creds[1]) - return self.netrc.authenticators(host) + return None def get_auth_header(self, host): a = self._get_auth_for_host(host) @@ -281,11 +227,6 @@ class CookiesAuthenticator(Authenticator): return '%s@%s' % (username, domain) -# Backwards compatibility just in case somebody imports this outside of -# depot_tools. -NetrcAuthenticator = CookiesAuthenticator - - class GceAuthenticator(Authenticator): """Authenticator implementation that uses GCE metadata service for token. """ diff --git a/git_cl.py b/git_cl.py index 3d50af954..1150e397e 100755 --- a/git_cl.py +++ b/git_cl.py @@ -2339,10 +2339,9 @@ class Changelist(object): ([] if git_auth else [git_host])) DieWithError('Credentials for the following hosts are required:\n' ' %s\n' - 'These are read from %s (or legacy %s)\n' + 'These are read from %s\n' '%s' % ('\n '.join(missing), cookie_auth.get_gitcookies_path(), - cookie_auth.get_netrc_path(), cookie_auth.get_new_password_message(git_host))) def EnsureCanUploadPatchset(self, force): @@ -3628,8 +3627,8 @@ def DownloadGerritHook(force): class _GitCookiesChecker(object): """Provides facilities for validating and suggesting fixes to .gitcookies.""" def __init__(self): - # Cached list of [host, identity, source], where source is either - # .gitcookies or .netrc. + # Cached list of [host, identity, source], where source is + # .gitcookies self._all_hosts = None def ensure_configured_gitcookies(self): @@ -3679,11 +3678,6 @@ class _GitCookiesChecker(object): @staticmethod 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( 'This tool will guide you through setting up recommended ' '.gitcookies store for git credentials.\n' @@ -3695,21 +3689,17 @@ class _GitCookiesChecker(object): RunGit(['config', '--global', 'http.cookiefile', 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: a = gerrit_util.CookiesAuthenticator() - self._all_hosts = [(h, u, s) for h, u, s in itertools.chain(( - (h, u, '.netrc') for h, (u, _, _) in a.netrc.hosts.items()), ( - (h, u, '.gitcookies') - for h, (u, _) in a.gitcookies.items())) + self._all_hosts = [(h, u, '.gitcookies') + for h, (u, _) in a.gitcookies.items() if h.endswith(_GOOGLESOURCE)] - if include_netrc: - return self._all_hosts - return [(h, u, s) for h, u, s in self._all_hosts if s != '.netrc'] + return self._all_hosts - def print_current_creds(self, include_netrc=False): - hosts = sorted(self.get_hosts_with_creds(include_netrc=include_netrc)) + def print_current_creds(self): + hosts = sorted(self.get_hosts_with_creds()) if not hosts: print('No Git/Gerrit credentials found') return @@ -3737,7 +3727,7 @@ class _GitCookiesChecker(object): 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: return True return False @@ -3870,8 +3860,8 @@ def CMDcreds_check(parser, args): checker = _GitCookiesChecker() checker.ensure_configured_gitcookies() - print('Your .netrc and .gitcookies have credentials for these hosts:') - checker.print_current_creds(include_netrc=True) + print('Your .gitcookies have credentials for these hosts:') + checker.print_current_creds() if not checker.find_and_report_problems(): print('\nNo problems detected in your .gitcookies file.') diff --git a/testing_support/gerrit-init.sh b/testing_support/gerrit-init.sh deleted file mode 100755 index fc89f5193..000000000 --- a/testing_support/gerrit-init.sh +++ /dev/null @@ -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 <.war", -# "md5Hash": "", -# }, -# { -# "name": "gerrit-.war", -# "md5Hash": "", -# }, -# ... -# } -# -# ...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 < "${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 < /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 < "${rundir}/tmp/.netrc" -machine localhost login ${username} password ${password} -EOF - -# Create a .git-credentials file, to enable password-less push. -cat < "${rundir}/tmp/.git-credentials" -http://${username}:${password}@localhost:${http_port} -EOF - -cat < - -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 diff --git a/tests/git_cl_test.py b/tests/git_cl_test.py index 397e632d1..44956c64a 100755 --- a/tests/git_cl_test.py +++ b/tests/git_cl_test.py @@ -41,9 +41,6 @@ import subprocess2 # TODO: Should fix these warnings. # pylint: disable=line-too-long -NETRC_FILENAME = '_netrc' if sys.platform == 'win32' else '.netrc' - - def callError(code=1, cmd='', cwd='', stdout=b'', stderr=b''): return subprocess2.CalledProcessError(code, cmd, cwd, stdout, stderr) @@ -145,7 +142,7 @@ class AuthenticatorMock(object): 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: >>> 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): return os.path.join('~', '.gitcookies') - @classmethod - def get_netrc_path(cls): - return os.path.join('~', NETRC_FILENAME) - def _get_auth_for_host(self, host): if same_auth: return same_auth @@ -2538,12 +2531,10 @@ class TestGitCl(unittest.TestCase): self.assertEqual( 'Credentials for the following hosts are required:\n' ' chromium-review.googlesource.com\n' - 'These are read from ~%(sep)s.gitcookies ' - '(or legacy ~%(sep)s%(netrc)s)\n' + 'These are read from ~%(sep)s.gitcookies\n' 'You can (re)generate your credentials by visiting ' 'https://chromium.googlesource.com/new-password\n' % { 'sep': os.sep, - 'netrc': NETRC_FILENAME, }, sys.stderr.getvalue()) def test_gerrit_ensure_authenticated_conflict(self): @@ -3109,25 +3100,19 @@ class TestGitCl(unittest.TestCase): 'host.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', CookiesAuthenticatorMock).start() - git_cl._GitCookiesChecker().print_current_creds(include_netrc=True) + git_cl._GitCookiesChecker().print_current_creds() self.assertEqual(list(sys.stdout.getvalue().splitlines()), [ - ' Host\t User\t Which file', - '============================\t=====\t===========', - 'host-review.googlesource.com\t user\t.gitcookies', - ' host.googlesource.com\t user\t.gitcookies', - ' host2.googlesource.com\tuser3\t .netrc', + ' Host\tUser\t Which file', + '============================\t====\t===========', + 'host-review.googlesource.com\tuser\t.gitcookies', + ' host.googlesource.com\tuser\t.gitcookies', ]) sys.stdout.seek(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()), [ ' Host\tUser\t Which file', '============================\t====\t===========', @@ -3141,7 +3126,7 @@ class TestGitCl(unittest.TestCase): if dirname == os.path.expanduser('~'): dirname = '~' base = os.path.basename(path) - if base in (NETRC_FILENAME, '.gitcookies'): + if base == '.gitcookies': return self._mocked_call('os.path.exists', os.path.join(dirname, base)) # 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): self._common_creds_check_mocks() mock.patch('git_cl._GitCookiesChecker.get_hosts_with_creds', - lambda _, include_netrc=False: []).start() + lambda _: []).start() self.calls = [ ((['git', 'config', '--global', 'http.cookiefile'], ), CERR1), - (('os.path.exists', os.path.join('~', NETRC_FILENAME)), True), (('ask_for_data', 'Press Enter to setup .gitcookies, ' 'or Ctrl+C to abort'), ''), (([ @@ -3168,15 +3152,13 @@ class TestGitCl(unittest.TestCase): ], ), ''), ] 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', sys.stdout.getvalue()) def test_creds_check_gitcookies_configured_custom_broken(self): self._common_creds_check_mocks() 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/.gitcookies') self.calls = [