import requests import os import sys import pathlib import logging import yaml from typing import Mapping, Iterable from collections import defaultdict logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') auth_token = os.environ.get('TOKEN', '') session = requests.session() session.headers = { 'Authorization': f'Bearer {auth_token}', 'Origin': 'https://hub.docker.com', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36', 'X-DOCKER-API-CLIENT': 'docker-hub/v3012.0.0', } base = pathlib.Path(__file__).parent.parent.parent.absolute() template = '''# Vulhub image for {placeholder_name} ## Image Description Vulhub is an open-source collection of pre-built vulnerable docker environments. No pre-existing knowledge of docker is required, just execute two simple commands and you have a vulnerable environment. This image is one of the environment of Vulhub project. Please see the [USER MANUAL](https://github.com/vulhub/vulhub) from the Vulhub project to see more detail. ## Usage Do not use this image directly, use it through [docker compose](https://docs.docker.com/compose/). ``` docker compose up -d ``` Following environments are using this image, you can find the `docker-compose.yml` file on these folders: {placeholder_vulns_block} ## Quick reference - **Maintained by**
[phith0n](https://github.com/phith0n) and other contributors from [Vulhub](https://github.com/vulhub) - **Where to get help:**
[Github Issues](https://github.com/vulhub/vulhub/issues) - **Which environments do this image be used:**
{placeholder_vulns_inline} ## License Because Vulhub is packaged with other software, please refer to the software license for the software inside the Vulhub image. Vulhub's own code is open source based on the [MIT license](https://github.com/vulhub/vulhub/blob/master/LICENSE). As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies with any relevant licenses for all software contained within. ''' def prepare_vulhub() -> Mapping: vulhub = defaultdict(list) for f in base.rglob("docker-compose.yml"): start = len(str(base.absolute())) + 1 end = len(str(f.absolute())) - 18 - 1 vuln_path = str(f.absolute())[start:end].replace('\\', '/') compose = yaml.safe_load(f.read_bytes()) for service_name, array in compose['services'].items(): if 'image' not in array: continue image_name = array['image'] if ':' in image_name: image_name, _ = image_name.split(':') if image_name.startswith('vulhub/'): vulhub[image_name].append(vuln_path) return vulhub def build_readme(name, vulns: Iterable): envs = [] for vuln in vulns: envs.append(f'[{vuln}](https://github.com/vulhub/vulhub/tree/master/{vuln})') return template\ .replace('{placeholder_name}', name)\ .replace('{placeholder_vulns_block}', '\n'.join([f'- {v}' for v in envs]))\ .replace('{placeholder_vulns_inline}', ', '.join(envs)) def list_all_repository(): response = session.get('https://hub.docker.com/v2/repositories/vulhub?page_size=200&ordering=last_updated') data = response.json() if response.status_code != 200 or data.get('error', None): raise Exception('authentication error') for obj in data['results']: yield f"{obj['namespace']}/{obj['name']}" def update_description(name, vulns): response = session.patch(f'https://hub.docker.com/v2/repositories/{name}/', json={ 'full_description': build_readme(name, vulns) }, headers={ 'Content-Type': 'application/json' }) if response.status_code != 200: raise Exception(f'update readme for {name} failed, status code = {response.status_code}, response text = {response.text}') def main(): try: vuln = prepare_vulhub() for name in list_all_repository(): update_description(name, vuln.get(name, [])) logging.info("Success to update readme for %s", name) except Exception as e: logging.error("error: %r", e, exc_info=True) if __name__ == '__main__': main()