matrx-orm 3.1.140__tar.gz → 3.1.141__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.
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/PKG-INFO +2 -2
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/secrets_battery/FEATURE.md +10 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/secrets_battery/__init__.py +2 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/secrets_battery/items.py +181 -74
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/secrets_battery/model.py +1 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/secrets_battery/org_service.py +92 -43
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/secrets_battery/service.py +9 -3
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/pyproject.toml +2 -2
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_secrets_battery.py +79 -2
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_secrets_minting_keys.py +5 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/.gitignore +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/AGENTS.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/BASE_CLASS_METHODS.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/CLAUDE.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/MODEL_API.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/database/orm/extended/managers/ai_model_base.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/docs/migrations.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/FEATURE.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/adapters/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/adapters/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/adapters/async_postgresql.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/adapters/base_adapter.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/adapters/postgresql.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/adapters/supabase_adapter.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/admin/FEATURE.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/admin/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/admin/router.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/api/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/api/auth.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/api/config.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/api/handlers.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/api/protocol.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/api/server.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/associations.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/cache_debug.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/catalog.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/catalog_sql.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/client/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/client/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/client/postgres_connection.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/client/postgrest.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/client/supabase_auth.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/client/supabase_config.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/client/supabase_manager.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/EXTENDED-TASK.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/FEATURE.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/TASKS.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/async_db_manager.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/base.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/config.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/connections.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/db_function.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/diagnostics.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/expressions.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/extended.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/fields.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/introspection.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/listen.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/loop_filters.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/model_dto.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/model_view.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/one_database.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/paginator.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/pool_maintenance.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/pool_watch.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/pooler_role.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/pydantic_bridge.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/registry.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/relations.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/resilience.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/rls_session.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/session_context.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/signals.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/tls.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/transaction.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/types.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/core/write_queue.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/entity.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/error_handling.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/exceptions.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/extended/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/extended/app_error_handler.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/identity_rule.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/local_sqlite.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/middleware/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/middleware/base.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/cli.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/ddl.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/diff.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/executor.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/integration.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/loader.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/operations.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/state.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/migrations/table_filter.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/no_org_assignment.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/FEATURE.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/bulk_update_values.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/catalog_select.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/conflict.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/conflict_writes.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/create.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/db_functions.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/delete.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/dynamic_admin.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/dynamic_crud.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/graph_walk.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/latest_rows.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/queue_claim.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/read.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/relational_backfill.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/staging_load.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/operations/update.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/platform_access.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/platform_db.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/py.typed +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/pytest_plugin.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/python_sql/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/python_sql/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/python_sql/db_objects.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/query/FEATURE.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/query/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/query/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/query/builder.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/query/executor.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/resources/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/FEATURE.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/code_handler.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/codegen_writer.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/columns.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/common.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/diff_preview.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/generator.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/package_wiring.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/relationships.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/runner.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/schema.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/schema_manager.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/tables.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/schema_builder/views.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/secrets_battery/attachments.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/secrets_battery/crypto.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/secrets_battery/host_authorization.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/coalesce.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/dag.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/errors.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/fallback.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/flush.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/lifecycle.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/managed.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/op.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/reads.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/session.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/session/telemetry.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/sql_executor/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/sql_executor/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/sql_executor/executor.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/sql_executor/queries.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/sql_executor/registry.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/sql_executor/types.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/sql_executor/utils.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/state.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/utils/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/utils/sql_utils.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/matrx_orm/utils/type_converters.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/scripts/git-branches.sh +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/scripts/publish.sh +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/scripts/release.sh +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/conftest.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_adapter_registry.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_admin_db_columns.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_admin_response_rendering.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_admin_search_negation.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_admin_search_sentinels.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_advisory_lock.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_agent_message.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_api_auth.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_api_config.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_api_handlers.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_api_protocol.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_array_agg_order_by.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_associations.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_associations_wiring.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_bulk_hydration_offload.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_bulk_update_by_pk.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_cache_debug.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_call_function.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_case_when.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_catalog.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_composite_pk_filter.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_composite_pk_write_paths.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_config.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_conflict_target.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_conflict_writes.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_connection_codecs.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_connection_poison_guard.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_connection_primitives.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_count_composite_distinct.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_count_limit_param_leak.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_db_function_field.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_ddl_generator.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_derived_table.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_dirty_tracking.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_dynamic_crud.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_exceptions.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_expression_primitives.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_fields.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_from_alias.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_fts.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_func_expression_args.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_graph_walk.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_having_annotate_alias.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_introspect_rls_policies.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_join_and_aggregate.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_latest_rows.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_listen_notify.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_local_sqlite.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_lock_contention_retry.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_managed_write_guard.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_matrx_entity.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_migration_diff_types.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_migration_loader.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_model_instance.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_model_meta.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_optimistic_concurrency.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_order_by_expression.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_org_assignment_inventory.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_parameter_name_hydration.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_patch_jsonb_path.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_persisted_count.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_pool_holder_census.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_pool_loop_recreation.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_pool_maintenance.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_postgrest_filters.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_pydantic_bridge.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_query_builder.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_query_error_detail.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_query_executor_sql.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_query_timeout.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_queue_claim.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_read_connection_retry.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_registry.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_registry_multi_database.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_registry_multi_schema.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_relational_backfill.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_relations.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_resilience.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_rls_session_scope.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_schema_exists.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_session_advisory_lock.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_standalone_write_session_context.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_state_cache.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_subquery_filter_raw.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_subquery_in_filter.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_subquery_nested_expressions.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_supabase_auth.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_supabase_config.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_tls.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_typed_join_projection.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_typed_predicates.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_update_case_expression.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_update_subquery.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_update_with_rebase.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_upsert_default_leak.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_upsert_with_conflict.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_values_jsonb_decode.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_watched_lifecycle.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_write_queue_deadline.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level1/test_write_retry_semantics.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/MODULE_README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/conftest.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/test_bulk_ops.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/test_cache_integration.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/test_crud.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/test_foreign_keys.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/test_m2m.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/test_manager.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/test_migrations_live.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/test_query_execution.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/level2/test_schema_diff.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/live_pooler_role.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project/.env.example +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project/README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project/generate.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project/generated/.gitkeep +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project/matrx_orm.yaml +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project/test_schema_generation.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project_desktop/.env.example +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project_desktop/README.md +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project_desktop/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project_desktop/client_example.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project_desktop/client_example.ts +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project_desktop/client_supabase_example.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/sample_project_desktop/server.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/entity_tests.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_base_generation.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_composite_pk_fk_generation.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_composite_unique_generation.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_dto_identity_generation.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_entity_capability_generation.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_enum_ordering.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_generate_schema.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_junction_analysis.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_multi_schema_output.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_schema_analysis.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_sql_expression_defaults.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_table_relationships_query.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema/test_view_generation.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema_builder/test_array_default_parsing.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema_builder/test_focused_generation_plan.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/schema_builder/test_host_models_aggregator.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/__init__.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/conftest.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_cache_no_downgrade.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_capture_poison_proof.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_coalesce.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_dag.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_disk_spill_fallback.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_flush_individual_fallback.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_governed_write.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_managed.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_op_enqueue_site.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_reads.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_record_error_bounded_insert.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_record_error_storm.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_session.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/session/test_spill_guard_plugin.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_array_arg_element_type.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_database_name_alias.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_db_functions.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_dynamic_select_unregistered.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_keyed_digest.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_model_cls_refactor.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_no_blocking_asyncpg_tls.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_one_database.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_order_by_desc_nulls_last.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_pooler_role_guard.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_sql_param_casts.py +0 -0
- {matrx_orm-3.1.140 → matrx_orm-3.1.141}/tests/test_sync_twins_guard.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: matrx-orm
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.141
|
|
4
4
|
Summary: Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching
|
|
5
5
|
Project-URL: Homepage, https://github.com/AI-Matrix-Engine/aidream-current
|
|
6
6
|
Project-URL: Repository, https://github.com/AI-Matrix-Engine/aidream-current
|
|
@@ -25,7 +25,7 @@ Requires-Python: >=3.13
|
|
|
25
25
|
Requires-Dist: asyncpg>=0.31.0
|
|
26
26
|
Requires-Dist: cryptography>=43.0
|
|
27
27
|
Requires-Dist: gitpython>=3.1.40
|
|
28
|
-
Requires-Dist: matrx-utils>=2.0.
|
|
28
|
+
Requires-Dist: matrx-utils>=2.0.38
|
|
29
29
|
Requires-Dist: psycopg-pool>=3.2.5
|
|
30
30
|
Requires-Dist: psycopg[binary]>=3.2.5
|
|
31
31
|
Requires-Dist: python-dotenv>=1.0
|
|
@@ -47,6 +47,16 @@ artifacts, not general document storage.
|
|
|
47
47
|
`editable=false` blocks human value changes (`FieldNotEditableError`); the owning
|
|
48
48
|
service rotates via `system_rotation=True` / `rotate_credential_fields`.
|
|
49
49
|
|
|
50
|
+
**Protected execution purpose.** `execution_purpose` is a closed, immutable
|
|
51
|
+
row purpose. `passkey_private` is reserved for native-provider use and is
|
|
52
|
+
never creatable through generic battery or HTTP constructors. Generic
|
|
53
|
+
single-field resolution refuses it before decrypt with the stable
|
|
54
|
+
`protected_execution_required` code; bulk env/token resolution omits it.
|
|
55
|
+
Item metadata and grants remain metadata-only, while generic child mutation,
|
|
56
|
+
fork, and transfer refuse a protected child. Every competing child/lifecycle
|
|
57
|
+
mutation locks and re-reads the parent in its transaction; whole-item delete
|
|
58
|
+
remains atomic.
|
|
59
|
+
|
|
50
60
|
**`inject_into_sandbox=true` REQUIRES an env alias — refused otherwise.** A
|
|
51
61
|
container environment is a NAME→value map, so a field with `key IS NULL` has
|
|
52
62
|
nowhere to land and bulk resolution drops it. Accepting the flag anyway meant a
|
|
@@ -76,6 +76,7 @@ from .items import (
|
|
|
76
76
|
CredentialItemNotFoundError,
|
|
77
77
|
CredentialItemRow,
|
|
78
78
|
FieldNotEditableError,
|
|
79
|
+
ProtectedSecretPurposeError,
|
|
79
80
|
FieldSpec,
|
|
80
81
|
ItemGrantSpec,
|
|
81
82
|
SandboxInjectionWithoutEnvKeyError,
|
|
@@ -210,6 +211,7 @@ __all__ = [
|
|
|
210
211
|
"CredentialItemNotFoundError",
|
|
211
212
|
"CredentialItemRow",
|
|
212
213
|
"FieldNotEditableError",
|
|
214
|
+
"ProtectedSecretPurposeError",
|
|
213
215
|
"FieldSpec",
|
|
214
216
|
"ItemGrantSpec",
|
|
215
217
|
"SandboxInjectionWithoutEnvKeyError",
|
|
@@ -67,6 +67,9 @@ def register_non_transferable_field_key(field_key: str) -> None:
|
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
HANDLING_MODES: tuple[str, ...] = ("visible", "revealable", "sealed")
|
|
70
|
+
GENERAL_EXECUTION_PURPOSE = "general"
|
|
71
|
+
PASSKEY_PRIVATE_EXECUTION_PURPOSE = "passkey_private"
|
|
72
|
+
PROTECTED_FIELD_KEY = "passkey_private"
|
|
70
73
|
ITEM_STATUSES: tuple[str, ...] = ("active", "disabled", "expired", "pending_verification")
|
|
71
74
|
URI_MATCH_MODES: tuple[str, ...] = ("host", "domain", "exact", "never")
|
|
72
75
|
ITEM_SOURCES: tuple[str, ...] = (
|
|
@@ -107,6 +110,24 @@ class SandboxInjectionWithoutEnvKeyError(ValueError):
|
|
|
107
110
|
together) or leave injection off."""
|
|
108
111
|
|
|
109
112
|
|
|
113
|
+
class ProtectedSecretPurposeError(PermissionError):
|
|
114
|
+
"""A generic path reached a native-provider-only secret before decrypt."""
|
|
115
|
+
|
|
116
|
+
code = "protected_execution_required"
|
|
117
|
+
|
|
118
|
+
def __init__(self, *, field_id: str | None, credential_item_id: str | None) -> None:
|
|
119
|
+
self.field_id = field_id
|
|
120
|
+
self.credential_item_id = credential_item_id
|
|
121
|
+
super().__init__(self.code)
|
|
122
|
+
|
|
123
|
+
def metadata(self) -> dict[str, str | None]:
|
|
124
|
+
return {
|
|
125
|
+
"code": self.code,
|
|
126
|
+
"field_id": self.field_id,
|
|
127
|
+
"credential_item_id": self.credential_item_id,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
110
131
|
# ── Shapes ────────────────────────────────────────────────────────────────
|
|
111
132
|
|
|
112
133
|
|
|
@@ -153,6 +174,7 @@ class CredentialFieldRow:
|
|
|
153
174
|
description: str | None
|
|
154
175
|
created_at: str
|
|
155
176
|
updated_at: str
|
|
177
|
+
execution_purpose: str
|
|
156
178
|
|
|
157
179
|
def to_dict(self) -> dict[str, Any]:
|
|
158
180
|
return dict(self.__dict__)
|
|
@@ -308,6 +330,7 @@ _FIELD_FIELDS = (
|
|
|
308
330
|
"id",
|
|
309
331
|
"credential_item_id",
|
|
310
332
|
"field_key",
|
|
333
|
+
"execution_purpose",
|
|
311
334
|
"key",
|
|
312
335
|
"handling",
|
|
313
336
|
"editable",
|
|
@@ -354,6 +377,7 @@ def _field_row(raw: dict[str, Any]) -> CredentialFieldRow:
|
|
|
354
377
|
id=str(raw["id"]),
|
|
355
378
|
credential_item_id=str(raw["credential_item_id"]),
|
|
356
379
|
field_key=str(raw["field_key"] or ""),
|
|
380
|
+
execution_purpose=_execution_purpose(raw),
|
|
357
381
|
env_key=raw.get("key"),
|
|
358
382
|
handling=str(raw.get("handling") or "revealable"),
|
|
359
383
|
editable=bool(raw.get("editable", True)),
|
|
@@ -388,6 +412,47 @@ async def _require_item_raw(item_id: str) -> dict[str, Any]:
|
|
|
388
412
|
return rows[0]
|
|
389
413
|
|
|
390
414
|
|
|
415
|
+
async def _lock_item_raw(item_id: str) -> dict[str, Any]:
|
|
416
|
+
"""Lock and re-read a live parent within the current transaction."""
|
|
417
|
+
rows = await (
|
|
418
|
+
CredentialItem.filter(id=item_id, deleted_at__isnull=True)
|
|
419
|
+
.select_for_update()
|
|
420
|
+
.values(*_ITEM_FIELDS)
|
|
421
|
+
)
|
|
422
|
+
if not rows:
|
|
423
|
+
raise CredentialItemNotFoundError(f"credential item {item_id} not found")
|
|
424
|
+
return rows[0]
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def _execution_purpose(raw: dict[str, Any]) -> str:
|
|
428
|
+
purpose = raw.get("execution_purpose")
|
|
429
|
+
if purpose not in (GENERAL_EXECUTION_PURPOSE, PASSKEY_PRIVATE_EXECUTION_PURPOSE):
|
|
430
|
+
# A missing projection is a security-contract failure, never evidence
|
|
431
|
+
# that the row is ordinary.
|
|
432
|
+
raise ProtectedSecretPurposeError(
|
|
433
|
+
field_id=str(raw["id"]) if raw.get("id") else None,
|
|
434
|
+
credential_item_id=(str(raw["credential_item_id"]) if raw.get("credential_item_id") else None),
|
|
435
|
+
)
|
|
436
|
+
return str(purpose)
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def _is_protected(raw: dict[str, Any]) -> bool:
|
|
440
|
+
return _execution_purpose(raw) == PASSKEY_PRIVATE_EXECUTION_PURPOSE
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def _refuse_protected(raw: dict[str, Any]) -> None:
|
|
444
|
+
if _is_protected(raw):
|
|
445
|
+
raise ProtectedSecretPurposeError(
|
|
446
|
+
field_id=str(raw["id"]) if raw.get("id") else None,
|
|
447
|
+
credential_item_id=(str(raw["credential_item_id"]) if raw.get("credential_item_id") else None),
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def _refuse_reserved_generic_field(field_key: str) -> None:
|
|
452
|
+
if field_key == PROTECTED_FIELD_KEY:
|
|
453
|
+
raise ValueError("field_key 'passkey_private' is reserved for native provider execution")
|
|
454
|
+
|
|
455
|
+
|
|
391
456
|
# ── Item CRUD ─────────────────────────────────────────────────────────────
|
|
392
457
|
|
|
393
458
|
|
|
@@ -516,6 +581,7 @@ async def create_credential_bundle(
|
|
|
516
581
|
seen: set[str] = set()
|
|
517
582
|
for spec in fields:
|
|
518
583
|
_validate_field_key(spec.field_key)
|
|
584
|
+
_refuse_reserved_generic_field(spec.field_key)
|
|
519
585
|
_validate_handling(spec.handling)
|
|
520
586
|
_validate_sandbox_injectable(
|
|
521
587
|
field_key=spec.field_key,
|
|
@@ -693,9 +759,9 @@ async def delete_credential_item(
|
|
|
693
759
|
) -> None:
|
|
694
760
|
"""Soft-delete the item, all its fields, and drop its grants — atomically.
|
|
695
761
|
Resolution stops immediately; ciphertext is recoverable until purge."""
|
|
696
|
-
raw = await _require_item_raw(item_id)
|
|
697
762
|
now = datetime.now(UTC)
|
|
698
763
|
async with transaction(PACKAGE_DB_NAME):
|
|
764
|
+
raw = await _lock_item_raw(item_id)
|
|
699
765
|
from .attachments import soft_delete_item_attachments
|
|
700
766
|
|
|
701
767
|
await UserSecretGrant.delete_where(credential_item_id=item_id)
|
|
@@ -743,6 +809,7 @@ async def add_credential_field(
|
|
|
743
809
|
first, then write.
|
|
744
810
|
"""
|
|
745
811
|
_validate_field_key(spec.field_key)
|
|
812
|
+
_refuse_reserved_generic_field(spec.field_key)
|
|
746
813
|
_validate_handling(spec.handling)
|
|
747
814
|
if spec.handling == "sealed":
|
|
748
815
|
await require_host_authorization(
|
|
@@ -758,30 +825,31 @@ async def add_credential_field(
|
|
|
758
825
|
)
|
|
759
826
|
if not isinstance(spec.value, str):
|
|
760
827
|
raise ValueError("value must be a string")
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
828
|
+
async with transaction(PACKAGE_DB_NAME):
|
|
829
|
+
raw = await _lock_item_raw(item_id)
|
|
830
|
+
instance = await UserSecret.create(
|
|
831
|
+
user_id=raw.get("user_id"),
|
|
832
|
+
organization_id=raw.get("organization_id"),
|
|
833
|
+
credential_item_id=item_id,
|
|
834
|
+
field_key=spec.field_key,
|
|
835
|
+
key=spec.env_key,
|
|
836
|
+
value_encrypted=encrypt_value(spec.value),
|
|
837
|
+
value_hint=mask_value(spec.value),
|
|
838
|
+
handling=spec.handling,
|
|
839
|
+
editable=spec.editable,
|
|
840
|
+
inject_into_sandbox=spec.inject_into_sandbox,
|
|
841
|
+
description=spec.description,
|
|
842
|
+
access_mode=str(raw.get("access_mode") or "all_members"),
|
|
843
|
+
created_by=actor_id,
|
|
844
|
+
updated_by=actor_id,
|
|
845
|
+
)
|
|
846
|
+
await record_secret_audit(
|
|
847
|
+
action="field_added",
|
|
848
|
+
actor_id=actor_id,
|
|
849
|
+
user_secret_id=str(instance.id),
|
|
850
|
+
organization_id=audit_organization_id,
|
|
851
|
+
metadata={"credential_item_id": item_id, "field_key": spec.field_key},
|
|
852
|
+
)
|
|
785
853
|
rows = await UserSecret.filter(id=instance.id).values(*_FIELD_FIELDS)
|
|
786
854
|
return _field_row(rows[0])
|
|
787
855
|
|
|
@@ -800,22 +868,31 @@ async def update_credential_field_value(
|
|
|
800
868
|
token refresh, key rotation)."""
|
|
801
869
|
if not isinstance(value, str):
|
|
802
870
|
raise ValueError("value must be a string")
|
|
803
|
-
rows = await UserSecret.filter(id=field_id, deleted_at__isnull=True).values(
|
|
871
|
+
rows = await UserSecret.filter(id=field_id, deleted_at__isnull=True).values("credential_item_id")
|
|
804
872
|
if not rows:
|
|
805
873
|
raise SecretNotFoundError(f"credential field {field_id} not found")
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
874
|
+
async with transaction(PACKAGE_DB_NAME):
|
|
875
|
+
if rows[0].get("credential_item_id"):
|
|
876
|
+
await _lock_item_raw(str(rows[0]["credential_item_id"]))
|
|
877
|
+
rows = await UserSecret.filter(id=field_id, deleted_at__isnull=True).select_for_update().values(
|
|
878
|
+
*_FIELD_FIELDS
|
|
879
|
+
)
|
|
880
|
+
if not rows:
|
|
881
|
+
raise SecretNotFoundError(f"credential field {field_id} not found")
|
|
882
|
+
raw = rows[0]
|
|
883
|
+
_refuse_protected(raw)
|
|
884
|
+
if not bool(raw.get("editable", True)) and not system_rotation:
|
|
885
|
+
raise FieldNotEditableError(
|
|
886
|
+
f"field {raw.get('field_key') or raw.get('key')!r} is not editable — "
|
|
887
|
+
"it is managed by its owning integration"
|
|
888
|
+
)
|
|
889
|
+
await UserSecret.update_where(
|
|
890
|
+
{"id": field_id, "deleted_at__isnull": True},
|
|
891
|
+
value_encrypted=encrypt_value(value),
|
|
892
|
+
value_hint=mask_value(value),
|
|
893
|
+
updated_by=actor_id,
|
|
894
|
+
updated_at=datetime.now(UTC),
|
|
811
895
|
)
|
|
812
|
-
await UserSecret.update_where(
|
|
813
|
-
{"id": field_id, "deleted_at__isnull": True},
|
|
814
|
-
value_encrypted=encrypt_value(value),
|
|
815
|
-
value_hint=mask_value(value),
|
|
816
|
-
updated_by=actor_id,
|
|
817
|
-
updated_at=datetime.now(UTC),
|
|
818
|
-
)
|
|
819
896
|
await record_secret_audit(
|
|
820
897
|
action="rotated" if system_rotation else "field_updated",
|
|
821
898
|
actor_id=actor_id,
|
|
@@ -852,10 +929,13 @@ async def rotate_credential_fields(
|
|
|
852
929
|
async with transaction(PACKAGE_DB_NAME):
|
|
853
930
|
# Item + field liveness re-checked INSIDE the transaction so a
|
|
854
931
|
# concurrent delete can't race a half-rotation in.
|
|
855
|
-
await
|
|
932
|
+
await _lock_item_raw(item_id)
|
|
856
933
|
rows = await UserSecret.filter(
|
|
857
934
|
credential_item_id=item_id, field_key__in=list(new_values), deleted_at__isnull=True
|
|
858
|
-
).values("id", "field_key")
|
|
935
|
+
).values("id", "field_key", "credential_item_id", "execution_purpose")
|
|
936
|
+
protected = [row for row in rows if _is_protected(row)]
|
|
937
|
+
if protected:
|
|
938
|
+
_refuse_protected(protected[0])
|
|
859
939
|
found = {str(r["field_key"]): str(r["id"]) for r in rows}
|
|
860
940
|
missing = sorted(set(new_values) - set(found))
|
|
861
941
|
if missing:
|
|
@@ -916,12 +996,18 @@ async def update_field_metadata(
|
|
|
916
996
|
raise ValueError(f"env_key must match {VALID_KEY_RE}; got {env_key!r}")
|
|
917
997
|
|
|
918
998
|
async with transaction(PACKAGE_DB_NAME):
|
|
919
|
-
rows = await UserSecret.filter(id=field_id, deleted_at__isnull=True).values(
|
|
999
|
+
rows = await UserSecret.filter(id=field_id, deleted_at__isnull=True).values("credential_item_id")
|
|
1000
|
+
if not rows:
|
|
1001
|
+
raise SecretNotFoundError(f"credential field {field_id} not found")
|
|
1002
|
+
if rows[0].get("credential_item_id"):
|
|
1003
|
+
await _lock_item_raw(str(rows[0]["credential_item_id"]))
|
|
1004
|
+
rows = await UserSecret.filter(id=field_id, deleted_at__isnull=True).select_for_update().values(
|
|
920
1005
|
*_FIELD_FIELDS, "user_id", "organization_id"
|
|
921
1006
|
)
|
|
922
1007
|
if not rows:
|
|
923
1008
|
raise SecretNotFoundError(f"credential field {field_id} not found")
|
|
924
1009
|
raw = rows[0]
|
|
1010
|
+
_refuse_protected(raw)
|
|
925
1011
|
|
|
926
1012
|
if handling is not None and str(raw.get("handling")) == "sealed" and handling != "sealed":
|
|
927
1013
|
raise SealedFieldError(
|
|
@@ -1000,13 +1086,26 @@ async def delete_credential_field(
|
|
|
1000
1086
|
actor_id: str | None = None,
|
|
1001
1087
|
) -> bool:
|
|
1002
1088
|
"""Soft-delete one field. Returns True when a row was affected."""
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1089
|
+
rows = await UserSecret.filter(id=field_id, deleted_at__isnull=True).values("credential_item_id")
|
|
1090
|
+
if not rows:
|
|
1091
|
+
return False
|
|
1092
|
+
async with transaction(PACKAGE_DB_NAME):
|
|
1093
|
+
if rows[0].get("credential_item_id"):
|
|
1094
|
+
await _lock_item_raw(str(rows[0]["credential_item_id"]))
|
|
1095
|
+
rows = await UserSecret.filter(id=field_id, deleted_at__isnull=True).select_for_update().values(
|
|
1096
|
+
"id", "credential_item_id", "execution_purpose"
|
|
1097
|
+
)
|
|
1098
|
+
if not rows:
|
|
1099
|
+
return False
|
|
1100
|
+
raw = rows[0]
|
|
1101
|
+
_refuse_protected(raw)
|
|
1102
|
+
result = await UserSecret.update_where(
|
|
1103
|
+
{"id": field_id, "deleted_at__isnull": True},
|
|
1104
|
+
deleted_at=datetime.now(UTC),
|
|
1105
|
+
is_active=False,
|
|
1106
|
+
updated_by=actor_id,
|
|
1107
|
+
updated_at=datetime.now(UTC),
|
|
1108
|
+
)
|
|
1010
1109
|
if result.rows_affected:
|
|
1011
1110
|
await record_secret_audit(
|
|
1012
1111
|
action="field_deleted",
|
|
@@ -1025,10 +1124,11 @@ async def resolve_field_by_id(field_id: str) -> str:
|
|
|
1025
1124
|
``sealed`` fields; never expose through a human-facing surface. The host
|
|
1026
1125
|
must have authorized the consumer before calling."""
|
|
1027
1126
|
rows = await UserSecret.filter(id=field_id, deleted_at__isnull=True, is_active=True).values(
|
|
1028
|
-
"id", "field_key", "key", "value_encrypted"
|
|
1127
|
+
"id", "credential_item_id", "field_key", "key", "execution_purpose", "value_encrypted"
|
|
1029
1128
|
)
|
|
1030
1129
|
if not rows:
|
|
1031
1130
|
raise SecretNotFoundError(f"credential field {field_id} not found")
|
|
1131
|
+
_refuse_protected(rows[0])
|
|
1032
1132
|
try:
|
|
1033
1133
|
value = decrypt_value(rows[0]["value_encrypted"])
|
|
1034
1134
|
except Exception as exc:
|
|
@@ -1048,9 +1148,10 @@ async def resolve_field(item_id: str, field_key: str) -> str:
|
|
|
1048
1148
|
field_key=field_key,
|
|
1049
1149
|
deleted_at__isnull=True,
|
|
1050
1150
|
is_active=True,
|
|
1051
|
-
).values("id")
|
|
1151
|
+
).values("id", "credential_item_id", "execution_purpose")
|
|
1052
1152
|
if not rows:
|
|
1053
1153
|
raise SecretNotFoundError(f"item {item_id} has no active field {field_key!r}")
|
|
1154
|
+
_refuse_protected(rows[0])
|
|
1054
1155
|
return await resolve_field_by_id(str(rows[0]["id"]))
|
|
1055
1156
|
|
|
1056
1157
|
|
|
@@ -1062,6 +1163,7 @@ async def resolve_item_fields(item_id: str, *, sandbox_only: bool = False) -> di
|
|
|
1062
1163
|
"credential_item_id": item_id,
|
|
1063
1164
|
"deleted_at__isnull": True,
|
|
1064
1165
|
"is_active": True,
|
|
1166
|
+
"execution_purpose": GENERAL_EXECUTION_PURPOSE,
|
|
1065
1167
|
}
|
|
1066
1168
|
if sandbox_only:
|
|
1067
1169
|
filters["inject_into_sandbox"] = True
|
|
@@ -1103,14 +1205,19 @@ async def reveal_field(
|
|
|
1103
1205
|
field_key=field_key,
|
|
1104
1206
|
deleted_at__isnull=True,
|
|
1105
1207
|
is_active=True,
|
|
1106
|
-
).values(
|
|
1208
|
+
).values(
|
|
1209
|
+
"id", "field_key", "key", "handling", "execution_purpose", "value_encrypted",
|
|
1210
|
+
"credential_item_id",
|
|
1211
|
+
)
|
|
1107
1212
|
else:
|
|
1108
1213
|
rows = await UserSecret.filter(id=field_id, deleted_at__isnull=True, is_active=True).values(
|
|
1109
|
-
"id", "field_key", "key", "handling", "
|
|
1214
|
+
"id", "field_key", "key", "handling", "execution_purpose", "value_encrypted",
|
|
1215
|
+
"credential_item_id",
|
|
1110
1216
|
)
|
|
1111
1217
|
if not rows:
|
|
1112
1218
|
raise SecretNotFoundError("credential field not found")
|
|
1113
1219
|
raw = rows[0]
|
|
1220
|
+
_refuse_protected(raw)
|
|
1114
1221
|
handling = str(raw.get("handling") or "revealable")
|
|
1115
1222
|
if handling == "sealed":
|
|
1116
1223
|
await record_secret_audit(
|
|
@@ -1463,11 +1570,18 @@ async def transfer_credential_item(
|
|
|
1463
1570
|
do NOT travel: they are retired in the same transaction and named in the
|
|
1464
1571
|
returned :class:`TransferResult`."""
|
|
1465
1572
|
_validate_owner(to_user_id, to_organization_id)
|
|
1466
|
-
raw = await _require_item_raw(item_id)
|
|
1467
|
-
from_user_id = str(raw["user_id"]) if raw.get("user_id") else None
|
|
1468
|
-
from_organization_id = str(raw["organization_id"]) if raw.get("organization_id") else None
|
|
1469
1573
|
now = datetime.now(UTC)
|
|
1470
1574
|
async with transaction(PACKAGE_DB_NAME):
|
|
1575
|
+
raw = await _lock_item_raw(item_id)
|
|
1576
|
+
protected = await UserSecret.filter(
|
|
1577
|
+
credential_item_id=item_id,
|
|
1578
|
+
deleted_at__isnull=True,
|
|
1579
|
+
execution_purpose=PASSKEY_PRIVATE_EXECUTION_PURPOSE,
|
|
1580
|
+
).values("id", "credential_item_id", "execution_purpose")
|
|
1581
|
+
if protected:
|
|
1582
|
+
_refuse_protected(protected[0])
|
|
1583
|
+
from_user_id = str(raw["user_id"]) if raw.get("user_id") else None
|
|
1584
|
+
from_organization_id = str(raw["organization_id"]) if raw.get("organization_id") else None
|
|
1471
1585
|
retired = await _retire_non_transferable_fields(
|
|
1472
1586
|
item_id, actor_id=actor_id, now=now, event="transfer"
|
|
1473
1587
|
)
|
|
@@ -1534,29 +1648,22 @@ async def fork_credential_item(
|
|
|
1534
1648
|
hands the copy to a principal who never established them (D-15). The new
|
|
1535
1649
|
item's ``lifecycle.fields_not_copied`` names what was left behind."""
|
|
1536
1650
|
_validate_owner(to_user_id, to_organization_id)
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1651
|
+
async with transaction(PACKAGE_DB_NAME):
|
|
1652
|
+
raw = await _lock_item_raw(item_id)
|
|
1653
|
+
all_field_rows = await UserSecret.filter(
|
|
1654
|
+
credential_item_id=item_id, deleted_at__isnull=True
|
|
1655
|
+
).values(*_FIELD_FIELDS, "value_encrypted")
|
|
1656
|
+
protected = [row for row in all_field_rows if _is_protected(row)]
|
|
1657
|
+
if protected:
|
|
1658
|
+
_refuse_protected(protected[0])
|
|
1659
|
+
field_rows = [
|
|
1660
|
+
fr for fr in all_field_rows if str(fr.get("field_key")) not in NON_TRANSFERABLE_FIELD_KEYS
|
|
1661
|
+
]
|
|
1662
|
+
not_copied = sorted(
|
|
1546
1663
|
str(fr.get("field_key"))
|
|
1547
1664
|
for fr in all_field_rows
|
|
1548
1665
|
if str(fr.get("field_key")) in NON_TRANSFERABLE_FIELD_KEYS
|
|
1549
|
-
}
|
|
1550
|
-
)
|
|
1551
|
-
if not_copied:
|
|
1552
|
-
logger.warning(
|
|
1553
|
-
"credential item %s: fork does NOT copy minting field(s) %s — the fork's "
|
|
1554
|
-
"owner must establish them again (D-15)",
|
|
1555
|
-
item_id,
|
|
1556
|
-
not_copied,
|
|
1557
1666
|
)
|
|
1558
|
-
|
|
1559
|
-
async with transaction(PACKAGE_DB_NAME):
|
|
1560
1667
|
new_item = await CredentialItem.create(
|
|
1561
1668
|
user_id=to_user_id,
|
|
1562
1669
|
organization_id=to_organization_id,
|
|
@@ -80,6 +80,7 @@ class UserSecret(Model):
|
|
|
80
80
|
source_user_secret_version = IntegerField()
|
|
81
81
|
credential_item_id = UUIDField()
|
|
82
82
|
field_key = TextField()
|
|
83
|
+
execution_purpose = TextField(null=False, default="general")
|
|
83
84
|
handling = TextField(null=False, default="revealable")
|
|
84
85
|
editable = BooleanField(null=False, default=True)
|
|
85
86
|
key = TextField()
|