Skip to content
This repository has been archived by the owner on Oct 26, 2023. It is now read-only.

Commit

Permalink
Merge pull request #76 from snyk-tech-services/develop
Browse files Browse the repository at this point in the history
release changes
  • Loading branch information
scott-es authored Mar 10, 2022
2 parents f7baa23 + 9ee8bca commit 435befe
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 124 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
version: 2.1
orbs:
snyk: snyk/snyk@0.0.10
snyk: snyk/snyk@1.1.2
jobs:
build-test:
docker:
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# snyk-scm-refresh
[![Known Vulnerabilities](https://snyk.io/test/github/snyk-tech-services/snyk-scm-refresh/badge.svg)](https://snyk.io/test/github/snyk-tech-services/snyk-scm-refresh) [![circleci](https://circleci.com/gh/snyk-tech-services/snyk-scm-refresh.svg?style=svg)](https://circleci.com/gh/snyk-tech-services/snyk-scm-refresh)

<blockquote>
<g-emoji class="g-emoji" alias="warning" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/26a0.png">⚠️</g-emoji> <strong>WARNING:</strong>
Python 3.10 introduces breaking changes that are currently incompatible with this tool. You must use Python 3.7-3.9
</blockquote>
<br/>

Keeps Snyk projects in sync with their associated Github repos

For repos with at least 1 project already in Snyk:
Expand All @@ -11,6 +17,8 @@ For repos with at least 1 project already in Snyk:
- Enable Snyk Code analysis for repos
- Detect deleted repos and log for review



**STOP NOW IF ANY OF THE FOLLOWING ARE TRUE**
- Monitoring non-default branches
- Using an SCM other than Github.com or Github Enterprise Server
Expand All @@ -36,7 +44,7 @@ optional arguments:
```

### Sync with defaults
`./snyk_scm_refresh.py --org-id=12345
`./snyk_scm_refresh.py --org-id=12345`

### Sync SCA projects only
`./snyk_scm_refresh.py --org-id=12345 --container=off`
Expand Down
6 changes: 2 additions & 4 deletions app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,7 @@ def run():
f"Processing {str(i+1)}/{str(len(snyk_repos))}")

try:
if snyk_repo.origin == "github":
gh_repo_status = get_gh_repo_status(snyk_repo, common.GITHUB_TOKEN)
elif snyk_repo.origin == "github-enterprise":
gh_repo_status = get_gh_repo_status(snyk_repo, common.GITHUB_ENTERPRISE_TOKEN, True)
gh_repo_status = get_gh_repo_status(snyk_repo)

except RuntimeError as err:
raise RuntimeError("Failed to query GitHub repository!") from err
Expand Down Expand Up @@ -124,6 +121,7 @@ def run():
snyk_repo.full_name,
f"Checking {str(len(snyk_repo.snyk_projects))} " \
f"projects for any stale manifests")
# print(f"snyk repo projects: {snyk_repo.snyk_projects}")
deleted_projects = snyk_repo.delete_stale_manifests(common.ARGS.dry_run)
for project in deleted_projects:
if not common.ARGS.dry_run:
Expand Down
23 changes: 16 additions & 7 deletions app/gh_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,28 @@ def passes_manifest_filter(path, skip_snyk_code=False):

return passes_filter

def get_gh_repo_status(snyk_gh_repo, github_token, github_enterprise=False):
def get_gh_repo_status(snyk_gh_repo):
"""detect if repo still exists, has been removed, or renamed"""
repo_owner = snyk_gh_repo["owner"]
repo_name = snyk_gh_repo["name"]
repo_owner = snyk_gh_repo.full_name.split("/")[0]
repo_name = snyk_gh_repo.full_name.split("/")[1]
response_message = ""
repo_default_branch = ""

# print(f'snyk_gh_repo origin: {snyk_gh_repo.origin}')

if snyk_gh_repo.origin == "github":
github_token = common.GITHUB_TOKEN
elif snyk_gh_repo.origin == "github-enterprise":
github_token = common.GITHUB_ENTERPRISE_TOKEN

headers = {"Authorization": "Bearer %s"}
headers["Authorization"] = headers["Authorization"] % (github_token)
if not github_enterprise:
if snyk_gh_repo.origin == "github" or \
(snyk_gh_repo.origin == "github-enterprise" and \
common.USE_GHE_INTEGRATION_FOR_GH_CLOUD):
request_url = f"https://api.github.com/repos/{snyk_gh_repo['full_name']}"
# print("requestURL: " + requestURL)
else:
elif snyk_gh_repo.origin == "github-enterprise":
request_url = f"https://{common.GITHUB_ENTERPRISE_HOST}" \
f"/api/v3/repos/{snyk_gh_repo['full_name']}"
try:
Expand Down Expand Up @@ -98,7 +107,7 @@ def get_gh_repo_status(snyk_gh_repo, github_token, github_enterprise=False):
repo_owner = ""
repo_name = ""

response_message = "Moved to %s" % repo_name
response_message = f"Moved to {repo_name}"

