privacyfence 4.0.0a11__tar.gz

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 (286) hide show
  1. privacyfence-4.0.0a11/.github/CODEOWNERS +2 -0
  2. privacyfence-4.0.0a11/.github/workflows/build.yml +114 -0
  3. privacyfence-4.0.0a11/.github/workflows/publish-pypi.yml +93 -0
  4. privacyfence-4.0.0a11/.github/workflows/tests.yml +112 -0
  5. privacyfence-4.0.0a11/.gitignore +71 -0
  6. privacyfence-4.0.0a11/CLAUDE.md +113 -0
  7. privacyfence-4.0.0a11/CONTRIBUTING.md +50 -0
  8. privacyfence-4.0.0a11/LICENSE +185 -0
  9. privacyfence-4.0.0a11/NOTICE +36 -0
  10. privacyfence-4.0.0a11/PKG-INFO +354 -0
  11. privacyfence-4.0.0a11/PrivacyFenceApp.spec +167 -0
  12. privacyfence-4.0.0a11/README.md +310 -0
  13. privacyfence-4.0.0a11/com.privacyfence.app.plist +53 -0
  14. privacyfence-4.0.0a11/credentials/.gitkeep +0 -0
  15. privacyfence-4.0.0a11/docs/TECHNICAL_REFERENCE.md +1514 -0
  16. privacyfence-4.0.0a11/docs/always-allow-rules-reference.md +376 -0
  17. privacyfence-4.0.0a11/docs/approval-list-ui-ux.md +595 -0
  18. privacyfence-4.0.0a11/docs/approval-window-content-reference.md +290 -0
  19. privacyfence-4.0.0a11/docs/atlassian-setup.md +92 -0
  20. privacyfence-4.0.0a11/docs/claude-knowledge-boundary.md +315 -0
  21. privacyfence-4.0.0a11/docs/coding-and-testing-guidelines.md +247 -0
  22. privacyfence-4.0.0a11/docs/connector-qa-testing.md +1274 -0
  23. privacyfence-4.0.0a11/docs/dev-vs-live-setup.md +109 -0
  24. privacyfence-4.0.0a11/docs/file-type-support.md +114 -0
  25. privacyfence-4.0.0a11/docs/google-cloud-setup.md +146 -0
  26. privacyfence-4.0.0a11/docs/https-connector-refactor-plan.md +1924 -0
  27. privacyfence-4.0.0a11/docs/images/architecture.svg +114 -0
  28. privacyfence-4.0.0a11/docs/images/screenshots/README.md +38 -0
  29. privacyfence-4.0.0a11/docs/images/screenshots/gmail-read-thread.png +0 -0
  30. privacyfence-4.0.0a11/docs/images/screenshots/menubar-auto-accept-rules.png +0 -0
  31. privacyfence-4.0.0a11/docs/images/screenshots/menubar.png +0 -0
  32. privacyfence-4.0.0a11/docs/images/screenshots/sheets-write.png +0 -0
  33. privacyfence-4.0.0a11/docs/manual-pre-release-test-plan.md +176 -0
  34. privacyfence-4.0.0a11/docs/mockups/approval-list.html +755 -0
  35. privacyfence-4.0.0a11/docs/pii-detection-keywords.md +95 -0
  36. privacyfence-4.0.0a11/docs/qa-environment-setup.md +621 -0
  37. privacyfence-4.0.0a11/docs/salesforce-setup.md +81 -0
  38. privacyfence-4.0.0a11/docs/security-and-compliance.md +355 -0
  39. privacyfence-4.0.0a11/docs/slack-setup.md +111 -0
  40. privacyfence-4.0.0a11/docs/telegram-setup.md +65 -0
  41. privacyfence-4.0.0a11/docs/testing-policy.md +253 -0
  42. privacyfence-4.0.0a11/mcpb/manifest.json.tmpl +25 -0
  43. privacyfence-4.0.0a11/mcpb/shim/build.mjs +23 -0
  44. privacyfence-4.0.0a11/mcpb/shim/package-lock.json +1754 -0
  45. privacyfence-4.0.0a11/mcpb/shim/package.json +22 -0
  46. privacyfence-4.0.0a11/mcpb/shim/src/daemon.ts +208 -0
  47. privacyfence-4.0.0a11/mcpb/shim/src/errors.ts +17 -0
  48. privacyfence-4.0.0a11/mcpb/shim/src/index.ts +159 -0
  49. privacyfence-4.0.0a11/mcpb/shim/src/protocol.ts +44 -0
  50. privacyfence-4.0.0a11/mcpb/shim/src/proxy.ts +49 -0
  51. privacyfence-4.0.0a11/mcpb/shim/test/daemon.test.ts +225 -0
  52. privacyfence-4.0.0a11/mcpb/shim/test/fakeMcpDaemon.ts +69 -0
  53. privacyfence-4.0.0a11/mcpb/shim/test/index.test.ts +86 -0
  54. privacyfence-4.0.0a11/mcpb/shim/test/protocol.test.ts +42 -0
  55. privacyfence-4.0.0a11/mcpb/shim/test/proxy.test.ts +92 -0
  56. privacyfence-4.0.0a11/mcpb/shim/test/testFiles.ts +59 -0
  57. privacyfence-4.0.0a11/mcpb/shim/tsconfig.json +19 -0
  58. privacyfence-4.0.0a11/privacyfence.service +62 -0
  59. privacyfence-4.0.0a11/pyproject.toml +137 -0
  60. privacyfence-4.0.0a11/scripts/build_dmg.sh +173 -0
  61. privacyfence-4.0.0a11/scripts/build_mcpb.sh +81 -0
  62. privacyfence-4.0.0a11/scripts/build_org_bundle.py +292 -0
  63. privacyfence-4.0.0a11/scripts/dev_start.sh +104 -0
  64. privacyfence-4.0.0a11/scripts/entitlements.plist +25 -0
  65. privacyfence-4.0.0a11/scripts/pre_release_check.py +75 -0
  66. privacyfence-4.0.0a11/scripts/qa_fixture_recorder.py +1387 -0
  67. privacyfence-4.0.0a11/scripts/qa_list_ids.py +88 -0
  68. privacyfence-4.0.0a11/scripts/qa_popup_smoke.py +3765 -0
  69. privacyfence-4.0.0a11/scripts/qa_web_smoke.py +239 -0
  70. privacyfence-4.0.0a11/scripts/slack_call_budget.py +253 -0
  71. privacyfence-4.0.0a11/scripts/sync_room_directory.py +142 -0
  72. privacyfence-4.0.0a11/setup.cfg +4 -0
  73. privacyfence-4.0.0a11/src/_daemon_entry.py +17 -0
  74. privacyfence-4.0.0a11/src/privacyfence/__init__.py +16 -0
  75. privacyfence-4.0.0a11/src/privacyfence/app_credentials.py +30 -0
  76. privacyfence-4.0.0a11/src/privacyfence/approval_icons.py +58 -0
  77. privacyfence-4.0.0a11/src/privacyfence/approval_list_html.py +273 -0
  78. privacyfence-4.0.0a11/src/privacyfence/approval_popup.py +278 -0
  79. privacyfence-4.0.0a11/src/privacyfence/approval_ui.py +160 -0
  80. privacyfence-4.0.0a11/src/privacyfence/approval_window.py +832 -0
  81. privacyfence-4.0.0a11/src/privacyfence/approval_window_html.py +875 -0
  82. privacyfence-4.0.0a11/src/privacyfence/approvals.py +521 -0
  83. privacyfence-4.0.0a11/src/privacyfence/apps_script_client.py +342 -0
  84. privacyfence-4.0.0a11/src/privacyfence/atlassian_oauth.py +229 -0
  85. privacyfence-4.0.0a11/src/privacyfence/audit_log.py +405 -0
  86. privacyfence-4.0.0a11/src/privacyfence/auto_accept.py +1679 -0
  87. privacyfence-4.0.0a11/src/privacyfence/calendar_client.py +745 -0
  88. privacyfence-4.0.0a11/src/privacyfence/card_builder.py +138 -0
  89. privacyfence-4.0.0a11/src/privacyfence/confluence_client.py +624 -0
  90. privacyfence-4.0.0a11/src/privacyfence/connector.py +90 -0
  91. privacyfence-4.0.0a11/src/privacyfence/connector_host.py +61 -0
  92. privacyfence-4.0.0a11/src/privacyfence/connector_registry.py +141 -0
  93. privacyfence-4.0.0a11/src/privacyfence/connectors/__init__.py +2 -0
  94. privacyfence-4.0.0a11/src/privacyfence/connectors/apps_script.py +316 -0
  95. privacyfence-4.0.0a11/src/privacyfence/connectors/calendar.py +765 -0
  96. privacyfence-4.0.0a11/src/privacyfence/connectors/confluence.py +551 -0
  97. privacyfence-4.0.0a11/src/privacyfence/connectors/contacts.py +422 -0
  98. privacyfence-4.0.0a11/src/privacyfence/connectors/drive.py +1598 -0
  99. privacyfence-4.0.0a11/src/privacyfence/connectors/gmail.py +1315 -0
  100. privacyfence-4.0.0a11/src/privacyfence/connectors/jira.py +447 -0
  101. privacyfence-4.0.0a11/src/privacyfence/connectors/salesforce.py +434 -0
  102. privacyfence-4.0.0a11/src/privacyfence/connectors/slack.py +732 -0
  103. privacyfence-4.0.0a11/src/privacyfence/connectors/tasks.py +380 -0
  104. privacyfence-4.0.0a11/src/privacyfence/connectors/telegram.py +304 -0
  105. privacyfence-4.0.0a11/src/privacyfence/contacts_client.py +681 -0
  106. privacyfence-4.0.0a11/src/privacyfence/daemon_main.py +1142 -0
  107. privacyfence-4.0.0a11/src/privacyfence/dialog_window.py +296 -0
  108. privacyfence-4.0.0a11/src/privacyfence/dialog_window_html.py +240 -0
  109. privacyfence-4.0.0a11/src/privacyfence/drive_client.py +2631 -0
  110. privacyfence-4.0.0a11/src/privacyfence/email_markdown.py +184 -0
  111. privacyfence-4.0.0a11/src/privacyfence/gate.py +1277 -0
  112. privacyfence-4.0.0a11/src/privacyfence/gmail_client.py +1261 -0
  113. privacyfence-4.0.0a11/src/privacyfence/html_to_text.py +250 -0
  114. privacyfence-4.0.0a11/src/privacyfence/jira_client.py +457 -0
  115. privacyfence-4.0.0a11/src/privacyfence/markdown_to_html.py +118 -0
  116. privacyfence-4.0.0a11/src/privacyfence/menu_bar.py +129 -0
  117. privacyfence-4.0.0a11/src/privacyfence/oauth_loopback.py +196 -0
  118. privacyfence-4.0.0a11/src/privacyfence/org_identity.py +219 -0
  119. privacyfence-4.0.0a11/src/privacyfence/org_mode.py +80 -0
  120. privacyfence-4.0.0a11/src/privacyfence/paths.py +133 -0
  121. privacyfence-4.0.0a11/src/privacyfence/pii_detector.py +448 -0
  122. privacyfence-4.0.0a11/src/privacyfence/principal.py +193 -0
  123. privacyfence-4.0.0a11/src/privacyfence/privacy_filter.py +167 -0
  124. privacyfence-4.0.0a11/src/privacyfence/resource_grants.py +626 -0
  125. privacyfence-4.0.0a11/src/privacyfence/resource_names.py +134 -0
  126. privacyfence-4.0.0a11/src/privacyfence/resources/approval_window/fonts/OFL.txt +93 -0
  127. privacyfence-4.0.0a11/src/privacyfence/resources/approval_window/fonts/SourceSerif4-Italic.woff2 +0 -0
  128. privacyfence-4.0.0a11/src/privacyfence/resources/approval_window/fonts/SourceSerif4-Regular.woff2 +0 -0
  129. privacyfence-4.0.0a11/src/privacyfence/resources/approval_window/fonts/SourceSerif4-SemiBold.woff2 +0 -0
  130. privacyfence-4.0.0a11/src/privacyfence/resources/approval_window/styles.css +447 -0
  131. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/README.md +47 -0
  132. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/calendar.png +0 -0
  133. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/confluence.png +0 -0
  134. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/contacts.png +0 -0
  135. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/drive.png +0 -0
  136. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/gmail.png +0 -0
  137. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/jira.png +0 -0
  138. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/salesforce.png +0 -0
  139. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/slack.png +0 -0
  140. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/tasks.png +0 -0
  141. privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/telegram.png +0 -0
  142. privacyfence-4.0.0a11/src/privacyfence/resources/icon_32.png +0 -0
  143. privacyfence-4.0.0a11/src/privacyfence/resources/icon_512.png +0 -0
  144. privacyfence-4.0.0a11/src/privacyfence/resources/icon_64.png +0 -0
  145. privacyfence-4.0.0a11/src/privacyfence/resources/icon_menubar.png +0 -0
  146. privacyfence-4.0.0a11/src/privacyfence/resources/settings.yaml.example +296 -0
  147. privacyfence-4.0.0a11/src/privacyfence/resources/sw.js +43 -0
  148. privacyfence-4.0.0a11/src/privacyfence/resources/tokens.css +120 -0
  149. privacyfence-4.0.0a11/src/privacyfence/room_directory_client.py +151 -0
  150. privacyfence-4.0.0a11/src/privacyfence/salesforce_client.py +406 -0
  151. privacyfence-4.0.0a11/src/privacyfence/settings_controller.py +1883 -0
  152. privacyfence-4.0.0a11/src/privacyfence/settings_window.py +264 -0
  153. privacyfence-4.0.0a11/src/privacyfence/settings_window_html.py +1208 -0
  154. privacyfence-4.0.0a11/src/privacyfence/slack_client.py +1774 -0
  155. privacyfence-4.0.0a11/src/privacyfence/tasks_client.py +338 -0
  156. privacyfence-4.0.0a11/src/privacyfence/telegram_client.py +597 -0
  157. privacyfence-4.0.0a11/src/privacyfence/text_extraction.py +376 -0
  158. privacyfence-4.0.0a11/src/privacyfence/update_checker.py +253 -0
  159. privacyfence-4.0.0a11/src/privacyfence/web/__init__.py +14 -0
  160. privacyfence-4.0.0a11/src/privacyfence/web/mcp_auth.py +101 -0
  161. privacyfence-4.0.0a11/src/privacyfence/web/mcp_dispatch.py +396 -0
  162. privacyfence-4.0.0a11/src/privacyfence/web/mcp_tools.py +281 -0
  163. privacyfence-4.0.0a11/src/privacyfence/web/oauth_provider.py +369 -0
  164. privacyfence-4.0.0a11/src/privacyfence/web/org_session.py +129 -0
  165. privacyfence-4.0.0a11/src/privacyfence/web/routes_approvals.py +305 -0
  166. privacyfence-4.0.0a11/src/privacyfence/web/routes_mcp.py +313 -0
  167. privacyfence-4.0.0a11/src/privacyfence/web/routes_org_identity.py +186 -0
  168. privacyfence-4.0.0a11/src/privacyfence/web/routes_settings.py +360 -0
  169. privacyfence-4.0.0a11/src/privacyfence/web/server.py +626 -0
  170. privacyfence-4.0.0a11/src/privacyfence/web/session_auth.py +66 -0
  171. privacyfence-4.0.0a11/src/privacyfence/web/state_stream.py +176 -0
  172. privacyfence-4.0.0a11/src/privacyfence/web_approval_ui.py +201 -0
  173. privacyfence-4.0.0a11/src/privacyfence/web_prompt.py +76 -0
  174. privacyfence-4.0.0a11/src/privacyfence/web_shell.py +356 -0
  175. privacyfence-4.0.0a11/src/privacyfence.egg-info/PKG-INFO +354 -0
  176. privacyfence-4.0.0a11/src/privacyfence.egg-info/SOURCES.txt +284 -0
  177. privacyfence-4.0.0a11/src/privacyfence.egg-info/dependency_links.txt +1 -0
  178. privacyfence-4.0.0a11/src/privacyfence.egg-info/entry_points.txt +2 -0
  179. privacyfence-4.0.0a11/src/privacyfence.egg-info/requires.txt +36 -0
  180. privacyfence-4.0.0a11/src/privacyfence.egg-info/scm_file_list.json +280 -0
  181. privacyfence-4.0.0a11/src/privacyfence.egg-info/scm_version.json +8 -0
  182. privacyfence-4.0.0a11/src/privacyfence.egg-info/top_level.txt +1 -0
  183. privacyfence-4.0.0a11/tests/__init__.py +0 -0
  184. privacyfence-4.0.0a11/tests/conftest.py +47 -0
  185. privacyfence-4.0.0a11/tests/fixtures/live/README.md +17 -0
  186. privacyfence-4.0.0a11/tests/fixtures/live/calendar/get_event.json +33 -0
  187. privacyfence-4.0.0a11/tests/fixtures/live/confluence/get_page.json +34 -0
  188. privacyfence-4.0.0a11/tests/fixtures/live/confluence/list_spaces.json +29 -0
  189. privacyfence-4.0.0a11/tests/fixtures/live/contacts/get_contact.json +73 -0
  190. privacyfence-4.0.0a11/tests/fixtures/live/drive/get_file_metadata.json +17 -0
  191. privacyfence-4.0.0a11/tests/fixtures/live/gmail/get_message.json +82 -0
  192. privacyfence-4.0.0a11/tests/fixtures/live/jira/get_issue.json +171 -0
  193. privacyfence-4.0.0a11/tests/fixtures/live/jira/list_projects.json +22 -0
  194. privacyfence-4.0.0a11/tests/fixtures/live/salesforce/get_record.json +76 -0
  195. privacyfence-4.0.0a11/tests/fixtures/live/salesforce/list_reports.json +17 -0
  196. privacyfence-4.0.0a11/tests/fixtures/live/slack/get_thread_replies.json +96 -0
  197. privacyfence-4.0.0a11/tests/fixtures/live/tasks/get_task.json +13 -0
  198. privacyfence-4.0.0a11/tests/fixtures/live/telegram/get_messages.json +60 -0
  199. privacyfence-4.0.0a11/tests/fixtures/qa_assets/lorem_ipsum.docx +0 -0
  200. privacyfence-4.0.0a11/tests/fixtures/qa_environment.yaml.example +126 -0
  201. privacyfence-4.0.0a11/tests/helpers.py +120 -0
  202. privacyfence-4.0.0a11/tests/integration/__init__.py +1 -0
  203. privacyfence-4.0.0a11/tests/integration/test_mcp_daemon_contract.py +157 -0
  204. privacyfence-4.0.0a11/tests/integration/test_shim_mcp_contract.py +206 -0
  205. privacyfence-4.0.0a11/tests/unit/__init__.py +0 -0
  206. privacyfence-4.0.0a11/tests/unit/connectors/__init__.py +0 -0
  207. privacyfence-4.0.0a11/tests/unit/connectors/test_apps_script_connector.py +326 -0
  208. privacyfence-4.0.0a11/tests/unit/connectors/test_calendar_connector.py +795 -0
  209. privacyfence-4.0.0a11/tests/unit/connectors/test_confluence_connector.py +760 -0
  210. privacyfence-4.0.0a11/tests/unit/connectors/test_contacts_connector.py +452 -0
  211. privacyfence-4.0.0a11/tests/unit/connectors/test_drive_connector.py +1792 -0
  212. privacyfence-4.0.0a11/tests/unit/connectors/test_gmail_connector.py +1407 -0
  213. privacyfence-4.0.0a11/tests/unit/connectors/test_jira_connector.py +557 -0
  214. privacyfence-4.0.0a11/tests/unit/connectors/test_readme_manifest_alignment.py +162 -0
  215. privacyfence-4.0.0a11/tests/unit/connectors/test_salesforce_connector.py +545 -0
  216. privacyfence-4.0.0a11/tests/unit/connectors/test_slack_connector.py +918 -0
  217. privacyfence-4.0.0a11/tests/unit/connectors/test_tasks_connector.py +415 -0
  218. privacyfence-4.0.0a11/tests/unit/connectors/test_telegram_connector.py +326 -0
  219. privacyfence-4.0.0a11/tests/unit/test_app_credentials.py +86 -0
  220. privacyfence-4.0.0a11/tests/unit/test_approval_icons.py +45 -0
  221. privacyfence-4.0.0a11/tests/unit/test_approval_list_html.py +79 -0
  222. privacyfence-4.0.0a11/tests/unit/test_approval_popup.py +324 -0
  223. privacyfence-4.0.0a11/tests/unit/test_approval_ui.py +151 -0
  224. privacyfence-4.0.0a11/tests/unit/test_approval_window.py +749 -0
  225. privacyfence-4.0.0a11/tests/unit/test_approval_window_html.py +752 -0
  226. privacyfence-4.0.0a11/tests/unit/test_approvals.py +466 -0
  227. privacyfence-4.0.0a11/tests/unit/test_apps_script_client.py +492 -0
  228. privacyfence-4.0.0a11/tests/unit/test_atlassian_oauth.py +328 -0
  229. privacyfence-4.0.0a11/tests/unit/test_audit_log.py +371 -0
  230. privacyfence-4.0.0a11/tests/unit/test_auto_accept.py +2134 -0
  231. privacyfence-4.0.0a11/tests/unit/test_calendar_client.py +1056 -0
  232. privacyfence-4.0.0a11/tests/unit/test_card_builder.py +127 -0
  233. privacyfence-4.0.0a11/tests/unit/test_confluence_client.py +776 -0
  234. privacyfence-4.0.0a11/tests/unit/test_connector.py +70 -0
  235. privacyfence-4.0.0a11/tests/unit/test_connector_registry.py +188 -0
  236. privacyfence-4.0.0a11/tests/unit/test_contacts_client.py +945 -0
  237. privacyfence-4.0.0a11/tests/unit/test_daemon_main.py +1795 -0
  238. privacyfence-4.0.0a11/tests/unit/test_dialog_window.py +310 -0
  239. privacyfence-4.0.0a11/tests/unit/test_dialog_window_html.py +162 -0
  240. privacyfence-4.0.0a11/tests/unit/test_drive_client.py +3546 -0
  241. privacyfence-4.0.0a11/tests/unit/test_email_markdown.py +123 -0
  242. privacyfence-4.0.0a11/tests/unit/test_gate.py +2633 -0
  243. privacyfence-4.0.0a11/tests/unit/test_gate_real_evaluator.py +828 -0
  244. privacyfence-4.0.0a11/tests/unit/test_gmail_client.py +1824 -0
  245. privacyfence-4.0.0a11/tests/unit/test_html_to_text.py +213 -0
  246. privacyfence-4.0.0a11/tests/unit/test_jira_client.py +682 -0
  247. privacyfence-4.0.0a11/tests/unit/test_markdown_to_html.py +140 -0
  248. privacyfence-4.0.0a11/tests/unit/test_menu_bar.py +141 -0
  249. privacyfence-4.0.0a11/tests/unit/test_oauth_loopback.py +306 -0
  250. privacyfence-4.0.0a11/tests/unit/test_org_identity.py +316 -0
  251. privacyfence-4.0.0a11/tests/unit/test_org_mode.py +73 -0
  252. privacyfence-4.0.0a11/tests/unit/test_p6_principal_isolation.py +203 -0
  253. privacyfence-4.0.0a11/tests/unit/test_paths.py +197 -0
  254. privacyfence-4.0.0a11/tests/unit/test_pii_detector.py +528 -0
  255. privacyfence-4.0.0a11/tests/unit/test_principal.py +211 -0
  256. privacyfence-4.0.0a11/tests/unit/test_privacy_filter.py +167 -0
  257. privacyfence-4.0.0a11/tests/unit/test_qa_fixture_recorder.py +1265 -0
  258. privacyfence-4.0.0a11/tests/unit/test_resource_grants.py +695 -0
  259. privacyfence-4.0.0a11/tests/unit/test_resource_names.py +155 -0
  260. privacyfence-4.0.0a11/tests/unit/test_room_directory_client.py +220 -0
  261. privacyfence-4.0.0a11/tests/unit/test_salesforce_client.py +659 -0
  262. privacyfence-4.0.0a11/tests/unit/test_settings_controller.py +1698 -0
  263. privacyfence-4.0.0a11/tests/unit/test_settings_window.py +274 -0
  264. privacyfence-4.0.0a11/tests/unit/test_settings_window_html.py +387 -0
  265. privacyfence-4.0.0a11/tests/unit/test_slack_client.py +2260 -0
  266. privacyfence-4.0.0a11/tests/unit/test_tasks_client.py +570 -0
  267. privacyfence-4.0.0a11/tests/unit/test_telegram_client.py +801 -0
  268. privacyfence-4.0.0a11/tests/unit/test_text_extraction.py +393 -0
  269. privacyfence-4.0.0a11/tests/unit/test_update_checker.py +408 -0
  270. privacyfence-4.0.0a11/tests/unit/test_web_approval_ui.py +266 -0
  271. privacyfence-4.0.0a11/tests/unit/test_web_prompt.py +151 -0
  272. privacyfence-4.0.0a11/tests/unit/test_web_shell.py +167 -0
  273. privacyfence-4.0.0a11/tests/unit/web/__init__.py +0 -0
  274. privacyfence-4.0.0a11/tests/unit/web/test_mcp_auth.py +51 -0
  275. privacyfence-4.0.0a11/tests/unit/web/test_mcp_dispatch.py +534 -0
  276. privacyfence-4.0.0a11/tests/unit/web/test_oauth_provider.py +348 -0
  277. privacyfence-4.0.0a11/tests/unit/web/test_org_mcp_e2e.py +272 -0
  278. privacyfence-4.0.0a11/tests/unit/web/test_org_session.py +118 -0
  279. privacyfence-4.0.0a11/tests/unit/web/test_routes_approvals.py +339 -0
  280. privacyfence-4.0.0a11/tests/unit/web/test_routes_mcp.py +285 -0
  281. privacyfence-4.0.0a11/tests/unit/web/test_routes_mcp_principal.py +83 -0
  282. privacyfence-4.0.0a11/tests/unit/web/test_routes_org_identity.py +244 -0
  283. privacyfence-4.0.0a11/tests/unit/web/test_routes_settings.py +416 -0
  284. privacyfence-4.0.0a11/tests/unit/web/test_server.py +377 -0
  285. privacyfence-4.0.0a11/tests/unit/web/test_server_org_mode.py +151 -0
  286. privacyfence-4.0.0a11/tests/unit/web/test_state_stream.py +161 -0
