mainsequence 9.0.15.dev58__tar.gz → 9.0.17__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-9.0.15.dev58 → mainsequence-9.0.17}/PKG-INFO +1 -1
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +24 -4
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +41 -12
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/_request_identity.py +2 -2
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/models_user.py +12 -3
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/server/fastapi.py +3 -2
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence.egg-info/PKG-INFO +1 -1
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/pyproject.toml +1 -1
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_fastapi_mcp.py +41 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/LICENSE +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/README.md +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/skills/a2a_sdk_execution/SKILL.md +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/skills/mainsequence-inference/SKILL.md +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/skills/maintenance/code_repository_maintenance/SKILL.md +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/skills/maintenance/metatables_transition/SKILL.md +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/skills/sdk_code_repository_execution/SKILL.md +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/__init__.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/__main__.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/bootstrap.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/api.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/cli.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/code_repository_status.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/config.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/ui.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/__init__.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/_transport.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/base.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/client.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/compute_validation.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/github_issues.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/inference.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/models_foundry.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/observability.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/utils.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/value_sets.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/code_repository_context.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/code_repository_skills.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/defaults.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/logconf.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/repository_identity_security.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/runtime_credential_exchange.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/scaffold_skills.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/server/__init__.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/server/caller_assertions.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence.egg-info/SOURCES.txt +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/setup.cfg +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_auth_bootstrap.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_auth_precedence.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_caller_assertions.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_canonical_api_route_contract.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_cli_auth_contract.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_cli_secure_storage.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_client.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_code_repository_branch_contract.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_code_repository_documentation_contract.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_code_repository_runtime_context.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_code_repository_skills.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_credential_repr.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_dependency_extras.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_dev_release_version.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_environment_resource_context.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_environment_response_contracts.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_fastapi_request_identity.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_github_issues_client.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_http_retry_budget.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_independent_context.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_inference_client.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_instrumentation.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_job_client.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_local_ops.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_logconf.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_notification_uid_contract.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_observability_client.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_runtime_credential_exchange.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_scaffold_skills.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_secret_client_model.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_source_ownership.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_ssh_utils.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_tolerant_response_reading.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_tolerant_value_sets.py +0 -0
- {mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_user_application_facts.py +0 -0
|
@@ -191,6 +191,10 @@ def team_report(team_uid: str) -> dict[str, str]:
|
|
|
191
191
|
|
|
192
192
|
- Authorize a requester-bound call against the requester. The acting
|
|
193
193
|
application has no rights of its own unless the API's policy grants them.
|
|
194
|
+
- The requester can authorize reads and writes within that person's own
|
|
195
|
+
member-level permissions. Before a write, check the exact object and action;
|
|
196
|
+
the example's team-membership check is not a general edit, run, share or
|
|
197
|
+
delete grant. The getter verifies identity, not operation permission.
|
|
194
198
|
- Fail closed: an operation that needs a person refuses the call when
|
|
195
199
|
`User.get_requester()` is `None`. Never fall back to the caller's rights.
|
|
196
200
|
- Never read a person's UID from the request body, a header or a query
|
|
@@ -201,9 +205,20 @@ def team_report(team_uid: str) -> dict[str, str]:
|
|
|
201
205
|
`is_organization_admin` is always `False`: a requester's access reaches the
|
|
202
206
|
API at member level only.
|
|
203
207
|
- Inside a requester-bound call, `reads_as_caller()` raises
|
|
204
|
-
`RequestIdentityError`:
|
|
205
|
-
-
|
|
206
|
-
and the
|
|
208
|
+
`RequestIdentityError`: a receiving application cannot forward its inbound
|
|
209
|
+
requester-bearing assertion to the directory endpoints. Platform-authorized
|
|
210
|
+
Agent delegation is separate and keeps the original person and request time.
|
|
211
|
+
- Hosted Agents never receive Secret values. The platform bounds work to at
|
|
212
|
+
most 24 hours after the original request and checks access on every call;
|
|
213
|
+
delegation does not restart that limit. This SDK does not enable platform
|
|
214
|
+
write endpoints or extend the inbound request scope.
|
|
215
|
+
- A model-driven Agent can be steered by prompt injection. Its writes can
|
|
216
|
+
cause damage within the person's permissions; keep object/action checks and
|
|
217
|
+
any mutation approval required by the application's policy outside model
|
|
218
|
+
claims or tool arguments.
|
|
219
|
+
- Test requester-authorized reads and writes, writes refused for a requester
|
|
220
|
+
without the necessary grant, and requester-required operations refused
|
|
221
|
+
without a requester even when the calling Agent has its own grants.
|
|
207
222
|
|
|
208
223
|
Which applications may act for their requester, what that access covers, and
|
|
209
224
|
what people are told:
|
|
@@ -218,7 +233,12 @@ To serve MCP tools from the same application, add the `mcp` extra and call
|
|
|
218
233
|
after `install_request_identity(app)`, with a stateless FastMCP server that
|
|
219
234
|
returns JSON. Tools authorize with `User.get_logged_user()` and
|
|
220
235
|
`User.get_requester()` exactly like REST handlers; admission to the release
|
|
221
|
-
does not authorize every tool.
|
|
236
|
+
does not authorize every tool. For a tool invoked by an Agent on a person's
|
|
237
|
+
behalf, check that requester for both reads and writes. Refuse a
|
|
238
|
+
requester-required write when the getter returns `None`, and verify object- and
|
|
239
|
+
action-specific permission before mutation; read access and MCP annotations are not
|
|
240
|
+
write authority. Ordinary non-requester calls retain their own caller policy.
|
|
241
|
+
See
|
|
222
242
|
[Serving MCP](https://mainsequence-sdk.github.io/mainsequence-sdk/knowledge/fastapi/#serving-mcp).
|
|
223
243
|
|
|
224
244
|
### Public provider callbacks and webhooks
|
|
@@ -240,14 +240,26 @@ whose own request it is serving. The platform setting is `acts_for_requester`.
|
|
|
240
240
|
|
|
241
241
|
### What the requester's access covers
|
|
242
242
|
|
|
243
|
-
-
|
|
243
|
+
- Reads and the creates, updates, runs, sharing changes and deletes the person
|
|
244
|
+
may make, where the platform endpoint supports requester-bound access.
|
|
245
|
+
- Check the person's permission for the exact object and operation on every
|
|
246
|
+
call. A read grant or team membership alone does not authorize a write.
|
|
244
247
|
- The requester's member level, never an admin's, even when the requester is
|
|
245
248
|
an Organization admin.
|
|
246
|
-
-
|
|
249
|
+
- Hosted Agents never receive Secret values, including through this access.
|
|
247
250
|
- At most 24 hours after the person's request, and only while the work for that
|
|
248
251
|
request runs.
|
|
249
252
|
- Checked again on every call, so it stops the moment the person's access ends.
|
|
250
|
-
-
|
|
253
|
+
- Platform-authorized Agent-to-Agent delegation keeps the person who started
|
|
254
|
+
the work and the original request time. Each delegated Agent must itself be
|
|
255
|
+
enabled to act for its requester. Delegation cannot restart the time limit,
|
|
256
|
+
select another person or increase their permissions.
|
|
257
|
+
- A receiving application cannot forward its inbound assertion to establish
|
|
258
|
+
another requester binding. `reads_as_caller()` still refuses these requests.
|
|
259
|
+
|
|
260
|
+
These writes and delegation require platform support; installing this SDK does
|
|
261
|
+
not enable them. Treat a refused operation as refused, never retry it with the
|
|
262
|
+
application's own grants.
|
|
251
263
|
|
|
252
264
|
### Never accept a person's UID from a request
|
|
253
265
|
|
|
@@ -255,19 +267,32 @@ The requester comes only from the platform. An application never accepts a
|
|
|
255
267
|
person's UID from a request body, header or query parameter, and never lets a
|
|
256
268
|
caller choose whom it acts for. A FastAPI application that receives a
|
|
257
269
|
requester-bound call reads the requester with `User.get_requester()` and
|
|
258
|
-
authorizes
|
|
270
|
+
authorizes reads and writes against that person's object- and operation-specific
|
|
271
|
+
permissions:
|
|
259
272
|
`.agents/skills/mainsequence/application_surfaces/api_surfaces/SKILL.md`.
|
|
260
273
|
|
|
261
274
|
### What people are told
|
|
262
275
|
|
|
263
|
-
Every client that shows an application with `acts_for_requester`
|
|
264
|
-
statement
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
276
|
+
Every client that shows an application with `acts_for_requester` uses the exact
|
|
277
|
+
platform-approved statement from
|
|
278
|
+
[Platform ADR-0051, What people are told](https://github.com/Main-Sequence-Server-Side/tdag-django/blob/development/docs/platform/adr/adr-0051-requester-bound-access-for-workloads.md#11-what-people-are-told).
|
|
279
|
+
Do not invent or paraphrase a separate SDK statement. For write-enabled
|
|
280
|
+
deployments, the approved wording must cover supported reads and writes within
|
|
281
|
+
the person's member-level permissions, Organization-admin approval without
|
|
282
|
+
admin powers or Secret values, the original 24-hour limit including delegation,
|
|
283
|
+
access revocation, and prompt-injection risk. Never present a write-enabled
|
|
284
|
+
Agent as read-only or claim that it cannot change, share or delete anything.
|
|
285
|
+
|
|
286
|
+
The platform behavior and approved write-enabled statement must ship together.
|
|
287
|
+
If the platform still supplies only the earlier read-only text, do not claim
|
|
288
|
+
the disclosure is ready for a write-enabled rollout or invent replacement words.
|
|
289
|
+
|
|
290
|
+
Explain the risk alongside the statement: a model-driven Agent can be steered
|
|
291
|
+
by prompt injection. Its reads and writes can reach as far as the person's
|
|
292
|
+
member-level permissions allow, including sharing and deleting where
|
|
293
|
+
supported, for at most 24 hours after the original request. Only Organization
|
|
294
|
+
admins decide which Agents may receive this authority; the application's
|
|
295
|
+
per-operation permission checks remain necessary.
|
|
271
296
|
|
|
272
297
|
## Review Rules
|
|
273
298
|
|
|
@@ -286,6 +311,8 @@ When reviewing an access-control task, look for:
|
|
|
286
311
|
- an application that takes a person's UID from a request instead of from the
|
|
287
312
|
platform
|
|
288
313
|
- `acts_for_requester` presented as something a non-admin can enable
|
|
314
|
+
- a requester-bound write authorized only by a read grant or the Agent's grants
|
|
315
|
+
- prompt-injection risk hidden behind a claim that requester access is read-only
|
|
289
316
|
|
|
290
317
|
## Validation Checklist
|
|
291
318
|
|
|
@@ -304,6 +331,8 @@ Do not claim success until you have checked:
|
|
|
304
331
|
- the task did not confuse sharing policy with orchestration or producer logic
|
|
305
332
|
- an application that acts for its requester takes the person only from the
|
|
306
333
|
platform, and its own grants are intentional
|
|
334
|
+
- requester-bound writes enforce the person's permission for the operation,
|
|
335
|
+
and clients explain both the write risk and the original 24-hour limit
|
|
307
336
|
|
|
308
337
|
## This Skill Must Stop And Escalate When
|
|
309
338
|
|
|
@@ -79,8 +79,8 @@ def _reads_as_caller():
|
|
|
79
79
|
)
|
|
80
80
|
if scope.requester is not None:
|
|
81
81
|
raise RequestIdentityError(
|
|
82
|
-
"This request is requester-bound.
|
|
83
|
-
"
|
|
82
|
+
"This request is requester-bound. reads_as_caller() cannot forward a "
|
|
83
|
+
"requester-bearing assertion to the directory endpoints."
|
|
84
84
|
)
|
|
85
85
|
if scope.caller_assertion is None:
|
|
86
86
|
raise RequestIdentityError(
|
|
@@ -1321,11 +1321,20 @@ class User(_CallerDirectoryReadMixin, UserApiBaseObjectOrm, BasePydanticModel):
|
|
|
1321
1321
|
local mode and WebSockets. Raises ``RequestIdentityError`` outside an
|
|
1322
1322
|
authenticated request, as ``get_logged_user()`` does.
|
|
1323
1323
|
|
|
1324
|
-
Authorize
|
|
1325
|
-
|
|
1324
|
+
Authorize reads and writes against the requester's permission for the
|
|
1325
|
+
exact object and operation. This getter verifies identity, not
|
|
1326
|
+
authorization; read access or team membership does not authorize a
|
|
1327
|
+
write. Give the acting application no rights of its own unless your
|
|
1328
|
+
policy grants them.
|
|
1326
1329
|
An operation that needs a person fails closed when this is ``None``.
|
|
1327
1330
|
Never take a person's UID from a request body, header or query
|
|
1328
|
-
parameter instead.
|
|
1331
|
+
parameter instead. Platform-supported requester-bound writes stay
|
|
1332
|
+
within the person's member-level rights, never admin powers or Secret
|
|
1333
|
+
values. The platform checks access on every call and limits the work to
|
|
1334
|
+
at most 24 hours after the original request, including across approved
|
|
1335
|
+
Agent delegation. A model-driven Agent can be steered by prompt
|
|
1336
|
+
injection, so per-operation checks remain necessary. This getter does
|
|
1337
|
+
not enable platform write endpoints or extend its request scope.
|
|
1329
1338
|
"""
|
|
1330
1339
|
requester = _get_requester()
|
|
1331
1340
|
if requester is not None and not isinstance(requester, RequestUserIdentity):
|
|
@@ -295,8 +295,9 @@ def reads_as_caller():
|
|
|
295
295
|
it. Raises ``RequestIdentityError`` outside an authenticated request or when
|
|
296
296
|
the request carries no assertion (local mode, WebSockets); it never reads as
|
|
297
297
|
the application instead. It also raises in a requester-bound request
|
|
298
|
-
(``User.get_requester()`` is not ``None``):
|
|
299
|
-
|
|
298
|
+
(``User.get_requester()`` is not ``None``): this helper cannot forward a
|
|
299
|
+
requester-bearing assertion to the directory endpoints. Platform-owned
|
|
300
|
+
Agent delegation is separate. See ADR-0036.
|
|
300
301
|
"""
|
|
301
302
|
with _reads_as_caller():
|
|
302
303
|
yield
|
|
@@ -135,6 +135,47 @@ def test_tools_read_the_verified_caller_and_rest_routes_keep_working(signed):
|
|
|
135
135
|
assert "/mcp" not in app.openapi()["paths"]
|
|
136
136
|
|
|
137
137
|
|
|
138
|
+
def test_requester_bound_write_checks_the_person_without_workload_fallback(signed):
|
|
139
|
+
token, _, _ = signed
|
|
140
|
+
server = _server()
|
|
141
|
+
report_editors = {USER, OTHER}
|
|
142
|
+
writes = []
|
|
143
|
+
|
|
144
|
+
@server.tool()
|
|
145
|
+
async def publish_report() -> str:
|
|
146
|
+
requester = User.get_requester()
|
|
147
|
+
if requester is None or requester.uid not in report_editors:
|
|
148
|
+
raise PermissionError("The requester cannot publish this report.")
|
|
149
|
+
writes.append((User.get_logged_user().uid, requester.uid))
|
|
150
|
+
return requester.uid
|
|
151
|
+
|
|
152
|
+
app = _install(FastAPI(), server)
|
|
153
|
+
with TestClient(app) as client:
|
|
154
|
+
allowed = client.post(
|
|
155
|
+
"/mcp",
|
|
156
|
+
json=_call("publish_report"),
|
|
157
|
+
headers={
|
|
158
|
+
**MCP_HEADERS,
|
|
159
|
+
ASSERTION_HEADER: token(requester={"sub": OTHER, "team_uids": []}),
|
|
160
|
+
},
|
|
161
|
+
)
|
|
162
|
+
assert _text(allowed) == OTHER
|
|
163
|
+
|
|
164
|
+
for proof in (
|
|
165
|
+
token(requester={"sub": str(uuid4()), "team_uids": []}),
|
|
166
|
+
token(),
|
|
167
|
+
):
|
|
168
|
+
refused = client.post(
|
|
169
|
+
"/mcp",
|
|
170
|
+
json=_call("publish_report"),
|
|
171
|
+
headers={**MCP_HEADERS, ASSERTION_HEADER: proof},
|
|
172
|
+
)
|
|
173
|
+
assert refused.status_code == 200
|
|
174
|
+
assert refused.json()["result"]["isError"] is True
|
|
175
|
+
|
|
176
|
+
assert writes == [(USER, OTHER)]
|
|
177
|
+
|
|
178
|
+
|
|
138
179
|
def test_concurrent_callers_keep_their_own_identity(signed):
|
|
139
180
|
token, _, _ = signed
|
|
140
181
|
server = _server()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/agent_scaffold/skills/a2a_sdk_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
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/cli/code_repository_status.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
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/client/agent_runtime_models.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
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/repository_identity_security.py
RENAMED
|
File without changes
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence/runtime_credential_exchange.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/mainsequence.egg-info/dependency_links.txt
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
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_canonical_api_route_contract.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_code_repository_branch_contract.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_code_repository_runtime_context.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_environment_resource_context.py
RENAMED
|
File without changes
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_environment_response_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
|
{mainsequence-9.0.15.dev58 → mainsequence-9.0.17}/tests/test_models_user_request_bound_auth.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
|