{"id":19652669,"url":"https://github.com/advanced-security/ghas-to-csv","last_synced_at":"2026-01-15T22:18:56.567Z","repository":{"id":37793283,"uuid":"479213922","full_name":"advanced-security/ghas-to-csv","owner":"advanced-security","description":"Play with GHAS API to provide posture data over time","archived":false,"fork":false,"pushed_at":"2026-01-09T00:03:28.000Z","size":373,"stargazers_count":40,"open_issues_count":2,"forks_count":18,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-13T04:11:36.434Z","etag":null,"topics":["csv","github-actions","github-advanced-security"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/advanced-security.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-04-08T02:14:39.000Z","updated_at":"2026-01-09T00:01:28.000Z","dependencies_parsed_at":"2026-01-12T07:07:39.648Z","dependency_job_id":null,"html_url":"https://github.com/advanced-security/ghas-to-csv","commit_stats":{"total_commits":53,"total_committers":6,"mean_commits":8.833333333333334,"dds":0.3584905660377359,"last_synced_commit":"a579e1ad15c6154756b77bebc652f76bfb4d3e2c"},"previous_names":["some-natalie/ghas-to-csv"],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/advanced-security/ghas-to-csv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fghas-to-csv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fghas-to-csv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fghas-to-csv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fghas-to-csv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/advanced-security","download_url":"https://codeload.github.com/advanced-security/ghas-to-csv/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fghas-to-csv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28472626,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-15T22:13:38.078Z","status":"ssl_error","status_checked_at":"2026-01-15T22:12:11.737Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csv","github-actions","github-advanced-security"],"created_at":"2024-11-11T15:11:41.955Z","updated_at":"2026-01-15T22:18:56.539Z","avatar_url":"https://github.com/advanced-security.png","language":"Python","funding_links":[],"categories":["others"],"sub_categories":[],"readme":"# GitHub Advanced Security to CSV\n\nSimple GitHub Action to scrape the GitHub Advanced Security API and shove it into a CSV.\n\n\u003e **Note**\n\u003e\n\u003e You need to set and store a PAT because the built-in `GITHUB_TOKEN` doesn't have the appropriate permissions for this Action to get all of the alerts.\n\n## What?\n\nGitHub Advanced Security can compile a _ton_ of information on the vulnerabilities in your project's [code](https://github.com/features/security/code), [supply chain](https://github.com/features/security/software-supply-chain), and any [secrets](https://docs.github.com/en/enterprise-cloud@latest/code-security/secret-scanning/about-secret-scanning) (like API keys or other sensitive info) that might have been accidentally exposed.  That information is surfaced in the repository, organization, or enterprise [security overview](https://docs.github.com/en/enterprise-cloud@latest/code-security/security-overview/about-the-security-overview) and the API.  The overview has all sorts of neat filters and such you can play with.  The API is great and powers all manner of partner integrations, but there's no direct CSV export.\n\nThe API changes a bit based on the version of GitHub you're using.  This Action gathers the GitHub API endpoint to use from the runner's [environment variables](https://docs.github.com/en/enterprise-cloud@latest/actions/learn-github-actions/environment-variables#default-environment-variables), so as long as you have a license for Advanced Security, this should work as expected in GitHub Enterprise Server and GitHub AE too.\n\n## Why?\n\nBecause I really want to see this data as a time-series to understand it, and [Flat Data](https://next.github.com/projects/flat-data/) doesn't support paginated APIs (yet?) ... so ... it's really an experiment and I wanted to play around with the shiny new toy.\n\nAlso ... CSV files are the dead-simple ingest point for a ton of other software services you might ~~want~~ have to use in business.  And some people just like CSV files and want to do things in spreadsheets and I'm not here to judge that.  Shine on, you spreadsheet gurus! :sparkles:\n\n## How?\n\nThis got a little more complicated than I'd like, but the tl;dr of what I'm trying to figure out is below:\n\n```mermaid\ngraph TD\n    A(GitHub API) --\u003e|this Action| B(fa:fa-file-csv CSV files)\n    B --\u003e|actions/upload-artifact| C(fa:fa-github GitHub)\n    C --\u003e|download| D(fa:fa-file-csv CSV files)\n    C --\u003e|flat-data| E(fa:fa-chart-line data awesomeness)\n```\n\nObviously if you're only wanting the CSV file, run this thing, then download the artifact.  It's a zip file with the CSV file(s).  You're ready to rock and roll. :smile:\n\nAn example of use is below.  Note that the custom inputs, such as if you are wanting data on a different repo and need additional scopes for that, are set as environmental variables:\n\n```yaml\n      - name: CSV export\n        uses: advanced-security/ghas-to-csv@v3\n        env:\n          GITHUB_PAT: ${{ secrets.PAT }}  # you need to set a PAT\n      - name: Upload CSV\n        uses: actions/upload-artifact@v4\n        with:\n          name: ghas-data\n          path: ${{ github.workspace }}/*.csv\n          if-no-files-found: error\n```\n\nTo run this targeting an organization, here's an example:\n\n```yaml\n      - name: CSV export\n        uses: advanced-security/ghas-to-csv@v3\n        env:\n          GITHUB_PAT: ${{ secrets.PAT }}\n          GITHUB_REPORT_SCOPE: \"organization\"\n          SCOPE_NAME: \"org-name-goes-here\"\n```\n\nOr for an enterprise:\n\n```yaml\n      - name: CSV export\n        uses: advanced-security/ghas-to-csv@v3\n        env:\n          GITHUB_PAT: ${{ secrets.PAT }}\n          GITHUB_REPORT_SCOPE: \"enterprise\"\n          SCOPE_NAME: \"enterprise-slug-goes-here\"\n```\n\nThe list of all available options that can be set as environmental variables is below:\n\n- `GITHUB_API_URL`: The URL of the GitHub API. Default value: `https://api.github.com`.\n- `GITHUB_SERVER_URL`: The URL of the GitHub server. Default value: `https://github.com`.\n- `GITHUB_PAT` or `GITHUB_TOKEN`: The personal access token (PAT) or token for authenticating with the GitHub API. If `GITHUB_PAT` is not set, the value of `GITHUB_TOKEN` is used if it is set. If neither is set, an error occurs.\n- `GITHUB_REPORT_SCOPE`: The scope of the report to generate. Valid values are `repository` (default), `organization`  or `enterprise`.\n- `SCOPE_NAME` or `GITHUB_REPOSITORY`: The name of the repository, organization or enterprise to generate the report for. If `SCOPE_NAME` is not set, the value of `GITHUB_REPOSITORY` is used if it is set. If neither is set, an error occurs.\n- `FEATURES`: A comma-separated list of features to include in the report. Valid values are `codescanning`, `secretscanning`, `dependabot` or simply `all`. Default value: `all`.\n\nThe first two are only needed if you're running this in a GitHub Enterprise Server or GitHub AE environment.  The last one is useful if you only want to get data on a specific feature.  For example, if you only want to get data on secret scanning, you can set `FEATURES` to `secretscanning`. Here's just another example how you would configure this on a GitHub Enterprise Server:\n\n```yaml\n      - name: CSV export\n        uses: advanced-security/ghas-to-csv@v3\n        env:\n          GITHUB_PAT: ${{ secrets.PAT }}\n          GITHUB_API_URL: \"https://github.example.com/api/v3\"\n          GITHUB_SERVER_URL: \"https://github.example.com\"\n          GITHUB_REPORT_SCOPE: \"enterprise\"\n          SCOPE_NAME: \"enterprise-slug-goes-here\"\n          FEATURES: \"secretscanning,codescanning\"\n```\n\n## Reporting\n\n|   | GitHub Enterprise Cloud | GitHub Enterprise Server (3.5+) | GitHub AE (M2) | Notes |\n| --- | --- | --- | --- | --- |\n| Secret scanning | :white_check_mark: Repo\u003cbr\u003e:white_check_mark: Org\u003cbr\u003e:white_check_mark: Enterprise |  :white_check_mark: Repo\u003cbr\u003e:white_check_mark: Org\u003cbr\u003e:white_check_mark: Enterprise | :white_check_mark: Repo\u003cbr\u003e:x: Org\u003cbr\u003e:x: Enterprise | [API docs](https://docs.github.com/en/enterprise-cloud@latest/rest/reference/secret-scanning) |\n| Code scanning |  :white_check_mark: Repo\u003cbr\u003e:white_check_mark: Org\u003cbr\u003e:white_check_mark: Enterprise | :white_check_mark: Repo\u003cbr\u003e:white_check_mark: Org\u003cbr\u003e:curly_loop: Enterprise (3.5, 3.6) \u003cbr\u003e:white_check_mark: Enterprise (3.7+) |  :white_check_mark: Repo\u003cbr\u003e:x: Org\u003cbr\u003e:curly_loop: Enterprise | [API docs](https://docs.github.com/en/enterprise-cloud@latest/rest/reference/code-scanning) |\n| Dependabot | :white_check_mark: Repo\u003cbr\u003e:white_check_mark: Org\u003cbr\u003e:white_check_mark: Enterprise | :white_check_mark: Repo (3.8+)\u003cbr\u003e:white_check_mark: Org (3.8+)\u003cbr\u003e:white_check_mark: Enterprise (3.8+)  | :x: | [API docs](https://docs.github.com/en/enterprise-cloud@latest/rest/dependabot/alerts) |\n\n:information_source:  All of this reporting requires either public repositories or a GitHub Advanced Security license.\n\n:information_source:  Any item with a :curly_loop: needs some looping logic, since repositories are supported and not higher-level ownership (like orgs or enterprises).  How this looks won't differ much between GHAE or GHES.  In both cases, you'll need an enterprise admin PAT to access the `all_organizations.csv` or `all_repositories.csv` report from `stafftools/reports`, then looping over it in the appropriate scope.  That will tell you about the existence of everything, but not give you permission to access it.  To do that, you'll need to use `ghe-org-admin-promote` in GHES ([link](https://docs.github.com/en/enterprise-server@latest/admin/configuration/configuring-your-enterprise/command-line-utilities#ghe-org-admin-promote)) to own all organizations within the server.\n\n## Using this with Flat Data\n\nWhy?  Because look at this beautiful [viewer](https://flatgithub.com).  It's so nice to have a working time-series data set without a ton of drama.\n\n![flat-viewer](images/flat-viewer.png)\n\nThis gets a little tricky because Flat doesn't support scraping paginated APIs or importing from a local file, so here's an example workflow that loads the data through a GitHub Actions runner.\n\n```yaml\nname: Gather data for Flat Data\non:\n  schedule:\n    - cron: '30 22 * * 1'  # Weekly at 22:30 UTC on Mondays\njobs:\n  data_gathering:\n    runs-on: ubuntu-latest\n    steps:\n      - name: CSV export\n        uses: advanced-security/ghas-to-csv@v3\n        env:\n          GITHUB_PAT: ${{ secrets.PAT }}  # needed if not running against the current repository\n          SCOPE_NAME: \"OWNER-NAME/REPO-NAME\"  # repository name, needed only if not running against the current repository\n      - name: Upload CSV\n        uses: actions/upload-artifact@v4\n        with:\n          name: ghas-data\n          path: ${{ github.workspace }}/*.csv\n          if-no-files-found: error\n  flat_data:\n    runs-on: ubuntu-latest\n    needs: [data_gathering]\n    steps:\n      - name: Check out repo\n        uses: actions/checkout@v3\n      - name: Download CSVs\n        uses: actions/download-artifact@v4\n        with:\n          name: ghas-data\n      - name: Tiny http server moment  # Flat can only use HTTP or SQL, so ... yeah.\n        run: |\n          docker run -d -p 8000:80 --read-only -v $(pwd)/nginx-cache:/var/cache/nginx -v $(pwd)/nginx-pid:/var/run -v $(pwd):/usr/share/nginx/html:ro nginx\n          sleep 10\n      - name: Flat the code scanning alerts\n        uses: githubocto/flat@v3\n        with:\n          http_url: http://localhost:8000/cs_list.csv\n          downloaded_filename: cs_list.csv\n      - name: Flat the secret scanning alerts\n        uses: githubocto/flat@v3\n        with:\n          http_url: http://localhost:8000/secrets_list.csv\n          downloaded_filename: secrets_list.csv\n```\n\n:information_source:  You may want to append what's below to the repository's `.gitignore` file to ignore the pid directory created by nginx.\n\n```gitignore\nnginx-pid/\n```\n\n## But it doesn't do THIS THING\n\nThe API docs are [here](https://docs.github.com/en/enterprise-cloud@latest) and pull requests are welcome! :heart:.\nSee [CONTRIBUTING](CONTRIBUTING.md) for more information.\n\n## Other notes\n\n[GitHub Copilot](https://copilot.github.com/) wrote most of the Python code in this project.  I mostly just structured the files/functions, wrote some docstrings, accounted for the differences in API versions across the products, and edited what it gave me. :heart:\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadvanced-security%2Fghas-to-csv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadvanced-security%2Fghas-to-csv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadvanced-security%2Fghas-to-csv/lists"}