qontract-reconcile 0.10.2.dev230__py3-none-any.whl → 0.10.2.dev232__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qontract-reconcile
3
- Version: 0.10.2.dev230
3
+ Version: 0.10.2.dev232
4
4
  Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
5
5
  Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
6
6
  Project-URL: repository, https://github.com/app-sre/qontract-reconcile
@@ -160,7 +160,6 @@ OpenShift templates can be found [here](/openshift/qontract-reconcile.yaml). In
160
160
  github-repo-permissions-validator
161
161
  Validates permissions in github
162
162
  repositories.
163
- github-users Validate compliance of GitHub user profiles.
164
163
  github-validator Validates GitHub organization settings.
165
164
  gitlab-fork-compliance Ensures that forks of App Interface are
166
165
  compliant.
@@ -9,7 +9,7 @@ reconcile/aws_iam_password_reset.py,sha256=O0JX2N5kNRKs3u2xzu4NNrI6p0ag5JWy3MTsv
9
9
  reconcile/aws_support_cases_sos.py,sha256=PDhilxQ4TBxVnxUPIUdTbKEaNUI0wzPiEsB91oHT2fY,3384
10
10
  reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=O1wFp52EyF538c6txaWBs8eMtUIy19gyHZ6VzJ6QXS8,3512
11
11
  reconcile/checkpoint.py,sha256=_JhMxrye5BgkRMxWYuf7Upli6XayPINKSsuo3ynHTRc,5010
12
- reconcile/cli.py,sha256=vrUcahFtsq_yGAzaa1QDyZHbMqMsnsNHzrvW4BiV_xA,114159
12
+ reconcile/cli.py,sha256=bDNLgSAIMkv1zE637ZJSO76nVdfjmhEsTA88jDuX50k,113598
13
13
  reconcile/closedbox_endpoint_monitoring_base.py,sha256=al7m8EgnnYx90rY1REryW3byN_ItfJfAzEeLtjbCfi0,4921
14
14
  reconcile/cluster_deployment_mapper.py,sha256=5gumAaRCcFXsabUJ1dnuUy9WrP_FEEM5JnOnE8ch9sE,2326
15
15
  reconcile/dashdotdb_base.py,sha256=83ZWIf5JJk3P_D69y2TmXRcQr6ELJGlv10OM0h7fJVs,4767
@@ -26,7 +26,6 @@ reconcile/github_org.py,sha256=Wc5cZamatuWsW2ZJT2ib5ps8l3iY3RXHwNUxVJerqz0,14173
26
26
  reconcile/github_owners.py,sha256=viE1KJ-zaTxuZ5yItg2C263J0brn-Q-3hR_DkYDMbhY,3122
27
27
  reconcile/github_repo_invites.py,sha256=U9UCzNVwrZ7MqODtFah8ogH0NNY-XjBin7G9gqHtCUY,2690
28
28
  reconcile/github_repo_permissions_validator.py,sha256=PNqL4dqa2OaNBy-NmLVN-t1HZa6eS6HgSYmfOunYqtA,1798
29
- reconcile/github_users.py,sha256=ZeYNMyvZPVMx6mh5TiKEUQy4W1uw3VmUZOHiXus5I0Y,5073
30
29
  reconcile/github_validator.py,sha256=-j17tn3csFVjPMSPL3te48iWVkPZCncRXdeKeLdGjjQ,931
31
30
  reconcile/gitlab_fork_compliance.py,sha256=RbHckzLnE9zkOFHJANzoejEMMbMAivmqJVs3Suvp9lU,4591
32
31
  reconcile/gitlab_housekeeping.py,sha256=JEnerWbirICkJQy91ZVepcHge2XWrVUazfIeKnZ94ZQ,26345
@@ -612,7 +611,7 @@ reconcile/utils/external_resources.py,sha256=YzTb0xAcNdmKO326mGQy7BmST56CZcdru4l
612
611
  reconcile/utils/filtering.py,sha256=S4PbMHuFr3ED0P2Q_ea5CAaB7FimI62B-F5YTaKrphA,402
613
612
  reconcile/utils/git.py,sha256=o4p9m8jlzCJDcutl2HErvGLhL6sZ1NB4Aw3zGcQIzso,2427
614
613
  reconcile/utils/github_api.py,sha256=S1vO-hvYPzm5BIychVIHSYibMns0HBmLgS78MkPfunE,3402
615
- reconcile/utils/gitlab_api.py,sha256=-wf1praBpU9h4TratCnAPBHEYgYJZLib6dl6Nszzrrw,28761
614
+ reconcile/utils/gitlab_api.py,sha256=4-DG5wV7k0jSl4Yp4ELQbp3qJY6uYuHukiZJ5tYkhCM,28648
616
615
  reconcile/utils/gpg.py,sha256=EKG7_fdMv8BMlV5yUdPiqoTx-KrzmVSEAl2sLkaKwWI,1123
