get_org_dsns 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. #!/usr/bin/env python
  2. from __future__ import annotations
  3. from gzip import GzipFile
  4. from http.client import HTTPResponse, HTTPSConnection
  5. from io import BytesIO
  6. from time import time
  7. from typing import Any
  8. from urllib.parse import urlencode
  9. import click
  10. from sentry.utils import json
  11. @click.command(
  12. help="Gets all of the DSNs for an organization, grouped by project. 'Secret' DSNs are omitted."
  13. )
  14. @click.option(
  15. "--slug",
  16. required=True,
  17. help="The org slug for which we are pulling all of the DSNs.",
  18. )
  19. @click.option(
  20. "--api",
  21. required=True,
  22. help="The Sentry instance (DE, US, or single-tenant) to hit for the api. Ex: `de.sentry.io`.",
  23. )
  24. @click.option(
  25. "--cookie",
  26. required=True,
  27. help="The superadmin cookie, copied verbatim.",
  28. )
  29. def get_all_project_dsns_for_org(slug, api, cookie):
  30. # Setup the connection.
  31. conn = HTTPSConnection(api)
  32. headers = make_headers(cookie)
  33. heartbeat = int(time())
  34. # Get all of the project slugs, then get keys for each slug.
  35. keys_by_slug: dict[str, list[str]] = {}
  36. proj_slugs = sorted(get_all_projects_for_org(conn, slug, api, cookie))
  37. for proj_slug in proj_slugs:
  38. t = int(time())
  39. if t - heartbeat > 5:
  40. heartbeat = t
  41. print(f"{len(keys_by_slug)} of {len(proj_slugs)} DSN sets downloaded...")
  42. endpoint = f"/api/0/projects/{slug}/{proj_slug}/keys/"
  43. conn.request("GET", f"https://{api}{endpoint}", headers=headers)
  44. response = conn.getresponse()
  45. if response.code != 200:
  46. raise Exception(f"keys endpoint returned a non-2XX response: {response.reason}")
  47. json_data = maybe_unzip(response)
  48. if not isinstance(json_data, list):
  49. raise Exception("Hmmm, the response from the call to the keys endpoint wasn't a list?")
  50. keys_by_slug[proj_slug] = {
  51. v["label"]: v["dsn"]["public"] for v in json_data if v["isActive"]
  52. }
  53. print("\n\n\n")
  54. print(keys_by_slug)
  55. def make_headers(cookie: str) -> dict[str, str]:
  56. return {
  57. "Accept": "application/json; charset=utf-8",
  58. "Accept-Encoding": "gzip, deflate, br, zstd",
  59. "Accept-Language": "en-US,en;q=0.9",
  60. "Cache-Control": "no-cache",
  61. "Content-Type": "application/json",
  62. "Cookie": cookie,
  63. "Pragma": "no-cache",
  64. "Priority": "u=1, i",
  65. "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
  66. }
  67. def maybe_unzip(response: HTTPResponse) -> Any:
  68. data = response.read()
  69. if response.getheader("Content-Encoding") == "gzip":
  70. with GzipFile(fileobj=BytesIO(data)) as gz:
  71. decompressed_data = gz.read()
  72. return json.loads(decompressed_data.decode("utf-8"))
  73. return json.loads(data.decode("utf-8"))
  74. def get_all_projects_for_org(conn: HTTPSConnection, slug: str, api: str, cookie: str) -> list[str]:
  75. """
  76. Paginate through the entire list of projects for the org, pulling down the project slugs.
  77. """
  78. # Set inputs
  79. base_url = f"https://{api}"
  80. endpoint = f"/api/0/organizations/{slug}/projects/"
  81. query_params = {"all_projects": 1}
  82. full_url = f"{base_url}{endpoint}?{urlencode(query_params)}"
  83. # Make the underlying request, and load it into JSON.
  84. conn.request("GET", full_url, headers=make_headers(cookie))
  85. response = conn.getresponse()
  86. if response.code != 200:
  87. raise Exception(f"projects endpoint returned a non-2XX response: {response.reason}")
  88. json_data = maybe_unzip(response)
  89. if not isinstance(json_data, list):
  90. raise Exception("Hmmm, the response from the call to the projects endpoint wasn't a list?")
  91. return [proj["slug"] for proj in json_data]
  92. if __name__ == "__main__":
  93. get_all_project_dsns_for_org()