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.
- privacyfence-4.0.0a11/.github/CODEOWNERS +2 -0
- privacyfence-4.0.0a11/.github/workflows/build.yml +114 -0
- privacyfence-4.0.0a11/.github/workflows/publish-pypi.yml +93 -0
- privacyfence-4.0.0a11/.github/workflows/tests.yml +112 -0
- privacyfence-4.0.0a11/.gitignore +71 -0
- privacyfence-4.0.0a11/CLAUDE.md +113 -0
- privacyfence-4.0.0a11/CONTRIBUTING.md +50 -0
- privacyfence-4.0.0a11/LICENSE +185 -0
- privacyfence-4.0.0a11/NOTICE +36 -0
- privacyfence-4.0.0a11/PKG-INFO +354 -0
- privacyfence-4.0.0a11/PrivacyFenceApp.spec +167 -0
- privacyfence-4.0.0a11/README.md +310 -0
- privacyfence-4.0.0a11/com.privacyfence.app.plist +53 -0
- privacyfence-4.0.0a11/credentials/.gitkeep +0 -0
- privacyfence-4.0.0a11/docs/TECHNICAL_REFERENCE.md +1514 -0
- privacyfence-4.0.0a11/docs/always-allow-rules-reference.md +376 -0
- privacyfence-4.0.0a11/docs/approval-list-ui-ux.md +595 -0
- privacyfence-4.0.0a11/docs/approval-window-content-reference.md +290 -0
- privacyfence-4.0.0a11/docs/atlassian-setup.md +92 -0
- privacyfence-4.0.0a11/docs/claude-knowledge-boundary.md +315 -0
- privacyfence-4.0.0a11/docs/coding-and-testing-guidelines.md +247 -0
- privacyfence-4.0.0a11/docs/connector-qa-testing.md +1274 -0
- privacyfence-4.0.0a11/docs/dev-vs-live-setup.md +109 -0
- privacyfence-4.0.0a11/docs/file-type-support.md +114 -0
- privacyfence-4.0.0a11/docs/google-cloud-setup.md +146 -0
- privacyfence-4.0.0a11/docs/https-connector-refactor-plan.md +1924 -0
- privacyfence-4.0.0a11/docs/images/architecture.svg +114 -0
- privacyfence-4.0.0a11/docs/images/screenshots/README.md +38 -0
- privacyfence-4.0.0a11/docs/images/screenshots/gmail-read-thread.png +0 -0
- privacyfence-4.0.0a11/docs/images/screenshots/menubar-auto-accept-rules.png +0 -0
- privacyfence-4.0.0a11/docs/images/screenshots/menubar.png +0 -0
- privacyfence-4.0.0a11/docs/images/screenshots/sheets-write.png +0 -0
- privacyfence-4.0.0a11/docs/manual-pre-release-test-plan.md +176 -0
- privacyfence-4.0.0a11/docs/mockups/approval-list.html +755 -0
- privacyfence-4.0.0a11/docs/pii-detection-keywords.md +95 -0
- privacyfence-4.0.0a11/docs/qa-environment-setup.md +621 -0
- privacyfence-4.0.0a11/docs/salesforce-setup.md +81 -0
- privacyfence-4.0.0a11/docs/security-and-compliance.md +355 -0
- privacyfence-4.0.0a11/docs/slack-setup.md +111 -0
- privacyfence-4.0.0a11/docs/telegram-setup.md +65 -0
- privacyfence-4.0.0a11/docs/testing-policy.md +253 -0
- privacyfence-4.0.0a11/mcpb/manifest.json.tmpl +25 -0
- privacyfence-4.0.0a11/mcpb/shim/build.mjs +23 -0
- privacyfence-4.0.0a11/mcpb/shim/package-lock.json +1754 -0
- privacyfence-4.0.0a11/mcpb/shim/package.json +22 -0
- privacyfence-4.0.0a11/mcpb/shim/src/daemon.ts +208 -0
- privacyfence-4.0.0a11/mcpb/shim/src/errors.ts +17 -0
- privacyfence-4.0.0a11/mcpb/shim/src/index.ts +159 -0
- privacyfence-4.0.0a11/mcpb/shim/src/protocol.ts +44 -0
- privacyfence-4.0.0a11/mcpb/shim/src/proxy.ts +49 -0
- privacyfence-4.0.0a11/mcpb/shim/test/daemon.test.ts +225 -0
- privacyfence-4.0.0a11/mcpb/shim/test/fakeMcpDaemon.ts +69 -0
- privacyfence-4.0.0a11/mcpb/shim/test/index.test.ts +86 -0
- privacyfence-4.0.0a11/mcpb/shim/test/protocol.test.ts +42 -0
- privacyfence-4.0.0a11/mcpb/shim/test/proxy.test.ts +92 -0
- privacyfence-4.0.0a11/mcpb/shim/test/testFiles.ts +59 -0
- privacyfence-4.0.0a11/mcpb/shim/tsconfig.json +19 -0
- privacyfence-4.0.0a11/privacyfence.service +62 -0
- privacyfence-4.0.0a11/pyproject.toml +137 -0
- privacyfence-4.0.0a11/scripts/build_dmg.sh +173 -0
- privacyfence-4.0.0a11/scripts/build_mcpb.sh +81 -0
- privacyfence-4.0.0a11/scripts/build_org_bundle.py +292 -0
- privacyfence-4.0.0a11/scripts/dev_start.sh +104 -0
- privacyfence-4.0.0a11/scripts/entitlements.plist +25 -0
- privacyfence-4.0.0a11/scripts/pre_release_check.py +75 -0
- privacyfence-4.0.0a11/scripts/qa_fixture_recorder.py +1387 -0
- privacyfence-4.0.0a11/scripts/qa_list_ids.py +88 -0
- privacyfence-4.0.0a11/scripts/qa_popup_smoke.py +3765 -0
- privacyfence-4.0.0a11/scripts/qa_web_smoke.py +239 -0
- privacyfence-4.0.0a11/scripts/slack_call_budget.py +253 -0
- privacyfence-4.0.0a11/scripts/sync_room_directory.py +142 -0
- privacyfence-4.0.0a11/setup.cfg +4 -0
- privacyfence-4.0.0a11/src/_daemon_entry.py +17 -0
- privacyfence-4.0.0a11/src/privacyfence/__init__.py +16 -0
- privacyfence-4.0.0a11/src/privacyfence/app_credentials.py +30 -0
- privacyfence-4.0.0a11/src/privacyfence/approval_icons.py +58 -0
- privacyfence-4.0.0a11/src/privacyfence/approval_list_html.py +273 -0
- privacyfence-4.0.0a11/src/privacyfence/approval_popup.py +278 -0
- privacyfence-4.0.0a11/src/privacyfence/approval_ui.py +160 -0
- privacyfence-4.0.0a11/src/privacyfence/approval_window.py +832 -0
- privacyfence-4.0.0a11/src/privacyfence/approval_window_html.py +875 -0
- privacyfence-4.0.0a11/src/privacyfence/approvals.py +521 -0
- privacyfence-4.0.0a11/src/privacyfence/apps_script_client.py +342 -0
- privacyfence-4.0.0a11/src/privacyfence/atlassian_oauth.py +229 -0
- privacyfence-4.0.0a11/src/privacyfence/audit_log.py +405 -0
- privacyfence-4.0.0a11/src/privacyfence/auto_accept.py +1679 -0
- privacyfence-4.0.0a11/src/privacyfence/calendar_client.py +745 -0
- privacyfence-4.0.0a11/src/privacyfence/card_builder.py +138 -0
- privacyfence-4.0.0a11/src/privacyfence/confluence_client.py +624 -0
- privacyfence-4.0.0a11/src/privacyfence/connector.py +90 -0
- privacyfence-4.0.0a11/src/privacyfence/connector_host.py +61 -0
- privacyfence-4.0.0a11/src/privacyfence/connector_registry.py +141 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/__init__.py +2 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/apps_script.py +316 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/calendar.py +765 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/confluence.py +551 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/contacts.py +422 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/drive.py +1598 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/gmail.py +1315 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/jira.py +447 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/salesforce.py +434 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/slack.py +732 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/tasks.py +380 -0
- privacyfence-4.0.0a11/src/privacyfence/connectors/telegram.py +304 -0
- privacyfence-4.0.0a11/src/privacyfence/contacts_client.py +681 -0
- privacyfence-4.0.0a11/src/privacyfence/daemon_main.py +1142 -0
- privacyfence-4.0.0a11/src/privacyfence/dialog_window.py +296 -0
- privacyfence-4.0.0a11/src/privacyfence/dialog_window_html.py +240 -0
- privacyfence-4.0.0a11/src/privacyfence/drive_client.py +2631 -0
- privacyfence-4.0.0a11/src/privacyfence/email_markdown.py +184 -0
- privacyfence-4.0.0a11/src/privacyfence/gate.py +1277 -0
- privacyfence-4.0.0a11/src/privacyfence/gmail_client.py +1261 -0
- privacyfence-4.0.0a11/src/privacyfence/html_to_text.py +250 -0
- privacyfence-4.0.0a11/src/privacyfence/jira_client.py +457 -0
- privacyfence-4.0.0a11/src/privacyfence/markdown_to_html.py +118 -0
- privacyfence-4.0.0a11/src/privacyfence/menu_bar.py +129 -0
- privacyfence-4.0.0a11/src/privacyfence/oauth_loopback.py +196 -0
- privacyfence-4.0.0a11/src/privacyfence/org_identity.py +219 -0
- privacyfence-4.0.0a11/src/privacyfence/org_mode.py +80 -0
- privacyfence-4.0.0a11/src/privacyfence/paths.py +133 -0
- privacyfence-4.0.0a11/src/privacyfence/pii_detector.py +448 -0
- privacyfence-4.0.0a11/src/privacyfence/principal.py +193 -0
- privacyfence-4.0.0a11/src/privacyfence/privacy_filter.py +167 -0
- privacyfence-4.0.0a11/src/privacyfence/resource_grants.py +626 -0
- privacyfence-4.0.0a11/src/privacyfence/resource_names.py +134 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/approval_window/fonts/OFL.txt +93 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/approval_window/fonts/SourceSerif4-Italic.woff2 +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/approval_window/fonts/SourceSerif4-Regular.woff2 +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/approval_window/fonts/SourceSerif4-SemiBold.woff2 +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/approval_window/styles.css +447 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/README.md +47 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/calendar.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/confluence.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/contacts.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/drive.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/gmail.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/jira.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/salesforce.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/slack.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/tasks.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/connector_icons/telegram.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/icon_32.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/icon_512.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/icon_64.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/icon_menubar.png +0 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/settings.yaml.example +296 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/sw.js +43 -0
- privacyfence-4.0.0a11/src/privacyfence/resources/tokens.css +120 -0
- privacyfence-4.0.0a11/src/privacyfence/room_directory_client.py +151 -0
- privacyfence-4.0.0a11/src/privacyfence/salesforce_client.py +406 -0
- privacyfence-4.0.0a11/src/privacyfence/settings_controller.py +1883 -0
- privacyfence-4.0.0a11/src/privacyfence/settings_window.py +264 -0
- privacyfence-4.0.0a11/src/privacyfence/settings_window_html.py +1208 -0
- privacyfence-4.0.0a11/src/privacyfence/slack_client.py +1774 -0
- privacyfence-4.0.0a11/src/privacyfence/tasks_client.py +338 -0
- privacyfence-4.0.0a11/src/privacyfence/telegram_client.py +597 -0
- privacyfence-4.0.0a11/src/privacyfence/text_extraction.py +376 -0
- privacyfence-4.0.0a11/src/privacyfence/update_checker.py +253 -0
- privacyfence-4.0.0a11/src/privacyfence/web/__init__.py +14 -0
- privacyfence-4.0.0a11/src/privacyfence/web/mcp_auth.py +101 -0
- privacyfence-4.0.0a11/src/privacyfence/web/mcp_dispatch.py +396 -0
- privacyfence-4.0.0a11/src/privacyfence/web/mcp_tools.py +281 -0
- privacyfence-4.0.0a11/src/privacyfence/web/oauth_provider.py +369 -0
- privacyfence-4.0.0a11/src/privacyfence/web/org_session.py +129 -0
- privacyfence-4.0.0a11/src/privacyfence/web/routes_approvals.py +305 -0
- privacyfence-4.0.0a11/src/privacyfence/web/routes_mcp.py +313 -0
- privacyfence-4.0.0a11/src/privacyfence/web/routes_org_identity.py +186 -0
- privacyfence-4.0.0a11/src/privacyfence/web/routes_settings.py +360 -0
- privacyfence-4.0.0a11/src/privacyfence/web/server.py +626 -0
- privacyfence-4.0.0a11/src/privacyfence/web/session_auth.py +66 -0
- privacyfence-4.0.0a11/src/privacyfence/web/state_stream.py +176 -0
- privacyfence-4.0.0a11/src/privacyfence/web_approval_ui.py +201 -0
- privacyfence-4.0.0a11/src/privacyfence/web_prompt.py +76 -0
- privacyfence-4.0.0a11/src/privacyfence/web_shell.py +356 -0
- privacyfence-4.0.0a11/src/privacyfence.egg-info/PKG-INFO +354 -0
- privacyfence-4.0.0a11/src/privacyfence.egg-info/SOURCES.txt +284 -0
- privacyfence-4.0.0a11/src/privacyfence.egg-info/dependency_links.txt +1 -0
- privacyfence-4.0.0a11/src/privacyfence.egg-info/entry_points.txt +2 -0
- privacyfence-4.0.0a11/src/privacyfence.egg-info/requires.txt +36 -0
- privacyfence-4.0.0a11/src/privacyfence.egg-info/scm_file_list.json +280 -0
- privacyfence-4.0.0a11/src/privacyfence.egg-info/scm_version.json +8 -0
- privacyfence-4.0.0a11/src/privacyfence.egg-info/top_level.txt +1 -0
- privacyfence-4.0.0a11/tests/__init__.py +0 -0
- privacyfence-4.0.0a11/tests/conftest.py +47 -0
- privacyfence-4.0.0a11/tests/fixtures/live/README.md +17 -0
- privacyfence-4.0.0a11/tests/fixtures/live/calendar/get_event.json +33 -0
- privacyfence-4.0.0a11/tests/fixtures/live/confluence/get_page.json +34 -0
- privacyfence-4.0.0a11/tests/fixtures/live/confluence/list_spaces.json +29 -0
- privacyfence-4.0.0a11/tests/fixtures/live/contacts/get_contact.json +73 -0
- privacyfence-4.0.0a11/tests/fixtures/live/drive/get_file_metadata.json +17 -0
- privacyfence-4.0.0a11/tests/fixtures/live/gmail/get_message.json +82 -0
- privacyfence-4.0.0a11/tests/fixtures/live/jira/get_issue.json +171 -0
- privacyfence-4.0.0a11/tests/fixtures/live/jira/list_projects.json +22 -0
- privacyfence-4.0.0a11/tests/fixtures/live/salesforce/get_record.json +76 -0
- privacyfence-4.0.0a11/tests/fixtures/live/salesforce/list_reports.json +17 -0
- privacyfence-4.0.0a11/tests/fixtures/live/slack/get_thread_replies.json +96 -0
- privacyfence-4.0.0a11/tests/fixtures/live/tasks/get_task.json +13 -0
- privacyfence-4.0.0a11/tests/fixtures/live/telegram/get_messages.json +60 -0
- privacyfence-4.0.0a11/tests/fixtures/qa_assets/lorem_ipsum.docx +0 -0
- privacyfence-4.0.0a11/tests/fixtures/qa_environment.yaml.example +126 -0
- privacyfence-4.0.0a11/tests/helpers.py +120 -0
- privacyfence-4.0.0a11/tests/integration/__init__.py +1 -0
- privacyfence-4.0.0a11/tests/integration/test_mcp_daemon_contract.py +157 -0
- privacyfence-4.0.0a11/tests/integration/test_shim_mcp_contract.py +206 -0
- privacyfence-4.0.0a11/tests/unit/__init__.py +0 -0
- privacyfence-4.0.0a11/tests/unit/connectors/__init__.py +0 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_apps_script_connector.py +326 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_calendar_connector.py +795 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_confluence_connector.py +760 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_contacts_connector.py +452 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_drive_connector.py +1792 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_gmail_connector.py +1407 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_jira_connector.py +557 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_readme_manifest_alignment.py +162 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_salesforce_connector.py +545 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_slack_connector.py +918 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_tasks_connector.py +415 -0
- privacyfence-4.0.0a11/tests/unit/connectors/test_telegram_connector.py +326 -0
- privacyfence-4.0.0a11/tests/unit/test_app_credentials.py +86 -0
- privacyfence-4.0.0a11/tests/unit/test_approval_icons.py +45 -0
- privacyfence-4.0.0a11/tests/unit/test_approval_list_html.py +79 -0
- privacyfence-4.0.0a11/tests/unit/test_approval_popup.py +324 -0
- privacyfence-4.0.0a11/tests/unit/test_approval_ui.py +151 -0
- privacyfence-4.0.0a11/tests/unit/test_approval_window.py +749 -0
- privacyfence-4.0.0a11/tests/unit/test_approval_window_html.py +752 -0
- privacyfence-4.0.0a11/tests/unit/test_approvals.py +466 -0
- privacyfence-4.0.0a11/tests/unit/test_apps_script_client.py +492 -0
- privacyfence-4.0.0a11/tests/unit/test_atlassian_oauth.py +328 -0
- privacyfence-4.0.0a11/tests/unit/test_audit_log.py +371 -0
- privacyfence-4.0.0a11/tests/unit/test_auto_accept.py +2134 -0
- privacyfence-4.0.0a11/tests/unit/test_calendar_client.py +1056 -0
- privacyfence-4.0.0a11/tests/unit/test_card_builder.py +127 -0
- privacyfence-4.0.0a11/tests/unit/test_confluence_client.py +776 -0
- privacyfence-4.0.0a11/tests/unit/test_connector.py +70 -0
- privacyfence-4.0.0a11/tests/unit/test_connector_registry.py +188 -0
- privacyfence-4.0.0a11/tests/unit/test_contacts_client.py +945 -0
- privacyfence-4.0.0a11/tests/unit/test_daemon_main.py +1795 -0
- privacyfence-4.0.0a11/tests/unit/test_dialog_window.py +310 -0
- privacyfence-4.0.0a11/tests/unit/test_dialog_window_html.py +162 -0
- privacyfence-4.0.0a11/tests/unit/test_drive_client.py +3546 -0
- privacyfence-4.0.0a11/tests/unit/test_email_markdown.py +123 -0
- privacyfence-4.0.0a11/tests/unit/test_gate.py +2633 -0
- privacyfence-4.0.0a11/tests/unit/test_gate_real_evaluator.py +828 -0
- privacyfence-4.0.0a11/tests/unit/test_gmail_client.py +1824 -0
- privacyfence-4.0.0a11/tests/unit/test_html_to_text.py +213 -0
- privacyfence-4.0.0a11/tests/unit/test_jira_client.py +682 -0
- privacyfence-4.0.0a11/tests/unit/test_markdown_to_html.py +140 -0
- privacyfence-4.0.0a11/tests/unit/test_menu_bar.py +141 -0
- privacyfence-4.0.0a11/tests/unit/test_oauth_loopback.py +306 -0
- privacyfence-4.0.0a11/tests/unit/test_org_identity.py +316 -0
- privacyfence-4.0.0a11/tests/unit/test_org_mode.py +73 -0
- privacyfence-4.0.0a11/tests/unit/test_p6_principal_isolation.py +203 -0
- privacyfence-4.0.0a11/tests/unit/test_paths.py +197 -0
- privacyfence-4.0.0a11/tests/unit/test_pii_detector.py +528 -0
- privacyfence-4.0.0a11/tests/unit/test_principal.py +211 -0
- privacyfence-4.0.0a11/tests/unit/test_privacy_filter.py +167 -0
- privacyfence-4.0.0a11/tests/unit/test_qa_fixture_recorder.py +1265 -0
- privacyfence-4.0.0a11/tests/unit/test_resource_grants.py +695 -0
- privacyfence-4.0.0a11/tests/unit/test_resource_names.py +155 -0
- privacyfence-4.0.0a11/tests/unit/test_room_directory_client.py +220 -0
- privacyfence-4.0.0a11/tests/unit/test_salesforce_client.py +659 -0
- privacyfence-4.0.0a11/tests/unit/test_settings_controller.py +1698 -0
- privacyfence-4.0.0a11/tests/unit/test_settings_window.py +274 -0
- privacyfence-4.0.0a11/tests/unit/test_settings_window_html.py +387 -0
- privacyfence-4.0.0a11/tests/unit/test_slack_client.py +2260 -0
- privacyfence-4.0.0a11/tests/unit/test_tasks_client.py +570 -0
- privacyfence-4.0.0a11/tests/unit/test_telegram_client.py +801 -0
- privacyfence-4.0.0a11/tests/unit/test_text_extraction.py +393 -0
- privacyfence-4.0.0a11/tests/unit/test_update_checker.py +408 -0
- privacyfence-4.0.0a11/tests/unit/test_web_approval_ui.py +266 -0
- privacyfence-4.0.0a11/tests/unit/test_web_prompt.py +151 -0
- privacyfence-4.0.0a11/tests/unit/test_web_shell.py +167 -0
- privacyfence-4.0.0a11/tests/unit/web/__init__.py +0 -0
- privacyfence-4.0.0a11/tests/unit/web/test_mcp_auth.py +51 -0
- privacyfence-4.0.0a11/tests/unit/web/test_mcp_dispatch.py +534 -0
- privacyfence-4.0.0a11/tests/unit/web/test_oauth_provider.py +348 -0
- privacyfence-4.0.0a11/tests/unit/web/test_org_mcp_e2e.py +272 -0
- privacyfence-4.0.0a11/tests/unit/web/test_org_session.py +118 -0
- privacyfence-4.0.0a11/tests/unit/web/test_routes_approvals.py +339 -0
- privacyfence-4.0.0a11/tests/unit/web/test_routes_mcp.py +285 -0
- privacyfence-4.0.0a11/tests/unit/web/test_routes_mcp_principal.py +83 -0
- privacyfence-4.0.0a11/tests/unit/web/test_routes_org_identity.py +244 -0
- privacyfence-4.0.0a11/tests/unit/web/test_routes_settings.py +416 -0
- privacyfence-4.0.0a11/tests/unit/web/test_server.py +377 -0
- privacyfence-4.0.0a11/tests/unit/web/test_server_org_mode.py +151 -0
- privacyfence-4.0.0a11/tests/unit/web/test_state_stream.py +161 -0
|
@@ -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.
|