617
616
  reconcile/utils/gql.py,sha256=C0thIm_k9MBldfqwHzyqtYZk9sIvMdm9IbbnXLGwjD8,14158
618
617
  reconcile/utils/grouping.py,sha256=vr9SFHZ7bqmHYrvYcEZt-Er3-yQYfAAdq5sHLZVmXPY,456
@@ -662,7 +661,6 @@ reconcile/utils/smtp_client.py,sha256=0xefB4I9E5eBB-FlxFJYjvz3Kvuqi_K3Ma_Wk0NAQK
662
661
  reconcile/utils/sqs_gateway.py,sha256=XNIf3PY4UCPNufP2Ul0UJj3fKlt5larBba-VTT-41Fg,2265
663
662
  reconcile/utils/state.py,sha256=az4tBmZ0EdbFcAGiBVUxs3cr2-BVWsuDQiNTvjjQq8s,16378
664
663
  reconcile/utils/structs.py,sha256=LcbLEg8WxfRqM6nW7NhcWN0YeqF7SQzxOgntmLs1SgY,352
665
- reconcile/utils/template.py,sha256=wTvRU4AnAV_o042tD4Mwls2dwWMuk7MKnde3MaCjaYg,331
666
664
  reconcile/utils/terraform_client.py,sha256=IDlrNvGEc2i6ElZIL_fzaJEad1nRC3DkP9_VXhJXmU0,37329
667
665
  reconcile/utils/terrascript_aws_client.py,sha256=RkiYjRietHFNXtfA1-WEZ1lZbJFBA_XCtTOsZUij5VM,292360
668
666
  reconcile/utils/three_way_diff_strategy.py,sha256=oQcHXd9LVhirJfoaOBoHUYuZVGfyL2voKr6KVI34zZE,4833
@@ -700,7 +698,7 @@ reconcile/utils/internal_groups/models.py,sha256=y_IqBVqfGqNXiu0VudvBWFrm_-uafVm
700
698
  reconcile/utils/jinja2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
701
699
  reconcile/utils/jinja2/extensions.py,sha256=7K-uo6G2eCWa98MHT8fRPYIKCLQB_5D2keqQ_LyAfHM,1293
702
700
  reconcile/utils/jinja2/filters.py,sha256=JfO_14APySBPidsMvHXG-8dULNPddZCE15Umjk_aSBk,4830
703
- reconcile/utils/jinja2/utils.py,sha256=UTA0oOdhUgUBY57lWxgJS9WIAzP1ONm7mgGhY_DrczM,8821
701
+ reconcile/utils/jinja2/utils.py,sha256=1ucq5RHn9BV6bLvu9L6ji1X7Aus61Y6kU9HU-UicXfk,9053
704
702
  reconcile/utils/jobcontroller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
705
703
  reconcile/utils/jobcontroller/controller.py,sha256=Vh08lZuCSIIceWGSDhBB00iFwTI9eeKZW1sfHlkAvSo,15373
706
704
  reconcile/utils/jobcontroller/models.py,sha256=x9YIvWfYOOvXNKToFVx1H7qDrZb0Sa1KI_4Y0gl7rMM,6336
@@ -803,7 +801,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
803
801
  tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
804
802
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
805
803
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
806
- qontract_reconcile-0.10.2.dev230.dist-info/METADATA,sha256=dkDDpJd-ycaLjY3mepy5DzTOq2liq8Z86xkeu8NjVhM,24431
807
- qontract_reconcile-0.10.2.dev230.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
808
- qontract_reconcile-0.10.2.dev230.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
809
- qontract_reconcile-0.10.2.dev230.dist-info/RECORD,,
804
+ qontract_reconcile-0.10.2.dev232.dist-info/METADATA,sha256=tnLkovENBUt8KdPD7fs4Sr3JJweV3mXEbw0IrFobGy4,24352
805
+ qontract_reconcile-0.10.2.dev232.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
806
+ qontract_reconcile-0.10.2.dev232.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
807
+ qontract_reconcile-0.10.2.dev232.dist-info/RECORD,,
reconcile/cli.py CHANGED
@@ -759,31 +759,6 @@ def github_owners(ctx: click.Context) -> None:
759
759
  run_integration(reconcile.github_owners, ctx)
760
760
 
761
761
 
