mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
fb82748296
* fix: make on_behalf_of control permissions for scripts and flows Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: inherit the recorded on-behalf-of identity when a preserving deploy omits it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep an omitted permissioned_as from re-versioning an unchanged script Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: derive the on-behalf-of principal from the email and reject mismatched pairs Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: stop workspace deploys from carrying a source-workspace principal Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: correct the onBehalfOfPermissionedAs param doc Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: pin that workspace deploys never carry a source-workspace principal Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: correct the omitted-principal contract and refresh generated prompts Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: keep external-superadmin principals on email-only redeploys Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: scope the recorded principal to its workspace and prefer real accounts Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: carry the recorded principal correctly through drafts and set-permissioned-as Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: sweep draft identity pairs on email change and offboarding Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: leave group identities alone when sweeping a user's email Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: treat only g/ without an email as a group, and match the offboard preview Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: stop the group guard from skipping rows with no recorded principal Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: state the group guard once instead of restating it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor: make the permissioned_as the only stored on-behalf-of identity Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * perf: skip resolving the on-behalf-of address for sync clients that discard it Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address the local review of the identity refactor Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: resolve the on-behalf-of identity coherently across clones, offboarding and no-op deploys * test: pin that a fork keeps only the on-behalf-of identities that resolve in it * fix: decide a principal prefix-first everywhere and canonicalize bare addresses * fix: prefix a slash-containing address so a reader cannot take it for a group * fix: read an address as a username before the group- convention * fix: rewrite the canonical principal when an account's address moves * fix: keep the address form of a principal to accounts without a usr row * fix: reject an identity a job row cannot carry and read it uncached at dispatch * fix: count characters against the job identity width and cap the backfill * refactor: name the script/flow principal on_behalf_of, as apps do * docs: state the caller-must-authorize contract on the identity resolvers * fix: keep writing on_behalf_of_email until every worker reads the principal * fix: err high on the compatibility version and document the last resolver * fix: keep the compatibility address current through identity mutations * fix: carry the compatibility address with the principal on every copy path * chore: re-pin the EE ref to the companion branch merged with EE main * fix: key the dbt retry lookup on the stored principal * fix: keep a mixed-version address recoverable through a fork * fix: read a round-tripped address uncached so a redeploy is not rejected * fix: refuse an email change that would make a principal unenqueueable * chore: update ee-repo-ref to ac3d7d015296f041ae44ab6bc4953485f44d36e4 This commit updates the EE repository reference after PR #704 was merged in windmill-ee-private. Previous ee-repo-ref: 219b0b03905a1a0028054b3a4985724e77d09036 New ee-repo-ref: ac3d7d015296f041ae44ab6bc4953485f44d36e4 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
84 lines
2.5 KiB
TypeScript
84 lines
2.5 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { deployItem } from "../windmill-utils-internal/src/deploy.ts";
|
|
|
|
// `deployItem` spreads the source item into the request body, and a script's/flow's
|
|
// on_behalf_of names a username that only exists in the source
|
|
// workspace. Sending it to the target pairs one workspace's principal with the other's
|
|
// email, which the backend rejects. Deleting the spread is an easy regression, so pin
|
|
// that the key never reaches the wire.
|
|
function recordingProvider(captured: [string, any][], flowExists: boolean) {
|
|
const source = {
|
|
on_behalf_of_email: "alice@corp",
|
|
on_behalf_of: "u/alice",
|
|
};
|
|
return {
|
|
existsFlowByPath: async () => flowExists,
|
|
existsScriptByPath: async () => true,
|
|
getFlowByPath: async () => ({
|
|
path: "f/x/f",
|
|
summary: "",
|
|
value: { modules: [] },
|
|
...source,
|
|
}),
|
|
createFlow: async (p: any) => void captured.push(["createFlow", p.requestBody]),
|
|
updateFlow: async (p: any) => void captured.push(["updateFlow", p.requestBody]),
|
|
getScriptByPath: async () => ({
|
|
path: "f/x/s",
|
|
summary: "",
|
|
content: "x",
|
|
language: "bun",
|
|
hash: "abc",
|
|
...source,
|
|
}),
|
|
createScript: async (p: any) =>
|
|
void captured.push(["createScript", p.requestBody]),
|
|
} as any;
|
|
}
|
|
|
|
test("deployItem: never sends the source workspace's on_behalf_of", async () => {
|
|
const captured: [string, any][] = [];
|
|
|
|
// The clear is written out once per branch, so exercise all three: a flow that
|
|
// does not exist in the target (create), one that does (update — the branch
|
|
// `wmill workspace merge` takes for anything already deployed), and a script.
|
|
await deployItem(
|
|
recordingProvider(captured, false),
|
|
"flow" as any,
|
|
"f/x/f",
|
|
"src",
|
|
"dst",
|
|
"alice@corp",
|
|
);
|
|
await deployItem(
|
|
recordingProvider(captured, true),
|
|
"flow" as any,
|
|
"f/x/f",
|
|
"src",
|
|
"dst",
|
|
"alice@corp",
|
|
);
|
|
await deployItem(
|
|
recordingProvider(captured, false),
|
|
"script" as any,
|
|
"f/x/s",
|
|
"src",
|
|
"dst",
|
|
"alice@corp",
|
|
);
|
|
|
|
expect(captured.map(([fn]) => fn)).toEqual([
|
|
"createFlow",
|
|
"updateFlow",
|
|
"createScript",
|
|
]);
|
|
for (const [, body] of captured) {
|
|
// The email is still overridden with the caller's choice...
|
|
expect(body.on_behalf_of_email).toBe("alice@corp");
|
|
expect(body.preserve_on_behalf_of).toBe(true);
|
|
// ...while the principal is dropped, so the backend derives the target's own.
|
|
expect(
|
|
"on_behalf_of" in JSON.parse(JSON.stringify(body)),
|
|
).toBe(false);
|
|
}
|
|
});
|