Skip to content

Commit d21a2f2

Browse files
fix: handle more ubuntu git repo errors (#214)
Currently there may be situations where there are untracked files present in the ubuntu git working directory (likely due to some previous failure state), so the provider will now automatically issue a `git clean -fd` to try and resolve these rather than failing. If the pull still fails, then just re-clone the repo (except in the case of 503 errors) Now raises a specific exception for the 503 errors which are frequently issued by the upstream https endpoint so that specific scenario can be handled separately Signed-off-by: Weston Steimel <[email protected]>
1 parent 5ab9ccf commit d21a2f2

File tree

1 file changed

+54
-18
lines changed
  • src/vunnel/providers/ubuntu

1 file changed

+54
-18
lines changed

src/vunnel/providers/ubuntu/git.py

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ class GitRevision:
2626
file: str
2727

2828

29+
class UbuntuGitServer503Error(Exception):
30+
"""Exception raised when the ubuntu git server returns a 503"""
31+
32+
def __init__(self):
33+
super().__init__(
34+
"The ubuntu git server is unavailable, try again later or switch to the git protocol endpoint git://git.launchpad.net/ubuntu-cve-tracker"
35+
)
36+
37+
2938
class GitWrapper:
3039
__active_retired_filename_regex__ = re.compile(r"(active|retired)/CVE-\S+")
3140
__cve_id_regex__ = re.compile(r"CVE-\S+")
@@ -36,12 +45,14 @@ class GitWrapper:
3645
_check_out_cmd_ = "git checkout {branch}"
3746
_pull_cmd_ = "git pull -f"
3847
_fetch_cmd_ = "git fetch --all"
48+
_clean_cmd_ = "git clean --force -d"
3949
_reset_cmd_ = "git reset --hard HEAD"
4050
_pull_ff_only_cmd_ = "git pull --ff-only"
4151
_write_graph_ = "git commit-graph write --reachable --changed-paths"
4252
_change_set_cmd_ = "git log --no-renames --no-merges --name-status --format=oneline {from_rev}..{to_rev}"
4353
_get_rev_content_cmd_ = "git show {sha}:{file}"
4454
_head_rev_cmd_ = "git rev-parse HEAD"
55+
_ubuntu_server_503_message = "error: RPC failed; HTTP 503 curl 22 The requested URL returned error: 503"
4556

4657
def __init__(
4758
self, source: str, branch: str, checkout_dest: str, workspace: str | None = None, logger: logging.Logger | None = None
@@ -78,30 +89,34 @@ def _check(self, destination):
7889

7990
return True
8091

81-
@utils.retry_with_backoff()
82-
def init_repo(self, force=False):
83-
if force:
84-
if os.path.exists(self.dest):
85-
self.logger.debug("deleting existing repository")
86-
shutil.rmtree(self.dest, ignore_errors=True)
87-
88-
if self._check(self.dest):
89-
self.logger.debug("found git repository at {}".format(self.dest))
90-
self.sync_with_upstream()
91-
return
92+
def _delete_repo(self):
93+
if os.path.exists(self.dest):
94+
self.logger.debug("deleting existing repository")
95+
shutil.rmtree(self.dest, ignore_errors=True)
9296

97+
def _clone_repo(self):
9398
try:
9499
self.logger.info(f"cloning git repository {self.src} branch {self.branch} to {self.dest}")
95-
96100
cmd = self._clone_cmd_.format(src=self.src, dest=self.dest, branch=self.branch)
97101
out = self._exec_cmd(cmd)
98-
99102
self.logger.debug("initialized git repo, cmd: {}, output: {}".format(cmd, out.decode()))
100103
self._write_graph()
101104
except:
102105
self.logger.exception(f"failed to clone git repository {self.src} branch {self.branch} to {self.dest}")
103106
raise
104107

108+
@utils.retry_with_backoff()
109+
def init_repo(self, force=False):
110+
if force:
111+
self._delete_repo()
112+
113+
if self._check(self.dest):
114+
self.logger.debug("found git repository at {}".format(self.dest))
115+
self.sync_with_upstream()
116+
return
117+
118+
self._clone_repo()
119+
105120
def parse_full_cve_revision_history(self, git_log_output: str) -> dict[str, list[GitRevision]]:
106121
hist = {}
107122
entries = self._parse_log(git_log_output)
@@ -126,13 +141,29 @@ def sync_with_upstream(self):
126141
try:
127142
try:
128143
self._exec_cmd(self._set_remote_cmd_.format(src=self.src), cwd=self.dest)
144+
145+
# Cleanup any untracked files which might be present and reset any changes on the current branch
146+
try:
147+
self._exec_cmd(self._clean_cmd_, cwd=self.dest)
148+
self._exec_cmd(self._reset_cmd_, cwd=self.dest)
149+
except:
150+
pass
151+
129152
self._exec_cmd(self._check_out_cmd_.format(branch=self.branch), cwd=self.dest)
130-
self._exec_cmd(self._reset_cmd_, cwd=self.dest)
131153
except: # nosec
132154
pass
133-
out = self._exec_cmd(self._pull_ff_only_cmd_, cwd=self.dest)
134-
self.logger.debug("synced with upstream git repo, output: {}".format(out.decode()))
135-
self._write_graph()
155+
156+
try:
157+
out = self._exec_cmd(self._pull_ff_only_cmd_, cwd=self.dest)
158+
self.logger.debug("synced with upstream git repo, output: {}".format(out.decode()))
159+
self._write_graph()
160+
except UbuntuGitServer503Error:
161+
raise
162+
except: # nosec
163+
# if something other than 503 occurred at this point just remove the repo and re-clone
164+
self._delete_repo()
165+
self._clone_repo()
166+
136167
except:
137168
self.logger.exception("failed to git pull")
138169
raise
@@ -358,7 +389,12 @@ def _exec_cmd(self, cmd, *args, **kwargs) -> bytes:
358389
try:
359390
self.logger.trace("running: {}".format(cmd))
360391
cmd_list = shlex.split(cmd)
361-
return subprocess.check_output(cmd_list, *args, **kwargs) # nosec
392+
return subprocess.check_output(cmd_list, *args, **kwargs, stderr=subprocess.PIPE) # nosec
362393
except Exception as e:
363394
self.logger.exception("error executing command: {}".format(cmd))
395+
396+
if isinstance(e, subprocess.CalledProcessError):
397+
if e.stderr and self._ubuntu_server_503_message in e.stderr.decode():
398+
raise UbuntuGitServer503Error()
399+
364400
raise e

0 commit comments

Comments
 (0)