762
- @integration.command(short_help="Validate compliance of GitHub user profiles.")
763
- @gitlab_project_id
764
- @threaded()
765
- @enable_deletion(default=False)
766
- @send_mails(default=False)
767
- @click.pass_context
768
- def github_users(
769
- ctx: click.Context,
770
- gitlab_project_id: str | None,
771
- thread_pool_size: int,
772
- enable_deletion: bool,
773
- send_mails: bool,
774
- ) -> None:
775
- import reconcile.github_users
776
-
777
- run_integration(
778
- reconcile.github_users,
779
- ctx,
780
- gitlab_project_id,
781
- thread_pool_size,
782
- enable_deletion,
783
- send_mails,
784
- )
785
-
786
-
787
762
  @integration.command(short_help="Validates GitHub organization settings.")
788
763
  @click.pass_context
789
764
  def github_validator(ctx: click.Context) -> None:
@@ -298,16 +298,15 @@ class GitLabApi:
298
298
 
299
299
  @staticmethod
300
300
  def _is_bot_username(username: str) -> bool:
301
- """crudely checking for the username
302
-
303
- as gitlab-python require a major upgrade to use the billable members apis
304
- https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#id11 lists the api
305
- billable_membersis the attribute that provides billable members of groups
301
+ """
302
+ Checks if a given username matches the pattern for an internal GitLab bot user.
306
303
 
307
- the second api is https://python-gitlab.readthedocs.io/en/stable/gl_objects/group_access_tokens.html
308
- which provides a list of access tokens as well as their assigned users
304
+ This method uses a regular expression (GROUP_BOT_NAME_REGEX) to determine
305
+ if the username conforms to the naming convention for internal GitLab bots,
306
+ as described in the GitLab documentation.
309
307
 
310
- those apis are not avaliable in python-gitlab v1.x
308
+ Reference:
309
+ - GitLab Internal Users Documentation: https://docs.gitlab.com/administration/internal_users/
311
310
  """
312
311
  return GROUP_BOT_NAME_REGEX.match(username) is not None
313
312
 
@@ -1,15 +1,17 @@
1
1
  import datetime
2
+ import os
2
3
  from functools import cache
3
4
  from typing import Any, Self
4
5
 
5
6
  import jinja2
7
+ from github import Github
6
8
  from jinja2.sandbox import SandboxedEnvironment
7
9
  from pydantic import BaseModel
8
10
  from sretoolbox.utils import retry
9
11
 
10
12
  from reconcile import queries
11
13
  from reconcile.checkpoint import url_makes_sense
12
- from reconcile.github_users import init_github
14
+ from reconcile.github_org import get_default_config
13
15
  from reconcile.utils import gql
14
16
  from reconcile.utils.aws_api import AWSApi
15
17
  from reconcile.utils.github_api import GithubRepositoryApi
@@ -97,6 +99,14 @@ def compile_jinja2_template(
97
99
  return jinja_env.from_string(body)
98
100
 
99
101
 
102
+ GH_BASE_URL = os.environ.get("GITHUB_API", "https://api.github.com")
103
+
104
+
105
+ def init_github() -> Github:
106
+ token = get_default_config()["token"]
107
+ return Github(token, base_url=GH_BASE_URL)
108
+
109
+
100
110
  def lookup_github_file_content(
101
111
  repo: str,
102
112
  path: str,
reconcile/github_users.py DELETED
@@ -1,158 +0,0 @@
1
- import logging
2
- import os
3
- import re
4
- from collections import defaultdict
5
- from collections.abc import Callable
6
-
7
- from github import Github
8
- from github.GithubException import GithubException
9
- from requests.exceptions import ReadTimeout
10
- from sretoolbox.utils import (
11
- retry,
12
- threaded,
13
- )
14
-
15
- from reconcile import (
16
- mr_client_gateway,
17
- queries,
18
- typed_queries,
19
- )
20
- from reconcile.github_org import get_default_config
21
- from reconcile.utils.defer import defer
22
- from reconcile.utils.mr import CreateDeleteUserAppInterface
23
- from reconcile.utils.mr.user_maintenance import PathSpec, PathTypes
24
- from reconcile.utils.secret_reader import SecretReader
25
- from reconcile.utils.smtp_client import (
26
- DEFAULT_SMTP_TIMEOUT,
27
- SmtpClient,
28
- get_smtp_server_connection,
29
- )
30
-
31
- GH_BASE_URL = os.environ.get("GITHUB_API", "https://api.github.com")
32
-
33
- QONTRACT_INTEGRATION = "github-users"
34
-
35
- UserAndCompany = tuple[str, str | None]
36
-
37
-
38
- def init_github() -> Github:
39
- token = get_default_config()["token"]
40
- return Github(token, base_url=GH_BASE_URL)
41
-
42
-
43
- def init_users_and_paths() -> list[dict[str, list]]:
44
- app_int_users = queries.get_users(refs=True)
45
-
46
- users = defaultdict(list)
47
- for user in app_int_users:
48
- u = user["org_username"]
49
- item = PathSpec(type=PathTypes.USER, path=user["path"])
50
- users[u].append(item)
51
- for r in user.get("requests"):
52
- item = PathSpec(type=PathTypes.REQUEST, path=r["path"])
53
- users[u].append(item)
54
- for q in user.get("queries"):
55
- item = PathSpec(type=PathTypes.QUERY, path=q["path"])
56
- users[u].append(item)
57
- for g in user.get("gabi_instances"):
58
- item = PathSpec(type=PathTypes.GABI, path=g["path"])
59
- users[u].append(item)
60
- for a in user.get("aws_accounts", []):
61
- item = PathSpec(type=PathTypes.AWS_ACCOUNTS, path=a["path"])
62
- users[u].append(item)
63
- for s in user.get("schedules"):
64
- item = PathSpec(type=PathTypes.SCHEDULE, path=s["path"])
65
- users[u].append(item)
66
-
67
- return [{"username": username, "paths": paths} for username, paths in users.items()]
68
-
69
-
70
- @retry(exceptions=(GithubException, ReadTimeout))
71
- def get_user_company(user: dict, github: Github) -> UserAndCompany:
72
- gh_user = github.get_user(login=user["github_username"])
73
- return user["org_username"], gh_user.company
74
-
75
-
76
- def get_users_to_delete(results: list[UserAndCompany]) -> list[dict]:
77
- pattern = r"^.*[Rr]ed ?[Hh]at.*$"
78
- org_usernames_to_delete = [
79
- u for u, c in results if c is None or not re.search(pattern, c)
80
- ]
81
- users_and_paths = init_users_and_paths()
82
- return [u for u in users_and_paths if u["username"] in org_usernames_to_delete]
83
-
84
-
85
- def send_email_notification(user: dict, smtp_client: SmtpClient) -> None:
86
- msg_template = """
87
- Hello,
88
-
89
- This is an automated message coming from App-Interface.
90
-
91
- The App SRE team adheres to the OpenShift GitHub policy:
92
- https://mojo.redhat.com/docs/DOC-1200784
93
-
94
- Your GitHub profile does not comply with the following requirements:
95
-
96
- - Company field should contain "Red Hat".
97
-
98
-
99
- For any questions, please ping @app-sre-ic on #sd-app-sre in CoreOS Slack,
100
- or mail us at sd-app-sre@redhat.com.
101
-
102
- App-Interface repository: https://gitlab.cee.redhat.com/service/app-interface
103
-
104
- """
105
- to = user["username"]
106
- subject = "App-Interface compliance - GitHub profile"
107
- body = msg_template
108
- smtp_client.send_mail([to], subject, body)
109
-
110
-
111
- @defer
112
- def run(
113
- dry_run: bool,
114
- gitlab_project_id: str | None = None,
115
- thread_pool_size: int = 10,
116
- enable_deletion: bool = False,
117
- send_mails: bool = False,
118
- defer: Callable | None = None,
119
- ) -> None:
120
- smtp_settings = typed_queries.smtp.settings()
121
- smtp_client = SmtpClient(
122
- server=get_smtp_server_connection(
123
- secret_reader=SecretReader(settings=queries.get_secret_reader_settings()),
124
- secret=smtp_settings.credentials,
125
- ),
126
- mail_address=smtp_settings.mail_address,
127
- timeout=smtp_settings.timeout or DEFAULT_SMTP_TIMEOUT,
128
- )
129
- users = queries.get_users()
130
- g = init_github()
131
-
132
- results = threaded.run(get_user_company, users, thread_pool_size, github=g)
133
-
134
- users_to_delete = get_users_to_delete(results)
135
-
136
- if not dry_run and enable_deletion:
137
- mr_cli = mr_client_gateway.init(gitlab_project_id=gitlab_project_id)
138
- if defer:
139
- defer(mr_cli.cleanup)
140
-
141
- for user in users_to_delete:
142
- username = user["username"]
143
- paths = user["paths"]
144
- logging.info(["delete_user", username])
145
-
146
- if not dry_run:
147
- if send_mails:
148
- send_email_notification(user, smtp_client)
149
- elif enable_deletion:
150
- mr = CreateDeleteUserAppInterface(username, paths)
151
- mr.submit(cli=mr_cli)
152
- else:
153
- msg = (
154
- "'delete' action is not enabled. "
155
- "Please run the integration manually "
156
- "with the '--enable-deletion' flag."
157
- )
158
- logging.warning(msg)
@@ -1,12 +0,0 @@
1
- import os
2
-
3
- import jinja2
4
-
5
- from reconcile import templates
6
-
7
-
8
- def get_package_environment():
9
- """Loads templates from the current Python package"""
10
- templates_dir = os.path.dirname(templates.__file__)
11
- template_loader = jinja2.FileSystemLoader(searchpath=templates_dir)
12
- return jinja2.Environment(loader=template_loader)