@@ -0,0 +1,2 @@
1
+ # All files require review from the repository owner.
2
+ * @andras-tkcs
@@ -0,0 +1,114 @@
1
+ name: Build & Release DMG
2
+
3
+ on:
4
+ push:
5
+ tags: ['v*']
6
+ workflow_dispatch: # allow manual runs from the Actions tab
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: macos-latest # arm64 Apple Silicon runner
11
+ permissions:
12
+ contents: write
13
+ env:
14
+ # Name of the notarytool keychain profile created fresh on each runner
15
+ # by the "Import notarization credentials" step below — not a secret,
16
+ # just needs to match between that step and the build step.
17
+ NOTARIZE_PROFILE: privacyfence-ci-notary
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ with:
22
+ fetch-depth: 0 # full history + tags -- setuptools_scm needs them (see CLAUDE.md)
23
+
24
+ - uses: actions/setup-python@v5
25
+ with:
26
+ python-version: '3.12'
27
+
28
+ - name: Install system dependencies
29
+ run: brew install create-dmg
30
+
31
+ - name: Install Python dependencies
32
+ run: pip install -e ".[dev]"
33
+
34
+ # ── Import Developer ID certificate for signing ────────────────────────
35
+ # Requires these GitHub secrets (Settings → Secrets and variables →
36
+ # Actions):
37
+ # MACOS_CERTIFICATE — base64-encoded "Developer ID Application"
38
+ # .p12 (cert + private key) (base64 -i cert.p12 | pbcopy)
39
+ # MACOS_CERTIFICATE_PWD — the .p12 export password
40
+ # SIGN_IDENTITY — e.g. "Developer ID Application: Your Name (TEAMID)"
41
+ - name: Import signing certificate
42
+ env:
43
+ MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
44
+ MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
45
+ run: |
46
+ echo "$MACOS_CERTIFICATE" | base64 --decode > certificate.p12
47
+ security create-keychain -p "" build.keychain
48
+ security default-keychain -s build.keychain
49
+ security unlock-keychain -p "" build.keychain
50
+ security import certificate.p12 -k build.keychain \
51
+ -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
52
+ security set-key-partition-list -S apple-tool:,apple: -s \
53
+ -k "" build.keychain
54
+ rm certificate.p12
55
+
56
+ # ── Import notarization credentials ─────────────────────────────────────
57
+ # Runners are ephemeral, so the notarytool profile is (re-)registered
58
+ # fresh every run rather than assumed to already exist. Requires an
59
+ # App Store Connect API key with the "Developer" role (Users and Access
60
+ # → Integrations → App Store Connect API) and these GitHub secrets:
61
+ # APPLE_API_KEY_P8 — base64-encoded AuthKey_<KEYID>.p8 (base64 -i AuthKey_*.p8 | pbcopy)
62
+ # APPLE_API_KEY_ID — the Key ID shown next to the key
63
+ # APPLE_API_ISSUER_ID — the Issuer ID (same for all keys on the team)
64
+ - name: Import notarization credentials
65
+ env:
66
+ APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }}
67
+ APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
68
+ APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }}
69
+ run: |
70
+ echo "$APPLE_API_KEY_P8" | base64 --decode > apple_api_key.p8
71
+ xcrun notarytool store-credentials "$NOTARIZE_PROFILE" \
72
+ --key apple_api_key.p8 \
73
+ --key-id "$APPLE_API_KEY_ID" \
74
+ --issuer "$APPLE_API_ISSUER_ID"
75
+ rm apple_api_key.p8
76
+
77
+ - name: Build .app and DMG
78
+ env:
79
+ SIGN_IDENTITY: ${{ secrets.SIGN_IDENTITY }}
80
+ TELEGRAM_API_ID: ${{ secrets.TELEGRAM_API_ID }}
81
+ TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }}
82
+ run: bash scripts/build_dmg.sh
83
+
84
+ - name: Upload DMG as artifact
85
+ uses: actions/upload-artifact@v4
86
+ with:
87
+ name: PrivacyFence-dmg
88
+ path: dist/PrivacyFence-*.dmg
89
+ retention-days: 30
90
+
91
+ # Attach to the GitHub Release when triggered by a version tag. A tag
92
+ # ending in -beta/-rc (e.g. v3.2.0-beta) publishes as a GitHub
93
+ # prerelease -- update_checker.py's beta update channel reads exactly
94
+ # this flag off the releases list, so an unmarked tag would be
95
+ # invisible to it.
96
+ #
97
+ # Alongside the DMG, also attach the two org config build scripts
98
+ # (scripts/build_org_bundle.py and scripts/sync_room_directory.py) as
99
+ # their own downloadable assets. They're stdlib-only / a checked-out
100
+ # copy is not what IT admins are expected to go find -- unlike the
101
+ # rest of scripts/, these two are themselves a release output, run by
102
+ # org admins (not contributors) to produce/update the org_config.json
103
+ # bundle distributed to end users -- see their own docstrings and
104
+ # docs/google-cloud-setup.md, docs/slack-setup.md,
105
+ # docs/salesforce-setup.md, docs/atlassian-setup.md.
106
+ - name: Attach release assets
107
+ if: startsWith(github.ref, 'refs/tags/')
108
+ uses: softprops/action-gh-release@v2
109
+ with:
110
+ files: |
111
+ dist/PrivacyFence-*.dmg
112
+ scripts/build_org_bundle.py
113
+ scripts/sync_room_directory.py
114
+ prerelease: ${{ contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}
@@ -0,0 +1,93 @@
1
+ name: Publish to PyPI
2
+
3
+ # Same trigger as build.yml (see CLAUDE.md's "Releasing" section) -- one tag
4
+ # push does everything: builds and signs the DMG (build.yml) *and* builds
5
+ # and publishes the sdist/wheel (this workflow), with no separate step.
6
+ #
7
+ # Publishing itself uses PyPI's OIDC "Trusted Publisher" flow
8
+ # (pypa/gh-action-pypi-publish), not a stored API token: GitHub mints a
9
+ # short-lived OIDC token for the job (permissions: id-token: write below),
10
+ # and PyPI/TestPyPI trade it for a one-shot upload credential themselves.
11
+ # There is no long-lived secret anywhere for this workflow to leak. Before
12
+ # this workflow can publish for the first time, a maintainer has to
13
+ # register it as a Trusted Publisher on both test.pypi.org and pypi.org --
14
+ # see CLAUDE.md.
15
+ on:
16
+ push:
17
+ tags: ['v*']
18
+ workflow_dispatch: # rerun by hand, e.g. after a failed publish -- point it
19
+ # at a tagged commit, or the build carries a local
20
+ # version segment (+g<sha>) that both indexes reject
21
+
22
+ # Restrictive default for GITHUB_TOKEN, per CodeQL's actions/missing-workflow-
23
+ # permissions check -- only `build` actually inherits this (it checks out the
24
+ # repo); the two publish jobs below declare their own narrower job-level
25
+ # `permissions:` (id-token: write only, no contents access at all), which
26
+ # replaces this default for them rather than adding to it.
27
+ permissions:
28
+ contents: read
29
+
30
+ jobs:
31
+ build:
32
+ runs-on: ubuntu-latest # pure Python sdist/wheel -- no macOS-only step needed
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ with:
36
+ fetch-depth: 0 # full history + tags -- setuptools_scm needs them (see CLAUDE.md)
37
+
38
+ - uses: actions/setup-python@v5
39
+ with:
40
+ python-version: '3.13'
41
+
42
+ - name: Build sdist and wheel
43
+ run: |
44
+ pip install --upgrade pip build
45
+ python -m build
46
+
47
+ - uses: actions/upload-artifact@v4
48
+ with:
49
+ name: pypi-dist
50
+ path: dist/
51
+
52
+ # Always published first -- rehearses the real upload (same files, same
53
+ # metadata) against TestPyPI before anything reaches the real index.
54
+ publish-testpypi:
55
+ needs: build
56
+ runs-on: ubuntu-latest
57
+ environment: testpypi # must match the Environment name on TestPyPI's
58
+ # Trusted Publisher entry, if one was set there
59
+ permissions:
60
+ id-token: write
61
+ steps:
62
+ - uses: actions/download-artifact@v4
63
+ with:
64
+ name: pypi-dist
65
+ path: dist/
66
+
67
+ - name: Publish to TestPyPI
68
+ uses: pypa/gh-action-pypi-publish@release/v1
69
+ with:
70
+ repository-url: https://test.pypi.org/legacy/
71
+ skip-existing: true # lets a rerun after a partial failure succeed
72
+ # without erroring on files TestPyPI already has
73
+
74
+ # Gated behind the TestPyPI job above, and behind the "pypi" GitHub
75
+ # Environment's own protection rules if any are configured (e.g. a
76
+ # required reviewer) -- see CLAUDE.md for setting that up.
77
+ publish-pypi:
78
+ needs: publish-testpypi
79
+ runs-on: ubuntu-latest
80
+ environment: pypi # must match the Environment name on PyPI's own
81
+ # Trusted Publisher entry, if one was set there
82
+ permissions:
83
+ id-token: write
84
+ steps:
85
+ - uses: actions/download-artifact@v4
86
+ with:
87
+ name: pypi-dist
88
+ path: dist/
89
+
90
+ - name: Publish to PyPI
91
+ uses: pypa/gh-action-pypi-publish@release/v1
92
+ with:
93
+ skip-existing: true
@@ -0,0 +1,112 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch: # allow manual runs from the Actions tab
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ # macOS-only project (rumps/PyObjC, real Unix-socket/osascript-backed
15
+ # tests) — must run on the same platform the app actually ships for.
16
+ runs-on: macos-latest
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ with:
21
+ fetch-depth: 0 # full history + tags -- setuptools_scm needs them (see CLAUDE.md)
22
+
23
+ - uses: actions/setup-python@v5
24
+ with:
25
+ python-version: '3.13'
26
+
27
+ - uses: actions/setup-node@v4
28
+ with:
29
+ node-version: '22'
30
+
31
+ - name: Install dependencies
32
+ run: pip install -e ".[test]"
33
+
34
+ - name: Install shim dependencies
35
+ run: npm ci
36
+ working-directory: mcpb/shim
37
+
38
+ # mcpb/shim/'s own suite (daemon discovery/launch, the stdio<->
39
+ # Streamable HTTP proxy — see docs/https-connector-refactor-plan.md
40
+ # §12, D11) runs against mcpb/shim/src/*.ts directly via tsx. It's the
41
+ # only Node suite left in this repo since P5 retired the bridge.
42
+ - name: Run shim test suite
43
+ run: npm test
44
+ working-directory: mcpb/shim
45
+
46
+ - name: Type-check shim
47
+ run: npm run typecheck
48
+ working-directory: mcpb/shim
49
+
50
+ # tests/integration/test_shim_mcp_contract.py spawns the real built
51
+ # shim.js against a real /mcp endpoint, so it needs to be built before
52
+ # pytest runs (the test builds it lazily on a cache miss too, but
53
+ # building here keeps that cost out of the timed test step and fails
54
+ # fast on a build error instead of a confusing test skip).
55
+ - name: Build shim
56
+ run: npm run build
57
+ working-directory: mcpb/shim
58
+
59
+ # Plain `pytest` already fails the step (non-zero exit) on the first
60
+ # failing test — no extra flags needed to enforce a 100% pass rate.
61
+ # pytest-timeout (configured in pyproject.toml) also fails any test
62
+ # that hangs, so a stuck test can't stall the job indefinitely. The
63
+ # coverage report here is informational only — nothing gates on it.
64
+ - name: Run test suite (100% pass rate required)
65
+ run: pytest -v --cov=src/privacyfence --cov-report=term-missing
66
+
67
+ test-linux:
68
+ # The platform-independent subset, starting at P1 (see
69
+ # docs/https-connector-refactor-plan.md §12 and
70
+ # docs/testing-policy.md §1): everything under web/, web_approval_ui.py,
71
+ # card_builder.py, and approval_icons.py has no AppKit/PyObjC dependency
72
+ # at all, and is what keeps P10's eventual cross-platform claim honest
73
+ # rather than aspirational. This does not replace the macOS job above --
74
+ # that one still covers the full suite, including everything genuinely
75
+ # macOS-only, and is what a PR needs to pass to merge.
76
+ runs-on: ubuntu-latest
77
+
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+ with:
81
+ fetch-depth: 0 # full history + tags -- setuptools_scm needs them (see CLAUDE.md)
82
+
83
+ - uses: actions/setup-python@v5
84
+ with:
85
+ python-version: '3.13'
86
+
87
+ # rumps/pyobjc-framework-* carry a `sys_platform == 'darwin'` marker
88
+ # (pyproject.toml), so this installs everything else -- the AppKit-only
89
+ # dependencies are simply absent here, same as on any non-macOS
90
+ # PrivacyFence deployment.
91
+ - name: Install dependencies
92
+ run: pip install -e ".[test]"
93
+
94
+ # --ignore the handful of test modules that import an AppKit-tainted
95
+ # module (approval_popup.py, approval_window.py, dialog_window.py,
96
+ # menu_bar.py) directly at module scope, so their absence on this
97
+ # platform is a real ImportError rather than something a skip marker
98
+ # could catch -- see docs/testing-policy.md §1 for the reasoning and
99
+ # the parallel case (test_settings_window.py) that *does* defer its
100
+ # AppKit import far enough to skip cleanly here instead. tests/
101
+ # integration/ is excluded too -- most of it drives the real Node
102
+ # shim, out of scope for this job (covered on the macOS job instead);
103
+ # test_mcp_daemon_contract.py itself needs no Node and could run
104
+ # here, but stays grouped with the rest of the directory for
105
+ # simplicity rather than special-cased out of this ignore.
106
+ - name: Run the platform-independent test subset
107
+ run: >
108
+ pytest tests/unit -v
109
+ --ignore=tests/unit/test_approval_popup.py
110
+ --ignore=tests/unit/test_approval_window.py
111
+ --ignore=tests/unit/test_dialog_window.py
112
+ --ignore=tests/unit/test_menu_bar.py
@@ -0,0 +1,71 @@
1
+ # Credentials and secrets
2
+ credentials/*
3
+ !credentials/.gitkeep
4
+ org/*
5
+ .env
6
+ *.pem
7
+ *.key
8
+ *.p12
9
+ src/privacyfence/_telegram_credentials.py
10
+ scripts/dev_env.sh
11
+ # scripts/sync_room_directory.py's OAuth token for the admin-scoped Google
12
+ # Cloud project it syncs the room directory from -- dev-mode data_dir() is
13
+ # the repo root, same as the other credential paths above.
14
+ .room_sync_token.json
15
+
16
+ # User configuration (keep only the .example)
17
+ config/settings.yaml
18
+ config/settings.local.yaml
19
+
20
+ # Local runtime caches (dev-mode data_dir() is the repo root -- see paths.py)
21
+ resource_name_cache.json
22
+ update_check_cache.json
23
+
24
+ # QA fixture manifest (keep only the .example) -- reveals which real
25
+ # project/space/folder/calendar/list/channel/chat a QA environment uses,
26
+ # on which real accounts. See tests/fixtures/qa_environment.yaml.example.
27
+ tests/fixtures/qa_environment.yaml
28
+
29
+ # Claude Code
30
+ .claude/
31
+
32
+ # Lock files
33
+ *.lock
34
+
35
+ # Python
36
+ *.pyc
37
+ __pycache__/
38
+ *.py[cod]
39
+ *.egg-info/
40
+ .eggs/
41
+ build/
42
+ dist/
43
+ .venv/
44
+ venv/
45
+
46
+ # Node (mcpb/shim/)
47
+ node_modules/
48
+ *.tsbuildinfo
49
+ env/
50
+
51
+ # Test / coverage artifacts
52
+ .coverage
53
+ .coverage.*
54
+ htmlcov/
55
+ coverage.xml
56
+ .pytest_cache/
57
+ .mypy_cache/
58
+ .ruff_cache/
59
+
60
+ # Logs
61
+ *.log
62
+ logs/
63
+
64
+ # macOS
65
+ .DS_Store
66
+ *.dmg
67
+ *.mcpb
68
+
69
+ # IDE
70
+ .idea/
71
+ .vscode/
@@ -0,0 +1,113 @@
1
+ # CLAUDE.md
2
+
3
+ Process notes for working on PrivacyFence with Claude Code. For code/test conventions see
4
+ [`docs/coding-and-testing-guidelines.md`](docs/coding-and-testing-guidelines.md); for contribution
5
+ process (forking, issues, license) see [`CONTRIBUTING.md`](CONTRIBUTING.md). This file covers the
6
+ parts of the workflow that live only in git history, not in a doc — release mechanics and branch
7
+ hygiene.
8
+
9
+ ## Releasing
10
+
11
+ There is no version string in the source tree and no version-bump commit. `pyproject.toml` declares
12
+ `dynamic = ["version"]`; the real version is derived from git tags by `setuptools_scm`
13
+ (`[tool.setuptools_scm]` in `pyproject.toml`), and `src/privacyfence/__init__.py` reads it back at
14
+ import time via `importlib.metadata.version("privacyfence")`. This replaced the old two-file
15
+ hand-bumped scheme (`pyproject.toml`'s `project.version` + `__init__.py`'s `__version__`, kept in
16
+ sync by a dedicated `Bump to vX.Y.Z` commit) specifically to avoid that scheme's failure mode:
17
+ parallel branches (see worktrees below) both claiming the same next version, one bump commit landing
18
+ after another release already took that number (see `d929510`, "Revert version bump — will release
19
+ together with other pending CRs", from back when that was still how it worked).
20
+
21
+ **Cutting a release is a tag, not a commit.** Once `main` is at the commit you want to release, tag
22
+ it and push the tag:
23
+
24
+ ```
25
+ git tag v4.0.0 # stable
26
+ git tag v4.0.0a13 # pre-release: a=alpha, b=beta, rc=release-candidate (PEP 440 short form)
27
+ git push origin <tag>
28
+ ```
29
+
30
+ That tag push is what `.github/workflows/build.yml` **and** `.github/workflows/publish-pypi.yml`
31
+ both trigger on (`on: push: tags: ['v*']`) — the former builds and signs the DMG and attaches it to
32
+ a GitHub Release, marked prerelease iff the tag contains `a`, `b`, or `rc` (`update_checker.py`'s
33
+ beta channel reads exactly that flag); the latter builds the sdist/wheel from the same tag and
34
+ publishes them to PyPI. Nothing else anywhere needs editing or committing first. Between tags,
35
+ `__version__` is a `setuptools_scm`-synthesized dev version (`<next-version>.dev<n>+g<sha>`, e.g.
36
+ `4.0.1.dev3+gabc1234`) — see `update_checker.py`'s module docstring for exactly how that's compared
37
+ against real release tags.
38
+
39
+ A checkout needs its full tag history for this to resolve correctly — a shallow clone (or a tarball
40
+ with no `.git/` at all) falls back to `[tool.setuptools_scm]`'s `fallback_version`, a placeholder
41
+ that's never a real shipped version. `.github/workflows/tests.yml` and `build.yml` both pass
42
+ `fetch-depth: 0` to `actions/checkout` for exactly this reason; do the same in any new workflow that
43
+ installs this package. `scripts/build_dmg.sh` and `scripts/build_mcpb.sh` both read the resolved
44
+ version back via `importlib.metadata.version("privacyfence")`, so they require the package to
45
+ already be `pip install -e .`d (both scripts' own prerequisites say so) — same as
46
+ `PrivacyFenceApp.spec`'s `VERSION` and `src/privacyfence/__init__.py`'s `__version__` itself.
47
+
48
+ `mcpb/shim/package.json`'s `version` field is **not** tied to any of this — leave it as
49
+ `0.0.0-dev`. The shim carries no protocol version of its own to keep in sync with the daemon's (it
50
+ has no tool-schema knowledge at all — see `mcpb/shim/src/index.ts`'s module docstring), so unlike
51
+ the original bridge it replaced (retired at P5, see `docs/https-connector-refactor-plan.md`),
52
+ there's nothing here for the real version to be injected into at build time. `scripts/
53
+ build_mcpb.sh` reads the real version only to stamp the `.mcpb` manifest itself
54
+ (`mcpb/manifest.json.tmpl`'s `__VERSION__`), not anything inside the bundled `shim.js`.
55
+
56
+ ### Publishing to PyPI
57
+
58
+ `publish-pypi.yml` builds the sdist/wheel and publishes to **TestPyPI first, then PyPI**, gated in
59
+ that order (`publish-pypi` job's `needs: publish-testpypi`) — a broken publish never reaches the
60
+ real index. It authenticates with neither project via a stored API token: both use PyPI's OIDC
61
+ **Trusted Publisher** mechanism (`pypa/gh-action-pypi-publish`, `permissions: id-token: write`),
62
+ so GitHub mints a short-lived token for the job and PyPI/TestPyPI trade it for a one-shot upload
63
+ credential themselves. There is no long-lived secret in this repo for either index.
64
+
65
+ Before the workflow can publish for the first time, register it as a Trusted Publisher on **both**
66
+ services — the project need not already exist there; both accept a "pending" publisher for a name
67
+ that isn't claimed yet, and claim it on the first successful publish. Do this once per service:
68
+
69
+ 1. Sign in and go to `test.pypi.org/manage/account/publishing/` (repeat later, separately, on
70
+ `pypi.org/manage/account/publishing/` — the two are unrelated accounts/registrations even if you
71
+ use the same login for both).
72
+ 2. Add a pending publisher with:
73
+ - **PyPI Project Name**: `privacyfence`
74
+ - **Owner**: `andras-tkcs`
75
+ - **Repository name**: `privacyfence`
76
+ - **Workflow name**: `publish-pypi.yml`
77
+ - **Environment name**: `testpypi` (on TestPyPI) / `pypi` (on PyPI) — matches the `environment:`
78
+ each job in `publish-pypi.yml` declares. Scoping the publisher to an environment means the
79
+ minted OIDC token is only ever valid for that job, not any other job in this repo.
80
+
81
+ Optionally, also create matching GitHub Environments (repo **Settings → Environments**) named
82
+ `testpypi` and `pypi`. This isn't required for the OIDC exchange itself, but it's where you'd add a
83
+ **required reviewer** on the `pypi` environment if you want a manual go/no-go checkpoint between the
84
+ TestPyPI publish succeeding and the real PyPI publish running — the "test first" step the workflow
85
+ already enforces via job ordering, made into an explicit approval gate rather than just a rerun-only
86
+ safety net.
87
+
88
+ `workflow_dispatch` exists for rerunning by hand (e.g. after a transient failure) — point it at a
89
+ tagged commit. Run from an untagged commit and `setuptools_scm` produces a dev version with a local
90
+ segment (`+g<sha>`), which both indexes reject as an upload.
91
+
92
+ ## Branching & PRs
93
+
94
+ - Branch names are `<type>/<kebab-case-description>`. Standard types: `feature/` for new
95
+ functionality, `fix/` for bug fixes, `chore/` for non-functional maintenance, `tests/` for
96
+ test-only changes. Use `feature/`, not `feat/` — a few early branches used `feat/` before this
97
+ was settled; that prefix is retired, don't reintroduce it on new branches.
98
+ - `main` is protected — all changes land via PR (`CONTRIBUTING.md`). PRs merge with a real merge
99
+ commit (`Merge pull request #N from <fork>/<branch>`), not squash — keep that in mind when writing
100
+ commit messages on a feature branch, since they survive into `main`'s history individually.
101
+ - Definition of done for a PR is the checklist in
102
+ [`docs/coding-and-testing-guidelines.md` §2.7](docs/coding-and-testing-guidelines.md#27-definition-of-done-for-a-pr-touching-this-repo).
103
+
104
+ ## Parallel sessions & worktrees
105
+
106
+ The user regularly runs multiple Claude Code sessions on this repo at once, each on a different
107
+ task/branch. To avoid one session's checkout state (branch switches, uncommitted edits) interfering
108
+ with another's:
109
+
110
+ - Start new work in its own `git worktree` under `~/Coding/worktrees/`, not by switching branches
111
+ in whichever checkout happens to be open. Naming convention already in use:
112
+ `~/Coding/worktrees/privacyfence-<short-branch-slug>` (e.g. `privacyfence-fix-tasks-ssl`).
113
+ - Don't reuse an existing worktree for an unrelated task — one worktree per active branch/task.
@@ -0,0 +1,50 @@
1
+ # Contributing to PrivacyFence
2
+
3
+ ## Forking
4
+
5
+ You're welcome to fork PrivacyFence and build on it. If you publish a fork or
6
+ derivative project, a brief note to the author (privacyfence@tkcs.name or
7
+ open a GitHub issue) is appreciated — not required, just courteous. See `NOTICE`
8
+ for details.
9
+
10
+ ## Pull Requests
11
+
12
+ All changes to `main` go through pull requests. Direct pushes are blocked.
13
+
14
+ 1. Fork the repo and create a feature branch off `main`.
15
+ 2. Keep PRs focused — one logical change per PR.
16
+ 3. Describe *why* the change is needed, not just what it does.
17
+ 4. PRs require review and approval from the maintainer before merging.
18
+ 5. Before opening a PR, work through the checklist in
19
+ [`docs/coding-and-testing-guidelines.md` §2.7](docs/coding-and-testing-guidelines.md#27-definition-of-done-for-a-pr-touching-this-repo)
20
+ — it covers required test coverage and when a local QA check needs to be run and pasted into the
21
+ PR description. See [`docs/testing-policy.md`](docs/testing-policy.md) for which checks run in CI
22
+ versus which ones you run locally.
23
+
24
+ ## Issues
25
+
26
+ Use GitHub Issues for bug reports and feature requests. Include:
27
+ - macOS version and Python version
28
+ - Steps to reproduce (for bugs)
29
+ - What connector is involved, if relevant
30
+
31
+ ## Code Style
32
+
33
+ - `src/privacyfence/` (the daemon): Python 3.11+, standard library preferred over new dependencies
34
+ - `mcpb/shim/` (the `.mcpb`'s stdio-to-Streamable-HTTP transport proxy, D11 in
35
+ [`docs/https-connector-refactor-plan.md`](docs/https-connector-refactor-plan.md) — the sole way Claude
36
+ Desktop reaches the daemon since P5 retired the original MCP bridge): TypeScript/Node, kept as a
37
+ separate language from the daemon so the `.mcpb` extension ships without a bundled Python runtime;
38
+ carries no tool-schema knowledge, so it stays small on purpose — see its own `src/index.ts` module
39
+ docstring before adding anything to it
40
+ - No comments unless the *why* is non-obvious
41
+ - Match the surrounding code's style
42
+
43
+ See [`docs/coding-and-testing-guidelines.md`](docs/coding-and-testing-guidelines.md) for the full,
44
+ codebase-derived conventions this project follows — coding patterns, the gate's security
45
+ invariants, and how to structure and write tests for `src/privacyfence/`.
46
+
47
+ ## License
48
+
49
+ By submitting a pull request you agree that your contribution is licensed under
50
+ the Apache License 2.0, the same license as this project.