mainsequence 6.0.28__tar.gz → 6.0.30__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.
- {mainsequence-6.0.28/mainsequence.egg-info → mainsequence-6.0.30}/PKG-INFO +1 -4
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/AGENTS.md +4 -3
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +28 -14
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/models_user.py +3 -2
- {mainsequence-6.0.28 → mainsequence-6.0.30/mainsequence.egg-info}/PKG-INFO +1 -4
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence.egg-info/SOURCES.txt +0 -3
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence.egg-info/requires.txt +0 -4
- {mainsequence-6.0.28 → mainsequence-6.0.30}/pyproject.toml +1 -5
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_models_user_request_bound_auth.py +1 -1
- mainsequence-6.0.28/mainsequence/client/fastapi/__init__.py +0 -3
- mainsequence-6.0.28/mainsequence/client/fastapi/auth.py +0 -66
- mainsequence-6.0.28/tests/test_fastapi_request_identity.py +0 -108
- {mainsequence-6.0.28 → mainsequence-6.0.30}/LICENSE +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/README.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/a2a_sdk_execution/SKILL.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/data_publishing/meta_table_migrations/SKILL.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/maintenance/project-maintenance/SKILL.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/sdk_project_execution/SKILL.md +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/__main__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/bootstrap.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/api.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/cli.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/config.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/migrations.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/cli/ui.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/base.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/client.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/compute_validation.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/dtype_codec.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/metatables/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/metatables/core.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/models_foundry.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/utils.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/defaults.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/logconf.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/__main__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/build_operations.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/data_nodes.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/models.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/namespacing.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/persist_managers.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/run_operations.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/future_registry.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/hashing.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/migrations/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/migrations/alembic.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/migrations/env.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/migrations/provider.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/migrations/registry.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/migrations/scaffold.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/migrations/templates/__init__.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/migrations/templates/env.py.mako +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/migrations/templates/script.py.mako +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/schema_names.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/sqlalchemy_contracts.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/project_skills.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/runtime_context.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/scaffold_skills.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/setup.cfg +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_auth_precedence.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_build_operations_hashing.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_canonical_api_route_contract.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_cli.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_cli_migrations.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_client.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_data_access_mixin_dimension_audit.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_data_node_storage_dimension_queries.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_data_node_update_flow.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_dependency_extras.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_duckdb_interface_dimensions.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_filter_normalization.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_instrumentation.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_logconf.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_meta_table_migrations.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_meta_tables_client_models.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_meta_tables_sqlalchemy_contracts.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_notification_uid_contract.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_pod_project_resolution.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_project_batch_jobs_from_file.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_project_branch_contract.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_project_skills.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_run_configuration.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_scaffold_skills.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_schema_names.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_secret_client_model.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_source_table_configuration.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_sqlite_interface_dimensions.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_update_statistics.py +0 -0
- {mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_update_uid_guards.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mainsequence
|
|
3
|
-
Version: 6.0.
|
|
3
|
+
Version: 6.0.30
|
|
4
4
|
Summary: Main Sequence SDK
|
|
5
5
|
Author-email: Main Sequence GmbH <dev@main-sequence.io>
|
|
6
6
|
License-Expression: LicenseRef-MainSequence-Proprietary
|
|
@@ -31,13 +31,10 @@ Requires-Dist: pygments>=2.20.0
|
|
|
31
31
|
Requires-Dist: pyyaml
|
|
32
32
|
Requires-Dist: requests>=2.33.0
|
|
33
33
|
Requires-Dist: sqlalchemy<3,>=2
|
|
34
|
-
Requires-Dist: starlette
|
|
35
34
|
Requires-Dist: structlog
|
|
36
35
|
Requires-Dist: tqdm
|
|
37
36
|
Requires-Dist: typer
|
|
38
37
|
Requires-Dist: urllib3>=2.7.0
|
|
39
|
-
Provides-Extra: fastapi
|
|
40
|
-
Requires-Dist: fastapi<1,>=0.115; extra == "fastapi"
|
|
41
38
|
Provides-Extra: local-data
|
|
42
39
|
Requires-Dist: duckdb>=1.4.2; extra == "local-data"
|
|
43
40
|
Requires-Dist: pyarrow>=23.0.1; extra == "local-data"
|
|
@@ -107,13 +107,14 @@ Working rules for this role:
|
|
|
107
107
|
User-resolution rule for agents:
|
|
108
108
|
|
|
109
109
|
- use `User.get_logged_user()` only when code is running with request-bound identity context:
|
|
110
|
-
- FastAPI with `LoggedUserContextMiddleware` installed by the application
|
|
111
110
|
- Streamlit
|
|
112
111
|
- code that explicitly binds `_CURRENT_AUTH_HEADERS`
|
|
113
112
|
- treat its result as `RequestUserIdentity`: the human caller's canonical `uid` and optional
|
|
114
113
|
`username`, never a numeric id or a full account profile
|
|
115
|
-
- in FastAPI handlers,
|
|
116
|
-
`request.state.
|
|
114
|
+
- in FastAPI handlers, use the Main Sequence platform-injected
|
|
115
|
+
`request.state.user` or `request.state.user_uid`; do not use
|
|
116
|
+
`User.get_logged_user()` as the handler entry point
|
|
117
|
+
- never use `request.state.user_id`
|
|
117
118
|
- use `User.get_authenticated_user_details()` in standalone authenticated CLI or script code that
|
|
118
119
|
is not request-bound
|
|
119
120
|
- keep authentication context separate from route-level authorization, deployment ownership,
|
|
@@ -92,25 +92,39 @@ Record:
|
|
|
92
92
|
- whether the API uses backend transport or a contract-defined direct
|
|
93
93
|
development transport
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
application must install it explicitly with
|
|
99
|
-
`app.add_middleware(LoggedUserContextMiddleware)`.
|
|
95
|
+
FastAPI releases receive the authenticated human from the Main Sequence
|
|
96
|
+
platform through injected request state. No SDK authentication setup is
|
|
97
|
+
required in project code:
|
|
100
98
|
|
|
101
|
-
|
|
99
|
+
```python
|
|
100
|
+
from fastapi import FastAPI, Request
|
|
102
101
|
|
|
103
|
-
|
|
102
|
+
|
|
103
|
+
app = FastAPI()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@app.get("/me")
|
|
107
|
+
def get_me(request: Request) -> dict[str, str | None]:
|
|
108
|
+
return {
|
|
109
|
+
"uid": request.state.user_uid,
|
|
110
|
+
"username": request.state.user.username,
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Route code must not detect local versus deployed execution, parse
|
|
115
|
+
authentication headers, or resolve the request user itself. Consume only the
|
|
116
|
+
platform-injected human caller identity:
|
|
117
|
+
|
|
118
|
+
- `request.state.user` contains canonical `uid` and optional `username`
|
|
104
119
|
- `request.state.user_uid` is the canonical public user UUID
|
|
105
120
|
- `request.state.user_id` does not exist
|
|
106
121
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
been resolved.
|
|
122
|
+
This identity is the human making the current HTTP request. It is not the
|
|
123
|
+
release creator, deployment owner, runtime workload principal, or runtime
|
|
124
|
+
target. Pass request state explicitly to shared services; do not use
|
|
125
|
+
`User.get_logged_user()` as a FastAPI entry point. Platform-injected identity is
|
|
126
|
+
not resource authorization; use `request.state.user_uid` when applying the
|
|
127
|
+
endpoint's authorization policy.
|
|
114
128
|
|
|
115
129
|
### 2. Implement the provider
|
|
116
130
|
|
|
@@ -1201,8 +1201,9 @@ class User(UserApiBaseObjectOrm, BasePydanticModel):
|
|
|
1201
1201
|
|
|
1202
1202
|
if not headers:
|
|
1203
1203
|
raise RequestIdentityError(
|
|
1204
|
-
"No request identity is available.
|
|
1205
|
-
"
|
|
1204
|
+
"No request identity is available. Provide an explicitly bound "
|
|
1205
|
+
"request-header context or Streamlit request headers. FastAPI "
|
|
1206
|
+
"handlers should use request.state.user instead."
|
|
1206
1207
|
)
|
|
1207
1208
|
|
|
1208
1209
|
normalized_headers = _normalize_request_headers(headers)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mainsequence
|
|
3
|
-
Version: 6.0.
|
|
3
|
+
Version: 6.0.30
|
|
4
4
|
Summary: Main Sequence SDK
|
|
5
5
|
Author-email: Main Sequence GmbH <dev@main-sequence.io>
|
|
6
6
|
License-Expression: LicenseRef-MainSequence-Proprietary
|
|
@@ -31,13 +31,10 @@ Requires-Dist: pygments>=2.20.0
|
|
|
31
31
|
Requires-Dist: pyyaml
|
|
32
32
|
Requires-Dist: requests>=2.33.0
|
|
33
33
|
Requires-Dist: sqlalchemy<3,>=2
|
|
34
|
-
Requires-Dist: starlette
|
|
35
34
|
Requires-Dist: structlog
|
|
36
35
|
Requires-Dist: tqdm
|
|
37
36
|
Requires-Dist: typer
|
|
38
37
|
Requires-Dist: urllib3>=2.7.0
|
|
39
|
-
Provides-Extra: fastapi
|
|
40
|
-
Requires-Dist: fastapi<1,>=0.115; extra == "fastapi"
|
|
41
38
|
Provides-Extra: local-data
|
|
42
39
|
Requires-Dist: duckdb>=1.4.2; extra == "local-data"
|
|
43
40
|
Requires-Dist: pyarrow>=23.0.1; extra == "local-data"
|
|
@@ -58,8 +58,6 @@ mainsequence/client/data_sources_interfaces/__init__.py
|
|
|
58
58
|
mainsequence/client/data_sources_interfaces/duckdb.py
|
|
59
59
|
mainsequence/client/data_sources_interfaces/local_paths.py
|
|
60
60
|
mainsequence/client/data_sources_interfaces/sqlite.py
|
|
61
|
-
mainsequence/client/fastapi/__init__.py
|
|
62
|
-
mainsequence/client/fastapi/auth.py
|
|
63
61
|
mainsequence/client/metatables/__init__.py
|
|
64
62
|
mainsequence/client/metatables/core.py
|
|
65
63
|
mainsequence/instrumentation/__init__.py
|
|
@@ -102,7 +100,6 @@ tests/test_data_node_storage_dimension_queries.py
|
|
|
102
100
|
tests/test_data_node_update_flow.py
|
|
103
101
|
tests/test_dependency_extras.py
|
|
104
102
|
tests/test_duckdb_interface_dimensions.py
|
|
105
|
-
tests/test_fastapi_request_identity.py
|
|
106
103
|
tests/test_filter_normalization.py
|
|
107
104
|
tests/test_instrumentation.py
|
|
108
105
|
tests/test_logconf.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mainsequence"
|
|
7
|
-
version = "6.0.
|
|
7
|
+
version = "6.0.30"
|
|
8
8
|
description = "Main Sequence SDK "
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.13"
|
|
@@ -40,7 +40,6 @@ dependencies = [
|
|
|
40
40
|
"pyyaml",
|
|
41
41
|
"requests>=2.33.0",
|
|
42
42
|
"sqlalchemy>=2,<3",
|
|
43
|
-
"starlette",
|
|
44
43
|
"structlog",
|
|
45
44
|
"tqdm",
|
|
46
45
|
"typer",
|
|
@@ -48,9 +47,6 @@ dependencies = [
|
|
|
48
47
|
]
|
|
49
48
|
|
|
50
49
|
[project.optional-dependencies]
|
|
51
|
-
"fastapi" = [
|
|
52
|
-
"fastapi>=0.115,<1",
|
|
53
|
-
]
|
|
54
50
|
"local-data" = [
|
|
55
51
|
"duckdb>=1.4.2",
|
|
56
52
|
"pyarrow>=23.0.1",
|
|
@@ -170,7 +170,7 @@ def test_get_logged_user_rejects_mismatched_bearer_and_gateway_uid(monkeypatch):
|
|
|
170
170
|
)
|
|
171
171
|
|
|
172
172
|
|
|
173
|
-
def
|
|
173
|
+
def test_get_logged_user_uses_explicitly_bound_identity_context():
|
|
174
174
|
expected = models_user_mod.RequestUserIdentity(uid=USER_UID, username="jose")
|
|
175
175
|
token = models_user_mod._CURRENT_USER.set(expected)
|
|
176
176
|
try:
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from starlette.concurrency import run_in_threadpool
|
|
4
|
-
from starlette.requests import Request
|
|
5
|
-
from starlette.responses import JSONResponse
|
|
6
|
-
from starlette.types import ASGIApp, Receive, Scope, Send
|
|
7
|
-
|
|
8
|
-
from mainsequence.client.exceptions import AuthenticationError, PermissionDeniedError
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def _load_auth_bindings():
|
|
12
|
-
from mainsequence.client.models_user import (
|
|
13
|
-
_CURRENT_AUTH_HEADERS,
|
|
14
|
-
_CURRENT_USER,
|
|
15
|
-
RequestIdentityError,
|
|
16
|
-
User,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
return User, RequestIdentityError, _CURRENT_AUTH_HEADERS, _CURRENT_USER
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class LoggedUserContextMiddleware:
|
|
23
|
-
"""Resolve and bind the human making each authenticated FastAPI request."""
|
|
24
|
-
|
|
25
|
-
def __init__(self, app: ASGIApp) -> None:
|
|
26
|
-
self.app = app
|
|
27
|
-
|
|
28
|
-
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
|
29
|
-
if scope["type"] != "http":
|
|
30
|
-
await self.app(scope, receive, send)
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
request = Request(scope)
|
|
34
|
-
if request.method == "OPTIONS":
|
|
35
|
-
await self.app(scope, receive, send)
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
User, RequestIdentityError, current_auth_headers, current_user = (
|
|
39
|
-
_load_auth_bindings()
|
|
40
|
-
)
|
|
41
|
-
headers_token = current_auth_headers.set(request.headers)
|
|
42
|
-
user_token = current_user.set(None)
|
|
43
|
-
resolved_user_token = None
|
|
44
|
-
try:
|
|
45
|
-
try:
|
|
46
|
-
user = await run_in_threadpool(User.get_logged_user)
|
|
47
|
-
except (RequestIdentityError, AuthenticationError, PermissionDeniedError):
|
|
48
|
-
response = JSONResponse(
|
|
49
|
-
{"detail": "Authenticated request user could not be resolved."},
|
|
50
|
-
status_code=401,
|
|
51
|
-
)
|
|
52
|
-
await response(scope, receive, send)
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
resolved_user_token = current_user.set(user)
|
|
56
|
-
request.state.user = user
|
|
57
|
-
request.state.user_uid = user.uid
|
|
58
|
-
await self.app(scope, receive, send)
|
|
59
|
-
finally:
|
|
60
|
-
if resolved_user_token is not None:
|
|
61
|
-
current_user.reset(resolved_user_token)
|
|
62
|
-
current_user.reset(user_token)
|
|
63
|
-
current_auth_headers.reset(headers_token)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
__all__ = ["LoggedUserContextMiddleware"]
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import asyncio
|
|
4
|
-
import json
|
|
5
|
-
|
|
6
|
-
from starlette.applications import Starlette
|
|
7
|
-
from starlette.requests import Request
|
|
8
|
-
from starlette.responses import JSONResponse, Response
|
|
9
|
-
from starlette.routing import Route
|
|
10
|
-
|
|
11
|
-
from mainsequence.client.fastapi import LoggedUserContextMiddleware
|
|
12
|
-
from mainsequence.client.models_user import _CURRENT_AUTH_HEADERS, _CURRENT_USER
|
|
13
|
-
|
|
14
|
-
USER_UID = "8f5d6b54-2f5e-4a8b-bb10-0b17f3f4c123"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def _request(app: Starlette, *, method: str = "GET", headers=None):
|
|
18
|
-
messages: list[dict] = []
|
|
19
|
-
scope = {
|
|
20
|
-
"type": "http",
|
|
21
|
-
"asgi": {"version": "3.0"},
|
|
22
|
-
"http_version": "1.1",
|
|
23
|
-
"method": method,
|
|
24
|
-
"scheme": "http",
|
|
25
|
-
"path": "/identity",
|
|
26
|
-
"raw_path": b"/identity",
|
|
27
|
-
"query_string": b"",
|
|
28
|
-
"headers": [
|
|
29
|
-
(str(key).lower().encode(), str(value).encode())
|
|
30
|
-
for key, value in (headers or {}).items()
|
|
31
|
-
],
|
|
32
|
-
"client": ("testclient", 50000),
|
|
33
|
-
"server": ("testserver", 80),
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async def receive():
|
|
37
|
-
return {"type": "http.request", "body": b"", "more_body": False}
|
|
38
|
-
|
|
39
|
-
async def send(message):
|
|
40
|
-
messages.append(message)
|
|
41
|
-
|
|
42
|
-
asyncio.run(app(scope, receive, send))
|
|
43
|
-
status = next(message["status"] for message in messages if message["type"] == "http.response.start")
|
|
44
|
-
body = b"".join(
|
|
45
|
-
message.get("body", b"")
|
|
46
|
-
for message in messages
|
|
47
|
-
if message["type"] == "http.response.body"
|
|
48
|
-
)
|
|
49
|
-
return status, json.loads(body) if body else None
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def _build_app(route_calls: list[str]) -> Starlette:
|
|
53
|
-
async def identity(request: Request) -> JSONResponse:
|
|
54
|
-
route_calls.append("identity")
|
|
55
|
-
return JSONResponse(
|
|
56
|
-
{
|
|
57
|
-
"uid": request.state.user.uid,
|
|
58
|
-
"state_uid": request.state.user_uid,
|
|
59
|
-
"has_numeric_id": hasattr(request.state, "user_id"),
|
|
60
|
-
}
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
async def preflight(request: Request) -> Response:
|
|
64
|
-
route_calls.append("preflight")
|
|
65
|
-
return Response(status_code=204)
|
|
66
|
-
|
|
67
|
-
app = Starlette(
|
|
68
|
-
routes=[
|
|
69
|
-
Route("/identity", identity),
|
|
70
|
-
Route("/identity", preflight, methods=["OPTIONS"]),
|
|
71
|
-
]
|
|
72
|
-
)
|
|
73
|
-
app.add_middleware(LoggedUserContextMiddleware)
|
|
74
|
-
return app
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def test_middleware_exposes_uid_only_request_state_and_resets_context():
|
|
78
|
-
route_calls: list[str] = []
|
|
79
|
-
status, body = _request(
|
|
80
|
-
_build_app(route_calls),
|
|
81
|
-
headers={"X-User-UID": USER_UID, "X-Username": "jose"},
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
assert status == 200
|
|
85
|
-
assert body == {
|
|
86
|
-
"uid": USER_UID,
|
|
87
|
-
"state_uid": USER_UID,
|
|
88
|
-
"has_numeric_id": False,
|
|
89
|
-
}
|
|
90
|
-
assert route_calls == ["identity"]
|
|
91
|
-
assert _CURRENT_AUTH_HEADERS.get() is None
|
|
92
|
-
assert _CURRENT_USER.get() is None
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def test_middleware_returns_401_without_running_route():
|
|
96
|
-
route_calls: list[str] = []
|
|
97
|
-
status, _ = _request(_build_app(route_calls))
|
|
98
|
-
|
|
99
|
-
assert status == 401
|
|
100
|
-
assert route_calls == []
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def test_middleware_allows_unauthenticated_options_preflight():
|
|
104
|
-
route_calls: list[str] = []
|
|
105
|
-
status, _ = _request(_build_app(route_calls), method="OPTIONS")
|
|
106
|
-
|
|
107
|
-
assert status == 204
|
|
108
|
-
assert route_calls == ["preflight"]
|
|
File without changes
|
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/a2a_sdk_execution/SKILL.md
RENAMED
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/data_access/exploration/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/agent_scaffold/skills/sdk_project_execution/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/data_sources_interfaces/__init__.py
RENAMED
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/data_sources_interfaces/duckdb.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/client/data_sources_interfaces/sqlite.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/compiled_sql/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/build_operations.py
RENAMED
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/data_nodes.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/namespacing.py
RENAMED
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/persist_managers.py
RENAMED
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/data_nodes/run_operations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/mainsequence/meta_tables/sqlalchemy_contracts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-6.0.28 → mainsequence-6.0.30}/tests/test_data_node_storage_dimension_queries.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|