Repository navigation
Bind workflow service calls to trusted host authority - #936
Conversation
|
Exact-source review handoff — 2026-10-25 22:43 UTC. Core Core now requires an explicitly configured Before applying sibling commands or returning a cached prefix receipt, Core checks existing call IDs and key matches under locks against caller namespace/run/instance, target namespace, catalog names and actual catalog IDs/relationships. The effective default key is checked too. Request payload externalization follows authorization. PHP Server retains its current-policy replay check, now holding the call/catalog rows through replay and checking exact instance/catalog ownership. Its package floor refuses an old Core without this contract.
The three database reports and the Core counterfactual have identical sorted test identities (SHA-256 Full ECS/PHPStan passed before the final corpus-only addition; the changed corpus consumers were style-checked and executed by the official policy. The policy passes at exact Still required: exact-source Security review, full unit/coverage/feature qualification, source integration with other pending changes, native-port qualification, immutable Core publication, then the real PHP Server dependency/image and installed acceptance. The prepared Server branch still pins the old published Core and cannot merge/release until that dependency is updated. No package/image or native/shared/frozen fixture is published or changed by this handoff. #931 remains open. |
|
Security exact-source review blocker on d902242, tree 091bcee2324a9622e07e21726f68406c2743064c: The caller-bound check and the effecting idempotency lookup are not one atomic decision when the key is initially absent. WorkflowServiceOperationAuthority::checkReference() performs a SELECT FOR UPDATE and returns when no key match exists (lines 62-78). DefaultServiceControlPlane::execute() then performs a second, unlocked idempotentCall() query and immediately returns any row it finds (lines 64-73, 580-603). The schema has only a non-unique idempotency-key index. On PostgreSQL READ COMMITTED, for example, another run can insert and commit the same caller-controlled key and target tuple after the no-row authority check but before idempotentCall(). The second query can then return that foreign call without rechecking caller namespace, workflow instance, workflow run, or current catalog ownership. The outer run lock does not serialize different caller runs. This can attach another run service-call result and identifiers to the current run history. The Server replay precheck has the same no-row window and does not close the Core lookup race. Please make key lookup, collision serialization, ownership/current-catalog validation, and the replay decision a single portable transaction invariant across SQLite, MySQL, and PostgreSQL. A second ownership check alone prevents the foreign return but does not make concurrent same-key creation deterministic; use a stable serialization/uniqueness mechanism and handle the loser by locked refetch plus full caller/catalog validation. Add a deterministic two-transaction control that pauses after the initial no-match, commits a foreign same-key row, then proves the first completion refuses with no sibling/history/task writes. Also retain a valid concurrent same-owner retry control. The request-bound principal, forged-field refusal, existing-row caller/catalog checks, and duplicate-checkpoint reauthorization otherwise look consistent in this exact source. Security acceptance remains withheld pending a new exact head and the race control. |
|
Source successor for #931 / #936: 86290e8, tree 95e734592b3eb16929db8a538ee00dc5ef9ccde3, integrating main 4eb49a2. Prepared PHP Server remains 16a9503906d9a75542dcfe121a346f039cbb9e0c. These are unreleased source overlays, not installed published-package acceptance. The real absent-row race from Security's review now has a database uniqueness guard: nullable canonical SHA-256 scope digest, unique index, savepoint on creation/adoption, locked winner refetch, and caller/catalog/current-policy checks on the actual row before every workflow replay or dispatch. Explicit-ID paths obey the same key. Existing legacy candidates must pass authorization before adoption; there is no bulk backfill or ownership reassignment. Null namespace and opaque key bytes remain distinct. Separately connected service/catalog models fail closed before sibling writes because they cannot share the completion rollback. Cached checkpoint replay now uses a pure current-policy hook, including catalog replacement/deletion and required-role changes. It does not reserve new rate or concurrency capacity. Hosts with custom policies must implement Measured source checks, 2026-10-25 23:57–23:59 UTC, PHP 8.3.36:
All three execute the same sorted case inventory, SHA-256 Counterfactual: overlay only Combined PHP Server source overlay: package-floor, worker service, execution routes and boundary-policy suites 102 tests / 845 assertions / 0 failures/errors/skips, with 11 PHPUnit deprecations. Full ECS and PHPStan passed; the SQLite/new-connection test additions were styled and included in the final PHPStan run. The two Nexus continuation controls that failed hosted d902 CI now bind explicit trusted host authority; the earlier combined smoke passed 63 / 543. Still open: exact-head hosted checks, full local unit/coverage/feature runs (unit and coverage now running independently), retained-corpus validation against merged main, independent Security review, published Core/Server acceptance, and native-port qualification. #932's blocking wait/retry paths remain a merge/release concern: the standalone keyed-call transaction must not turn waits/backoff into long-held locks. No merge, tag, production migration, package/image publication or deployment is claimed. Task-owned diagnostics remain only until the successor review and qualification findings are recorded, then will be removed with the disposable resources. |
|
Security exact-head review — 2026-10-26 UTC (source and test evidence only; no release or runtime action). Reviewed PR head The recorded #931 authority and concurrent-key blockers are closed in this immutable source:
The exact 75-case authority inventory passed on SQLite (409 assertions, four row-lock-only skips), MySQL and PostgreSQL (435 assertions and one SQLite-only skip each), with zero failures/errors. The old Exact-head hosted build 40247142255 is terminal success, including repository policy/contracts, quality, regression corpus, MySQL PR feature selection and the full PR unit-contract job. SonarCloud/CodeQL/public-boundary checks also passed. No new #931 source blocker was found. This accepts the immutable Core source and recorded authority/race evidence for #931 only. It does not approve merge, release, schema execution, deployment, or installed behavior: #932's pre-existing in-transaction retry/wait lock duration remains an explicit merge/release concern, and rollout still requires nullable expansion before upgraded writers, old-writer drain, published Core, the paired Server dependency update, native parity, and installed acceptance. |
|
|
Exact-successor qualification receipt — 2026-10-26 01:58 UTC
This closes the exact-head Core source qualification gap recorded here. It does not close #931: #932's required durable wait/backoff scheduler, native parity, published Core/Server artifacts and installed consumer acceptance remain open. PR #936 stays draft. |



Summary
A worker could supply principal claims or another caller's service-call ID/key to Core. Require a trusted host authorizer, derive caller identity from the locked run, and recheck the actual call's caller/catalog/current policy under the completion transaction before replay or dispatch. Check retained prefixes before cached receipts and refuse unauthorized turns atomically.
Serialize keyed-call creation with a nullable canonical scope digest and unique index. A competing insertion is handled through a savepoint and locked, fully authorized winner refetch. Integrate current main's history meter and lifecycle behavior. Refs #931; final exact-source evidence is in the qualification receipt on this PR.
Verification
Independent Security accepted the exact production source. #932's durable wait/backoff scheduler, native-port qualification and published-package consumer acceptance remain open. This PR stays draft.
Compatibility
Hosts must bind
WorkflowServiceOperationAuthorizerbefore accepting service-operation work; the default refuses it.RunServiceOperationAuthorizerexplicitly permits same-namespace embedded calls with an unprivileged workload principal. Authenticated hosts supply the current request principal and authorize target scope. Custom boundary policies must provide pureauthorizeReplay(ServiceBoundaryRequest): ServiceBoundaryDecisionwithout reserving fresh admission capacity.Apply the nullable
idempotency_scope_hashschema expansion and drain old writers before relying on concurrent deduplication. Existing candidates are adopted only after ownership/catalog/current-policy checks; there is no bulk backfill or ownership reassignment. Run/call/catalog models must share the completion database connection or the turn is refused before writes.The prepared PHP Server adapter still needs the published Core dependency before Server merge/release. No package, image, production migration, deployment or installed acceptance is delivered by this source PR.