repo_status = {
"response_code": response.status_code,
Expand Down Expand Up @@ -130,7 +139,7 @@ def is_default_branch_renamed(snyk_gh_repo, new_branch, github_token, github_ent
try:
response = requests.get(url=request_url, allow_redirects=False, headers=headers)

if response.status_code == 301 or response.status_code == 302:
if response.status_code in (301, 302):
print('redirect response url: ' + response.headers["Location"])
if str(response.headers["Location"]).endswith(f"/{new_branch}"):
# print('the redirect is pointing to the new branch')
Expand Down
6 changes: 3 additions & 3 deletions app/snyk_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
get_repo_manifests,
passes_manifest_filter
)
import app.utils.snyk_helper
import app

class SnykRepo():
""" SnykRepo object """
Expand All @@ -33,7 +33,7 @@ def __init__(
self.branch = branch
self.snyk_projects = snyk_projects
def __getitem__(self, item):
return self.full_name
return self.__dict__[item]

def get_projects(self):
""" return list of projects for this repo """
Expand Down Expand Up @@ -107,7 +107,7 @@ def update_branch(self, new_branch_name, dry_run):
for (i, snyk_project) in enumerate(self.snyk_projects):
if snyk_project["branch"] != new_branch_name:
if not dry_run:
sys.stdout.write("\r - %s/%s" % (i+1, len(self.snyk_projects)))
sys.stdout.write(f"\r - {i+1}/{len(self.snyk_projects)}")
sys.stdout.flush()
try:
app.utils.snyk_helper.update_project_branch(snyk_project["id"],
Expand Down
93 changes: 68 additions & 25 deletions app/tests/test_snyk_scm_refresh.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"""test suite for snyk_scm_refresh.py"""
import os
import pytest
from snyk.models import Project
import common
from app.snyk_repo import SnykRepo

from app.gh_repo import (
get_gh_repo_status,
passes_manifest_filter,

)
from app.utils.snyk_helper import get_snyk_projects_for_repo

Expand All @@ -27,53 +29,94 @@ def json(self):
(404, "Not Found", "test_org/test_repo", None, None, "")
],
)
def test_get_gh_repo_status(mocker, status_code, response_message, repo, name, owner, default_branch):
def test_get_gh_repo_status_github(mocker, status_code, response_message, repo, name, owner, default_branch):

# TODO: assumes a successful redirect for the 301 case
mocker.patch(
"requests.get", side_effect=[MockResponse(status_code), MockResponse(200)]
)
mocker.patch.dict(os.environ, {'GITHUB_ENTERPRISE_TOKEN': '1234', 'GITHUB_ENTERPRISE_HOST':common.GITHUB_CLOUD_API_HOST})

snyk_repo_github = SnykRepo(
'new_owner/new_repo',
"1234-5678",
"new_owner",
"12345",
"github",
"master",
[]
)

snyk_repo = {
"full_name": 'new_owner/new_repo',
"owner":'new_owner',
"name": 'new_repo',
"org_id": "1234-5678",
"gh_integration_id": "12345",
"branch_from_name": "",
"branch": "master"
repo_status = {
"response_code": status_code,
"response_message": response_message,
"repo_name": snyk_repo_github["full_name"].split("/")[1],
"snyk_org_id": snyk_repo_github["org_id"],
"repo_owner": snyk_repo_github["full_name"].split("/")[0],
"repo_full_name": snyk_repo_github["full_name"],
"repo_default_branch": default_branch
}

assert get_gh_repo_status(snyk_repo_github) == repo_status

@pytest.mark.parametrize(
"status_code, response_message, repo, name, owner, default_branch",
[
(200, "Match", "test_org/test_repo", "test_repo", "test_owner", "master"),
(301, "Moved to new_repo", "new_owner/new_repo", "new_repo", "new_owner", ""),
(404, "Not Found", "test_org/test_repo", None, None, "")
],
)
def test_get_gh_repo_status_github_enterprise_cloud(mocker, status_code, response_message, repo, name, owner, default_branch):

# TODO: assumes a successful redirect for the 301 case
mocker.patch(
"requests.get", side_effect=[MockResponse(status_code), MockResponse(200)]
)
mocker.patch.dict(os.environ, {'GITHUB_ENTERPRISE_TOKEN': '1234', 'GITHUB_ENTERPRISE_HOST':common.GITHUB_CLOUD_API_HOST})

snyk_repo_github_enterprise = SnykRepo(
'new_owner/new_repo',
"1234-5678",
"new_owner",
"12345",
"github-enterprise",
"master",
[]
)

repo_status = {
"response_code": status_code,
"response_message": response_message,
"repo_name": snyk_repo["name"],
"snyk_org_id": snyk_repo["org_id"],
"repo_owner": snyk_repo["owner"],
"repo_full_name": snyk_repo["full_name"],
"repo_name": snyk_repo_github_enterprise["full_name"].split("/")[1],
"snyk_org_id": snyk_repo_github_enterprise["org_id"],
"repo_owner": snyk_repo_github_enterprise["full_name"].split("/")[0],
"repo_full_name": snyk_repo_github_enterprise["full_name"],
"repo_default_branch": default_branch
}

assert get_gh_repo_status(snyk_repo, "test_token") == repo_status
assert get_gh_repo_status(snyk_repo_github_enterprise) == repo_status

def test_get_gh_repo_status_unauthorized(mocker):
""" test handling unauthorized token """
mocker.patch(
"requests.get", side_effect=[MockResponse(401)]
)

snyk_repo = {
"full_name": 'test_org/test_repo',
"owner":'test_org',
"name": 'test_repo',
"org_id": "1234-5678",
"gh_integration_id": "12345",
"branch_from_name": "",
"branch": "master"
}
mocker.patch.dict(os.environ, {'GITHUB_TOKEN': 'test_token'})

snyk_repo = SnykRepo(
'test_org/test_repo',
"1234-5678",
"new_owner",
"12345",
"github",
"master",
[]
)

with pytest.raises(RuntimeError):
get_gh_repo_status(snyk_repo, "test_token")
get_gh_repo_status(snyk_repo)

def test_get_snyk_project_for_repo():
""" test collecting projects for a repo """
Expand Down
Loading

0 comments on commit 435befe

Please sign in to comment.