Repository navigation
Ask for M365 Run as approval only when someone else authored the revision - #1630
Merged
Paul Lizer (paullizer) merged 3 commits intoOct 3, 2026
Conversation
…sion A workflow revision saved by its own Run as user now runs as them without a pending approval. The approval service records an approved, audited, self-authored binding for that exact revision, connection id and generation, and sends no notification. A revision someone else saved, a missing modified_by, an agent or action someone else changed after the save, or a new connection still asks. Audience changes no longer ask again; source sharing and the runtime checks that guard work in progress are unchanged. Explicit decisions still win: a denial or cancellation stops its run, and revoking a binding revokes every approved copy of that revision and keeps it from being self-authored again. Raw Data Management edits of workflows, agents and actions now record the administrator as their last author. The V2 proposal card, the editor's Run as note, the AI assist warning, the Run as help text and the classic Profile and Approvals labels follow the new rule. Version 0.261.229. Refs microsoft#1621 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A revocation only stopped a new self-authored binding from being created. A run that read its records before the revocation could still write a self-authored binding under a new key, for example after a reconnect, and every later run reused it. Copies an interrupted fan-out missed were also reused. ensure_workflow_binding now reuses an approved binding of a revoked revision only when it is an ordinary approval granted after the latest revocation, and revokes any other approved copy it finds, so _create_request can't return it as an existing approval either. _create_self_authored_binding looks for a revocation after writing its record and withdraws the record if it finds one, so either side sees the other. Revoking a copy that changed meanwhile is retried. Refs microsoft#1621 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Before 0.261.229 revoking a Run as binding withdrew only that binding, which covered one audience or connection generation. Treating every stored revocation as revision-wide cancelled approvals still in use on the first run after the upgrade. revoke_workflow_binding now marks each binding it revokes, the chosen one and its fan-out copies, revision_wide. Only marked revocations set the time before which no other approval of the revision stands. A copy a run withdraws later is left unmarked, so it can't cancel an approval the user granted in between. Any revocation still blocks a self-authored binding for its revision. Refs microsoft#1621 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This was referenced Oct 3, 2026
Paul Lizer (paullizer)
merged commit Oct 3, 2026
ca95275
into
microsoft:paullizer-react-v2-ui
11 checks passed
Paul Lizer (paullizer)
added a commit
that referenced
this pull request
Oct 3, 2026
Brings in #1630 (Run as approval only when someone else authored the revision), which the base branch released as 0.261.229. Layer 1 also used 0.261.229, so its release notes move into the v0.261.230 section alongside layer 2 (#1629, already merged into this branch). Merging this pull request takes the base from 0.261.229 to 0.261.230 and delivers both layers. VERSION stays 0.261.230. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
added a commit
that referenced
this pull request
Oct 3, 2026
The base branch released #1630 (Run as) as 0.261.229, the number layer 1 had used. Layer 1 now ships with layer 2 in 0.261.230, so its fix doc, user guide note and test headers say 0.261.230. FIX_VERSION only feeds assert_app_version_at_least, which VERSION 0.261.230 satisfies. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 3, 2026
Bring in the base branch update that released Run as (microsoft#1630) as 0.261.229 and relabeled layer 1 as 0.261.230. The merge was clean: VERSION stays 0.261.232 and the release notes run 0.261.232, 0.261.231, 0.261.230, 0.261.229. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 3, 2026
Run as (microsoft#1630) shipped as 0.261.229, so layers 1 and 2 ship together as 0.261.230. Link the merged 3a and 3b pull requests in the delivery table. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
14 of 24 tasks
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 3, 2026
… Run as The microsoft#1621 screening changes (microsoft#1628, microsoft#1631, microsoft#1632) and microsoft#1630 have landed on paullizer-react-v2-ui, so the roadmap no longer describes V2 where it says a result is withheld when a source document becomes unreadable, or that every material edit needs Run as approval again. - §7: reads and deliveries re-check the chat, workflow and run that hold a result; since 0.261.231 the documents a run's tasks read are provenance only. - Gotcha 36: delivery no longer withholds a result over an unreadable source. - 6a: "lost access" in its Done when now means access to the workflow or run. - Gotchas 4 and 15: since 0.261.229 a revision the Run as user saved, assistant edits included, runs as them without a separate approval; changes saved by someone else still ask again. - The intro names both changes. Docs only; the original plan text in §5 and the shipped Phase 3 notes are left as history. Refs microsoft#1543 microsoft#1546 microsoft#1621 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This was referenced Oct 3, 2026
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 6, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 6, 2026
Captured with --write-golden on unmodified ca95275 (0.261.229, microsoft#1630) in a fresh detached worktree. The only difference from the fd842e1 capture is the captured_from label; microsoft#1630 changed no captured byte. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
added a commit
that referenced
this pull request
Oct 6, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
modified_byequalsm365_run_as_user_id, which equals the run's data user, and nobody else changed an agent or action it uses after that save.ensure_workflow_bindingthen records an approved binding markedself_authored: truefor that exact revision, connection id and generation. It writes an append-onlyself_authored_approvedaudit event, sends no notification and is never pending. A revision someone else saved, a missingmodified_by, or a later edit by someone else still asks. A new connection id or generation also asks again on someone else's revision.ensure_workflow_bindingandvalidate_workflow_bindingstop comparingaudience_version, though the binding still records it. Source-sharing approvals are unchanged, and so are the runtime audience checks that guard runs and deliveries already in progress.m365_workflow_declined). Revoking a binding in Profile revokes every approved copy of that revision. The revision is never self-authored again and falls back to a normal pending approval. A revocation stays in force when it races a run or is interrupted. A revocation made before this release still withdraws only its own binding, so other approvals keep working.modified_byfrom the authenticated actor. The one gap was raw Data Management Cosmos DB editor edits of workflows, agents and actions, which now record the administrator. The V2 proposal card follows the backend's newapproval_state: self_authored. The editor's "Saving requires re-approving Run as" note, the AI assistant'srun_as_reapprovalwarning, the Run as help text and the classic Profile and Approvals labels follow the same rule.Linked issue
Refs #1621
This is the Run as part of #1621. It is independent of the content-screening PR stack (#1628 and later) and touches no content screening code.
Version note: this PR and #1628 both claim
0.261.229. Whichever merges second renumbers its version:config.py, the release notes header, the testVersion:headers andassert_app_version_at_least, and the feature doc.Release Notes & Latest Features
Is this visible to end users?
Is this admin-facing (Admin Settings, governance, deployment, config)?
Should this become a Latest Feature card?
Screenshot needed for the card?
Version bump
application/single_app/config.pyVERSIONthird segment bumped, or not needed because this is docs-onlydeployers/version.txtbumped, or not needed becausedeployers/was not changedVERSIONmoves from0.261.228to0.261.229. Nothing underdeployers/changed.Testing / validation
pythonis a venv overlay on the system site packages with cryptography 46.0.7, Flask 3.1.3, Werkzeug 3.1.6 and Flask-Session 0.8.0. The global environment can't collect these tests. Baselines were recorded onfd842e199before any edit.python -m pytest functional_tests/test_m365_run_as_self_authored.py -q→ 51 passed.python -O -m pytest functional_tests/test_m365_run_as_self_authored.py -q→ 51 passed.functions_m365_approvals.py,functions_m365_execution.py,functions_m365_runtime.pyandfunctions_data_management.pyreverted to base → 15 failed, 28 passed.functions_m365_approvals.py→ 4 failed.test_group_collaboration_source_storage_fix.pyandtest_mcp_authorization_context.py, run withpython -m pytest <files> -q -rfE. No new failures.1284fdfaf: 28 failed, 1899 passed, which is 24 failed test IDs plus 4SUBFAILEDsubtests.capture_execution_identityNameError, and tests that need Azure configuration.test_m365_runtime_imports.pycold-import probe that hit its 90s subprocess timeout under load. Rerun alone,python -m pytest "functional_tests/test_m365_runtime_imports.py::test_web_scheduler_modules_import_without_reversed_bootstrap_or_network[functions_m365_execution-True]" -q→ 1 passed. A baseline timeout in the same family no longer fails.fd842e199:python -m pytest functional_tests/test_group_collaboration_source_storage_fix.py functional_tests/test_mcp_authorization_context.py -qin a base worktree → 4 failed, 49 passed.test_orchestration_workflow_proposal_imports.pyandtest_m365_conversation_lifecycle.py::test_real_conversation_deletion_fork_copy_and_retention_routes. Rerun alone → 7 passed.PLAYWRIGHT_SERVICE_URLunset:python -m pytest ui_tests/test_m365_lifecycle_and_approvals.py ui_tests/test_v2_orchestration_workflow_proposal_card.py ui_tests/test_v2_workflow_ask_ai.py ui_tests/test_v2_workflow_change_tracking.py ui_tests/test_v2_orchestration_auto_open.py -q.test_v2_orchestration_auto_open.py.npm run typecheckandnpm run buildinapplication/v2_ui→ passed.python scripts/build_docs_inventory.py→ the inventory content is unchanged; the line-ending-only diff was restored.python -m pytest functional_tests/test_docs_app_surface_coverage.py functional_tests/test_docs_site_quality.py -q→ 13 passed.1284fdfaf, though no routes changed:python -m pytest functional_tests/route_tests/test_route_blueprint_policy_inventory.py -q→ 11 passedpython -m pytest functional_tests/route_tests/test_route_unauthenticated_policy_contract.py -q→ 6 passedpython -m pytest functional_tests/route_tests/test_route_policy_test_coverage.py -q→ 2 passedfd842e199..1284fdfaf, 40 changed files:python scripts/check_xss_sinks.py --base-sha fd842e199 --head-sha HEAD <changed files>→ passed, 29 files.python scripts/check_broken_access_control.py --base-sha fd842e199 --head-sha HEAD <changed files>→ passed, 20 files.python scripts/check_swagger_routes.py→ not run, because no route files changed.git diff --check fd842e199 HEAD→ clean.873a191e1, a revocation racing a new self-authored binding could be undone. In1284fdfaf, that fix had treated revocations made before this release, which withdrew a single binding, as revision-wide. A final review of1284fdfaffound no remaining bugs.Documentation
Release notes updated, or not needed
Feature documentation updated, or not needed
Fix documentation updated, or not needed
New:
docs/explanation/features/M365_RUN_AS_SELF_AUTHORED_APPROVAL.md.Updated: the release notes (
v0.261.229, Breaking Changes),docs/guides/microsoft-365-conversation-data.mdanddocs/guides/create-a-workflow.md. Also the feature docs for Microsoft 365 actions, workflow editor change tracking, the workflow AI assistant, chat workflow proposals, the workflow draft service, workflow calendar schedules and the orchestration roadmap.No fix doc: this is a behavior change, documented as a feature.
Known limitation, documented: after Create, the proposal card judges a workflow by its own
modified_by. When someone else later edits an agent it uses, the card shows that only once a run waits.Security checklist
@swagger_route(security=get_auth_security())sanitize_settings_for_user()No routes or settings payloads were added or changed.