Skip to content

Instantly share code, notes, and snippets.

@xavdid
Last active September 19, 2021 03:40
Show Gist options
  • Save xavdid/f8d89a98d4f791c7b347d73652a47356 to your computer and use it in GitHub Desktop.
Save xavdid/f8d89a98d4f791c7b347d73652a47356 to your computer and use it in GitHub Desktop.
Python script to find ENV_VAR keys on your travis projects
import argparse
import os
from math import ceil
from typing import List
try:
import requests
from requests import HTTPError
except ImportError:
print("This script uses the `requests` package")
print(
"To use it, follow https://docs.python-requests.org/en/latest/user/install/#install"
)
exit(1)
# ARGPARSE
parser = argparse.ArgumentParser(
description="Find TravisCI repos affected by their Sept 2021 security incident"
)
parser.add_argument(
"organization", help="The GitHub organization that owns the repos, like 'zapier'"
)
parser.add_argument(
"--travis-token",
help="A valid TravisCI token. Found at https://app.travis-ci.com/account/preferences. Can also be supplied in the environment as $TRAVIS_TOKEN.",
)
args = parser.parse_args()
# STORE ARGS
org = args.organization
token = args.travis_token or os.environ.get("TRAVIS_TOKEN")
if token is None:
raise ValueError("Missing TravisCI token. Either pass to script or set in env")
req_headers = {"authorization": f"token {token}", "Travis-API-Version": "3"}
# FUNCS
def make_request(url: str, params=None):
response = requests.get(url=url, params=params, headers=req_headers)
try:
response.raise_for_status()
except HTTPError:
if response.status_code != 403:
print(f'Got error: {response.json()["error_message"]}\n')
raise
return response.json()
def get_repos_by_page():
params = {"private": "false", "sort_by": "default_branch.last_build"}
page = make_request(f"https://api.travis-ci.com/owner/{org}/repos", params=params)
print(f"Found {ceil(page['@pagination']['count'] / 100)} pages!\n")
# special case because we'll always do at least 1 page
print(f"Checking page 1...")
yield page["repositories"]
offset = 100
while not page["@pagination"]["is_last"]:
print(f"Checking page {offset // 100 + 1}...")
page = make_request(
f"https://api.travis-ci.com/owner/{org}/repos",
params={**params, "offset": offset},
)
yield page["repositories"]
offset += 100
def get_vars_for_repo(repo_id: int) -> List[str]:
response = make_request(f"https://api.travis-ci.com/repo/github/{repo_id}/env_vars")
return [e["name"] for e in response["env_vars"]]
# MAIN
print(
f'Using TravisCI API to find public CI projects with environment variables in the "{org}" organization\n'
)
result = []
for page in get_repos_by_page():
for repo in page:
var_names = get_vars_for_repo(repo["id"])
if var_names:
result.append(
"\n".join([f'- {repo["name"]}', *[f" - {v}" for v in var_names]])
)
print(f"\n\nFound {len(result)} affected repos:\n")
print("\n\n".join(result))
@shawnzhu
Copy link

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment