diff --git a/README.rst b/README.rst index c23027d..cd7be1f 100644 --- a/README.rst +++ b/README.rst @@ -284,6 +284,17 @@ The tool automatically extracts file extensions from HTTP headers to ensure file **Fine-grained token limitation:** Due to a GitHub platform limitation, fine-grained personal access tokens (``github_pat_...``) cannot download attachments from private repositories directly. This affects both ``/assets/`` (images) and ``/files/`` (documents) URLs. The tool implements a workaround for image attachments using GitHub's Markdown API, which converts URLs to temporary JWT-signed URLs that can be downloaded. However, this workaround only works for images - document attachments (PDFs, text files, etc.) will fail with 404 errors when using fine-grained tokens on private repos. For full attachment support on private repositories, use a classic token (``-t``) instead of a fine-grained token (``-f``). See `#477 `_ for details. +About security advisories +------------------------- + +GitHub security advisories are only available in public repositories. GitHub does not provide the respective API endpoint for private repositories. + +Therefore the logic is implemented as follows: +- Security advisories are included in the `--all` option. +- If only the `--all` option was provided, backups of security advisories are skipped for private repositories. +- If the `--security-advisories` option is provided (on its own or in addition to `--all`), a backup of security advisories is attempted for all repositories, with graceful handling if the GitHub API doesn't return any. + + Run in Docker container ----------------------- diff --git a/github_backup/github_backup.py b/github_backup/github_backup.py index 705f013..346d541 100644 --- a/github_backup/github_backup.py +++ b/github_backup/github_backup.py @@ -1814,7 +1814,7 @@ def backup_repositories(args, output_directory, repositories): if args.include_milestones or args.include_everything: backup_milestones(args, repo_cwd, repository, repos_template) - if args.include_security_advisories or args.include_everything: + if args.include_security_advisories or (args.include_everything and not repository["Private"]): backup_security_advisories(args, repo_cwd, repository, repos_template) if args.include_labels or args.include_everything: @@ -2039,13 +2039,20 @@ def backup_security_advisories(args, repo_cwd, repository, repos_template): return logger.info("Retrieving {0} security advisories".format(repository["full_name"])) - mkdir_p(repo_cwd, advisory_cwd) template = "{0}/{1}/security-advisories".format( repos_template, repository["full_name"] ) - _advisories = retrieve_data(args, template) + try: + _advisories = retrieve_data(args, template) + except Exception as e: + if "404" in str(e): + logger.info("Security advisories are not available for this repository, skipping") + return + raise + + mkdir_p(repo_cwd, advisory_cwd) advisories = {} for advisory in _advisories: