roksta 0.3.2__cp311-cp311-macosx_10_9_universal2.whl → 0.3.8__cp311-cp311-macosx_10_9_universal2.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.
Files changed (131) hide show
  1. roksta/__init__.cpython-311-darwin.so +0 -0
  2. roksta/ai/__init__.cpython-311-darwin.so +0 -0
  3. roksta/ai/call_ai.cpython-311-darwin.so +0 -0
  4. roksta/ai/gemini.cpython-311-darwin.so +0 -0
  5. roksta/ai/generic.cpython-311-darwin.so +0 -0
  6. roksta/ai/llm.cpython-311-darwin.so +0 -0
  7. roksta/ai/openai.cpython-311-darwin.so +0 -0
  8. roksta/ai/tools/__init__.cpython-311-darwin.so +0 -0
  9. roksta/ai/tools/delete_file.cpython-311-darwin.so +0 -0
  10. roksta/ai/tools/edit_file.cpython-311-darwin.so +0 -0
  11. roksta/ai/tools/final_response.cpython-311-darwin.so +0 -0
  12. roksta/ai/tools/get_file_summaries.cpython-311-darwin.so +0 -0
  13. roksta/ai/tools/read_file.cpython-311-darwin.so +0 -0
  14. roksta/ai/tools/regex_replace.cpython-311-darwin.so +0 -0
  15. roksta/ai/tools/shell_any.cpython-311-darwin.so +0 -0
  16. roksta/ai/tools/shell_limited.cpython-311-darwin.so +0 -0
  17. roksta/ai/tools/tool_defs.cpython-311-darwin.so +0 -0
  18. roksta/ai/tools/tool_utils.cpython-311-darwin.so +0 -0
  19. roksta/ai/tools/web_fetch.cpython-311-darwin.so +0 -0
  20. roksta/ai/tools/write_file.cpython-311-darwin.so +0 -0
  21. roksta/analytics.cpython-311-darwin.so +0 -0
  22. roksta/balance.cpython-311-darwin.so +0 -0
  23. roksta/build_project.cpython-311-darwin.so +0 -0
  24. roksta/chat_workflow.cpython-311-darwin.so +0 -0
  25. roksta/check_for_updates.cpython-311-darwin.so +0 -0
  26. roksta/check_subtask_sequence.cpython-311-darwin.so +0 -0
  27. roksta/checkpoints.cpython-311-darwin.so +0 -0
  28. roksta/clarify_goal.cpython-311-darwin.so +0 -0
  29. roksta/codebase_listing.cpython-311-darwin.so +0 -0
  30. roksta/command_handlers/__init__.cpython-311-darwin.so +0 -0
  31. roksta/command_handlers/handle_activate_command.cpython-311-darwin.so +0 -0
  32. roksta/command_handlers/handle_add_funds_command.cpython-311-darwin.so +0 -0
  33. roksta/command_handlers/handle_auto_charge_command.cpython-311-darwin.so +0 -0
  34. roksta/command_handlers/handle_auto_commit_command.cpython-311-darwin.so +0 -0
  35. roksta/command_handlers/handle_building_command.cpython-311-darwin.so +0 -0
  36. roksta/command_handlers/handle_chat_command.cpython-311-darwin.so +0 -0
  37. roksta/command_handlers/handle_dev_rate_command.cpython-311-darwin.so +0 -0
  38. roksta/command_handlers/handle_feedback_command.cpython-311-darwin.so +0 -0
  39. roksta/command_handlers/handle_goal_command.cpython-311-darwin.so +0 -0
  40. roksta/command_handlers/handle_help_command.cpython-311-darwin.so +0 -0
  41. roksta/command_handlers/handle_init_command.cpython-311-darwin.so +0 -0
  42. roksta/command_handlers/handle_linting_command.cpython-311-darwin.so +0 -0
  43. roksta/command_handlers/handle_login_command.cpython-311-darwin.so +0 -0
  44. roksta/command_handlers/handle_logout_command.cpython-311-darwin.so +0 -0
  45. roksta/command_handlers/handle_payment_details_command.cpython-311-darwin.so +0 -0
  46. roksta/command_handlers/handle_quit_command.cpython-311-darwin.so +0 -0
  47. roksta/command_handlers/handle_redeem_command.cpython-311-darwin.so +0 -0
  48. roksta/command_handlers/handle_request_activation_command.cpython-311-darwin.so +0 -0
  49. roksta/command_handlers/handle_testing_command.cpython-311-darwin.so +0 -0
  50. roksta/command_handlers/handle_usage_command.cpython-311-darwin.so +0 -0
  51. roksta/create_default_config.cpython-311-darwin.so +0 -0
  52. roksta/create_default_ignore_file.cpython-311-darwin.so +0 -0
  53. roksta/default_config.cpython-311-darwin.so +0 -0
  54. roksta/default_ignores.cpython-311-darwin.so +0 -0
  55. roksta/discover_test_command.cpython-311-darwin.so +0 -0
  56. roksta/enums.cpython-311-darwin.so +0 -0
  57. roksta/env.cpython-311-darwin.so +0 -0
  58. roksta/extended_text_area.cpython-311-darwin.so +0 -0
  59. roksta/firebase.cpython-311-darwin.so +0 -0
  60. roksta/firebase_auth_web.cpython-311-darwin.so +0 -0
  61. roksta/firebase_config.cpython-311-darwin.so +0 -0
  62. roksta/fix_tests.cpython-311-darwin.so +0 -0
  63. roksta/gen_codebase_summaries.cpython-311-darwin.so +0 -0
  64. roksta/gen_one_line_goal.cpython-311-darwin.so +0 -0
  65. roksta/gen_subtasks.cpython-311-darwin.so +0 -0
  66. roksta/get_codebase_structure.cpython-311-darwin.so +0 -0
  67. roksta/get_failing_tests.cpython-311-darwin.so +0 -0
  68. roksta/goal_workflow.cpython-311-darwin.so +0 -0
  69. roksta/init_codebase.cpython-311-darwin.so +0 -0
  70. roksta/lint_code.cpython-311-darwin.so +0 -0
  71. roksta/logger.cpython-311-darwin.so +0 -0
  72. roksta/main.cpython-311-darwin.so +0 -0
  73. roksta/make_issue.cpython-311-darwin.so +0 -0
  74. roksta/new_features.cpython-311-darwin.so +0 -0
  75. roksta/parse_directive_cli_tokens.cpython-311-darwin.so +0 -0
  76. roksta/parse_readme.cpython-311-darwin.so +0 -0
  77. roksta/propose_solution.cpython-311-darwin.so +0 -0
  78. roksta/response_formats.cpython-311-darwin.so +0 -0
  79. roksta/rewrite_goal.cpython-311-darwin.so +0 -0
  80. roksta/roksta.cpython-311-darwin.so +0 -0
  81. roksta/run_cli_goal.cpython-311-darwin.so +0 -0
  82. roksta/save_chat_transcript.cpython-311-darwin.so +0 -0
  83. roksta/select_files.cpython-311-darwin.so +0 -0
  84. roksta/tips.cpython-311-darwin.so +0 -0
  85. roksta/utils.cpython-311-darwin.so +0 -0
  86. roksta/write_code.cpython-311-darwin.so +0 -0
  87. roksta-0.3.8.dist-info/METADATA +471 -0
  88. roksta-0.3.8.dist-info/RECORD +91 -0
  89. {roksta-0.3.2.dist-info → roksta-0.3.8.dist-info}/top_level.txt +0 -1
  90. roksta-0.3.2.dist-info/METADATA +0 -40
  91. roksta-0.3.2.dist-info/RECORD +0 -121
  92. tests/__init__.py +0 -2
  93. tests/conftest.py +0 -211
  94. tests/functions/__init__.py +0 -2
  95. tests/functions/api_v1_00/__init__.py +0 -2
  96. tests/functions/api_v1_00/test__analytics.py +0 -416
  97. tests/functions/api_v1_00/test__gemini_proxy.py +0 -352
  98. tests/functions/api_v1_00/test__generic_proxy.py +0 -428
  99. tests/functions/api_v1_00/test__get_payment_details.py +0 -356
  100. tests/functions/api_v1_00/test__openai_proxy.py +0 -449
  101. tests/functions/api_v1_00/test__redeem_credit_code.py +0 -167
  102. tests/functions/api_v1_00/test__sync_emails.py +0 -325
  103. tests/functions/api_v1_00/test__take_payment.py +0 -491
  104. tests/functions/api_v1_00/test__use_activation_code.py +0 -438
  105. tests/functions/api_v1_01/__init__.py +0 -2
  106. tests/functions/api_v1_01/test__analytics.py +0 -416
  107. tests/functions/api_v1_01/test__gemini_proxy.py +0 -352
  108. tests/functions/api_v1_01/test__generic_proxy.py +0 -428
  109. tests/functions/api_v1_01/test__get_payment_details.py +0 -356
  110. tests/functions/api_v1_01/test__openai_proxy.py +0 -449
  111. tests/functions/api_v1_01/test__redeem_credit_code.py +0 -167
  112. tests/functions/api_v1_01/test__sync_emails.py +0 -325
  113. tests/functions/api_v1_01/test__take_payment.py +0 -491
  114. tests/functions/api_v1_01/test__use_activation_code.py +0 -438
  115. tests/functions/api_v1_02/__init__.py +0 -2
  116. tests/functions/api_v1_02/test__analytics.py +0 -416
  117. tests/functions/api_v1_02/test__gemini_proxy.py +0 -352
  118. tests/functions/api_v1_02/test__generic_proxy.py +0 -428
  119. tests/functions/api_v1_02/test__get_payment_details.py +0 -356
  120. tests/functions/api_v1_02/test__openai_proxy.py +0 -449
  121. tests/functions/api_v1_02/test__redeem_credit_code.py +0 -167
  122. tests/functions/api_v1_02/test__sync_emails.py +0 -325
  123. tests/functions/api_v1_02/test__take_payment.py +0 -491
  124. tests/functions/api_v1_02/test__use_activation_code.py +0 -438
  125. tests/functions/api_v1_02/test_proxy_keyword_replacement.py +0 -557
  126. tests/functions/api_v1_02/test_replace_keywords.py +0 -74
  127. tests/functions/test_auth.py +0 -24
  128. tests/functions/test_main.py +0 -73
  129. tests/functions/test_utils.py +0 -484
  130. {roksta-0.3.2.dist-info → roksta-0.3.8.dist-info}/WHEEL +0 -0
  131. {roksta-0.3.2.dist-info → roksta-0.3.8.dist-info}/entry_points.txt +0 -0
@@ -1,325 +0,0 @@
1
- import os
2
- import sys
3
- import json
4
- import types
5
- import importlib
6
- from unittest.mock import patch
7
-
8
-
9
- # Ensure the functions/ directory is importable as a top-level module location
10
- PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
11
- FUNCTIONS_DIR = os.path.join(PROJECT_ROOT, 'functions')
12
- if FUNCTIONS_DIR not in sys.path:
13
- sys.path.insert(0, FUNCTIONS_DIR)
14
-
15
- # -----------------------------
16
- # Provide lightweight fake modules to satisfy imports inside _sync_emails
17
- # These are minimal and will be patched in individual tests as needed.
18
- # -----------------------------
19
- # Save original sys.modules entries so we can restore them after importing the module under test
20
- _orig_sys_modules = {}
21
- _names_to_fake = ['firebase_functions', 'utils', 'auth', 'firebase_admin']
22
- for name in _names_to_fake:
23
- _orig_sys_modules[name] = sys.modules.get(name)
24
-
25
- # Fake firebase_functions.https_fn.Response to capture returned data
26
- firebase_functions = types.ModuleType('firebase_functions')
27
-
28
- class FakeResponse:
29
- def __init__(self, response=None, mimetype=None, status=200, **kwargs):
30
- # Mirror the small subset of the interface tests expect
31
- self.status_code = status
32
- if isinstance(response, (dict, list)):
33
- self._body_text = json.dumps(response)
34
- else:
35
- self._body_text = '' if response is None else response
36
- self.headers = kwargs.get('headers', {})
37
-
38
- def get_data(self, as_text=False):
39
- if as_text:
40
- return self._body_text
41
- return self._body_text.encode('utf-8')
42
-
43
- firebase_functions.https_fn = types.SimpleNamespace(Request=object, Response=FakeResponse)
44
- sys.modules['firebase_functions'] = firebase_functions
45
-
46
- # Fake utils module (verify_firebase_token, create_json_response)
47
- utils_mod = types.ModuleType('utils')
48
-
49
- def _dummy_verify_firebase_token(req: object) -> dict:
50
- # Default behavior: return a decoded token with a uid
51
- return {'uid': 'test_user'}
52
-
53
-
54
- def _create_json_response(success: bool, payload=None, status_code: int = 200):
55
- # Normalize payload to include a message field
56
- if isinstance(payload, dict):
57
- message = payload.get('message', '')
58
- data = {'success': success, 'message': message}
59
- data['payload'] = payload
60
- else:
61
- message = payload if payload is not None else ''
62
- data = {'success': success, 'message': message}
63
- return firebase_functions.https_fn.Response(response=data, status=status_code)
64
-
65
- utils_mod.verify_firebase_token = _dummy_verify_firebase_token
66
- utils_mod.create_json_response = _create_json_response
67
- sys.modules['utils'] = utils_mod
68
-
69
- # Fake auth module (validate_auth_key will be patched per-test as needed)
70
- auth_mod = types.ModuleType('auth')
71
-
72
- def _simple_validate_auth_key(val: str) -> bool:
73
- return True
74
-
75
- auth_mod.validate_auth_key = _simple_validate_auth_key
76
- sys.modules['auth'] = auth_mod
77
-
78
- # Fake firebase_admin to prevent importing the real package during tests
79
- firebase_admin = types.ModuleType('firebase_admin')
80
- # Minimal fake auth and firestore objects; tests will patch their behavior as needed
81
- fake_auth = types.SimpleNamespace(get_user=lambda uid: types.SimpleNamespace(email='test@example.com'))
82
- # Provide a placeholder firestore client function; will be overridden by tests
83
- fake_firestore = types.SimpleNamespace(client=lambda: None)
84
- firebase_admin.auth = fake_auth
85
- firebase_admin.firestore = fake_firestore
86
- sys.modules['firebase_admin'] = firebase_admin
87
-
88
- # -----------------------------
89
- # Import the module under test after preparing the fake imports
90
- # -----------------------------
91
- repo_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
92
- functions_root = os.path.join(repo_root, 'functions')
93
- module_path = os.path.join(functions_root, 'api_v1_00', '_sync_emails.py')
94
- spec = importlib.util.spec_from_file_location('api_v1_00._sync_emails', module_path)
95
- _sync = importlib.util.module_from_spec(spec)
96
- spec.loader.exec_module(_sync)
97
-
98
-
99
- # Restore original sys.modules mappings to avoid side-effects for other tests
100
- for name, orig in _orig_sys_modules.items():
101
- if orig is None:
102
- try:
103
- del sys.modules[name]
104
- except KeyError:
105
- pass
106
- else:
107
- sys.modules[name] = orig
108
-
109
-
110
- # -----------------------------
111
- # Fake Firestore implementation used by tests
112
- # -----------------------------
113
- class FakeDocumentSnapshot:
114
- def __init__(self, exists: bool, data: dict | None):
115
- self.exists = exists
116
- self._data = data
117
-
118
- def to_dict(self):
119
- return self._data
120
-
121
-
122
- class FakeDocumentReference:
123
- def __init__(self, client, collection: str, doc_id: str):
124
- self.client = client
125
- self.collection = collection
126
- self.doc_id = doc_id
127
-
128
- def get(self):
129
- coll = self.client._data.get(self.collection, {})
130
- if self.doc_id in coll:
131
- return FakeDocumentSnapshot(True, coll[self.doc_id])
132
- return FakeDocumentSnapshot(False, None)
133
-
134
- def update(self, update_dict: dict):
135
- # Record the update
136
- self.client._updates.append((self.collection, self.doc_id, update_dict))
137
- coll = self.client._data.setdefault(self.collection, {})
138
- # Apply update to stored doc if it exists and is a dict
139
- if isinstance(coll.get(self.doc_id), dict):
140
- coll[self.doc_id].update(update_dict)
141
- else:
142
- coll[self.doc_id] = update_dict
143
-
144
-
145
- class FakeCollectionReference:
146
- def __init__(self, client, name: str):
147
- self.client = client
148
- self.name = name
149
-
150
- def document(self, doc_id: str):
151
- return FakeDocumentReference(self.client, self.name, doc_id)
152
-
153
-
154
- class FakeFirestoreClient:
155
- def __init__(self, initial_data: dict | None = None):
156
- # initial_data should be a dict mapping collection_name -> {doc_id: doc_data}
157
- self._data = initial_data.copy() if initial_data else {}
158
- self._updates = []
159
-
160
- def collection(self, name: str):
161
- return FakeCollectionReference(self, name)
162
-
163
- def get_updates(self):
164
- return self._updates
165
-
166
-
167
- # Simple helper request stub used in the tests
168
- class DummyRequest:
169
- def __init__(self, headers=None, method='POST', json_data=None, raise_on_get_json=False):
170
- self.headers = headers or {}
171
- self.method = method
172
- self._json_data = json_data
173
- self._raise = raise_on_get_json
174
-
175
- def get_json(self, silent=True):
176
- if self._raise:
177
- raise Exception('Malformed JSON')
178
- return self._json_data
179
-
180
-
181
- def _parse_response(resp):
182
- data = resp.get_data(as_text=True)
183
- return json.loads(data)
184
-
185
-
186
- # -----------------------------
187
- # Tests
188
- # -----------------------------
189
-
190
- def test_missing_auth_header_returns_401():
191
- req = DummyRequest(headers={}, method='POST')
192
- # Ensure verify_firebase_token is not called when header is missing
193
- with patch.object(_sync, 'verify_firebase_token', side_effect=Exception('Should not be called')):
194
- resp = _sync._sync_emails(req)
195
-
196
- assert resp.status_code == 401
197
- payload = _parse_response(resp)
198
- assert payload['success'] is False
199
- assert 'Missing app authentication key' in payload['message']
200
-
201
-
202
- def test_invalid_auth_key_returns_403():
203
- headers = {_sync.AUTH_HEADER_NAME: 'bad-token'}
204
- req = DummyRequest(headers=headers, method='POST')
205
- with patch.object(_sync, 'validate_auth_key', return_value=False):
206
- resp = _sync._sync_emails(req)
207
- assert resp.status_code == 403
208
- payload = _parse_response(resp)
209
- assert payload['success'] is False
210
- assert 'Invalid app authentication key' in payload['message']
211
-
212
-
213
- def test_verify_token_raises_returns_403():
214
- headers = {_sync.AUTH_HEADER_NAME: 'ok'}
215
- req = DummyRequest(headers=headers, method='POST')
216
- with patch.object(_sync, 'validate_auth_key', return_value=True), patch.object(_sync, 'verify_firebase_token', side_effect=Exception('boom')):
217
- resp = _sync._sync_emails(req)
218
-
219
- assert resp.status_code == 403
220
- payload = _parse_response(resp)
221
- assert payload['success'] is False
222
- assert 'Authentication failed' in payload['message']
223
-
224
-
225
- def test_missing_uid_in_token_returns_403():
226
- headers = {_sync.AUTH_HEADER_NAME: 'ok'}
227
- req = DummyRequest(headers=headers, method='POST')
228
- with patch.object(_sync, 'validate_auth_key', return_value=True), patch.object(_sync, 'verify_firebase_token', return_value={}):
229
- resp = _sync._sync_emails(req)
230
-
231
- assert resp.status_code == 403
232
- payload = _parse_response(resp)
233
- assert payload['success'] is False
234
- assert 'UID missing' in payload['message']
235
-
236
-
237
- def test_get_user_failure_returns_500():
238
- headers = {_sync.AUTH_HEADER_NAME: 'ok'}
239
- req = DummyRequest(headers=headers, method='POST')
240
- with patch.object(_sync, 'validate_auth_key', return_value=True), patch.object(_sync, 'verify_firebase_token', return_value={'uid': 'u'}), patch.object(_sync.auth, 'get_user', side_effect=Exception('nope')):
241
- resp = _sync._sync_emails(req)
242
-
243
- assert resp.status_code == 500
244
- payload = _parse_response(resp)
245
- assert payload['success'] is False
246
- assert 'Failed to retrieve user data from Firebase Authentication' in payload['message']
247
-
248
-
249
- def test_no_updates_when_emails_match_returns_200():
250
- headers = {_sync.AUTH_HEADER_NAME: 'ok'}
251
- req = DummyRequest(headers=headers, method='POST')
252
-
253
- fake_data = {
254
- 'users': {'u': {'email': 'auth@example.com'}},
255
- 'billing': {'u': {'email': 'auth@example.com'}}
256
- }
257
- fake_client = FakeFirestoreClient(initial_data=fake_data)
258
-
259
- with patch.object(_sync, 'validate_auth_key', return_value=True), \
260
- patch.object(_sync, 'verify_firebase_token', return_value={'uid': 'u'}), \
261
- patch.object(_sync.auth, 'get_user', return_value=types.SimpleNamespace(email='auth@example.com')), \
262
- patch.object(_sync.firestore, 'client', return_value=fake_client):
263
- resp = _sync._sync_emails(req)
264
-
265
- assert resp.status_code == 200
266
- payload = _parse_response(resp)
267
- assert payload['success'] is True
268
- assert 'No email updates were necessary' in payload['message']
269
- assert fake_client.get_updates() == []
270
-
271
-
272
- def test_updates_when_mismatch_calls_update_returns_200():
273
- headers = {_sync.AUTH_HEADER_NAME: 'ok'}
274
- req = DummyRequest(headers=headers, method='POST')
275
-
276
- fake_data = {
277
- 'users': {'u': {'email': 'old_user@example.com'}},
278
- 'billing': {'u': {'email': 'old_billing@example.com'}}
279
- }
280
- fake_client = FakeFirestoreClient(initial_data=fake_data)
281
-
282
- with patch.object(_sync, 'validate_auth_key', return_value=True), \
283
- patch.object(_sync, 'verify_firebase_token', return_value={'uid': 'u'}), \
284
- patch.object(_sync.auth, 'get_user', return_value=types.SimpleNamespace(email='auth@example.com')), \
285
- patch.object(_sync.firestore, 'client', return_value=fake_client):
286
- resp = _sync._sync_emails(req)
287
-
288
- assert resp.status_code == 200
289
- payload = _parse_response(resp)
290
- assert payload['success'] is True
291
- assert 'User profile email updated.' in payload['message']
292
- assert 'Billing email updated.' in payload['message']
293
-
294
- updates = fake_client.get_updates()
295
- # Ensure we have two updates and that both updated emails match the auth email
296
- assert any(u for u in updates if u[0] == 'users' and u[1] == 'u' and u[2] == {'email': 'auth@example.com'})
297
- assert any(u for u in updates if u[0] == 'billing' and u[1] == 'u' and u[2] == {'email': 'auth@example.com'})
298
-
299
-
300
- def test_billing_exists_without_email_field_only_user_updated_returns_200():
301
- headers = {_sync.AUTH_HEADER_NAME: 'ok'}
302
- req = DummyRequest(headers=headers, method='POST')
303
-
304
- fake_data = {
305
- 'users': {'u': {'email': 'old_user@example.com'}},
306
- 'billing': {'u': {'some_other_key': 'value'}}
307
- }
308
- fake_client = FakeFirestoreClient(initial_data=fake_data)
309
-
310
- with patch.object(_sync, 'validate_auth_key', return_value=True), \
311
- patch.object(_sync, 'verify_firebase_token', return_value={'uid': 'u'}), \
312
- patch.object(_sync.auth, 'get_user', return_value=types.SimpleNamespace(email='auth@example.com')), \
313
- patch.object(_sync.firestore, 'client', return_value=fake_client):
314
- resp = _sync._sync_emails(req)
315
-
316
- assert resp.status_code == 200
317
- payload = _parse_response(resp)
318
- assert payload['success'] is True
319
- assert 'User profile email updated.' in payload['message']
320
- assert 'Billing email updated.' not in payload['message']
321
-
322
- updates = fake_client.get_updates()
323
- assert any(u for u in updates if u[0] == 'users' and u[1] == 'u' and u[2] == {'email': 'auth@example.com'})
324
- # Ensure billing was not updated
325
- assert not any(u for u in updates if u[0] == 'billing')