mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
343ce6e143
* fix: default an omitted app policy execution_mode to publisher Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: drop stale comments claiming execution_mode is required Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: derive a raw app's policy on deploy instead of trusting the caller's Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: pin the ee ref to the companion branch Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: vendor the raw-app policy derivation into the bundle job Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: note the vendored raw-app policy bundle Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: derive the policy on a value-only raw-source update too Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: reject raw-app runnables whose shape yields an unusable grant Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: cache the new policy query and tighten raw-app runnable validation Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: let the policy bundle drift guard survive a CRLF checkout Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: update ee-repo-ref to 23431f5cf1d627051ded89111bbf2e301e9db456 This commit updates the EE repository reference after PR #729 was merged in windmill-ee-private. Previous ee-repo-ref: 0bdf8818fa115ad6b0d14f3117a18e8a580cce4d New ee-repo-ref: 23431f5cf1d627051ded89111bbf2e301e9db456 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>
70 lines
2.8 KiB
TypeScript
70 lines
2.8 KiB
TypeScript
/**
|
|
* The raw-app bundle job carries the frontend's policy derivation, vendored by
|
|
* cli/generate-app-policy.ts into backend/windmill-api/src/apps_raw_policy.gen.js
|
|
* and prepended to the job script.
|
|
*
|
|
* If that copy drifts from the frontend source, deployed apps get policy keys
|
|
* the app editor would not have written, and every runnable is refused at run
|
|
* time with "forbidden by policy" — an app that deploys and then does nothing.
|
|
* So rebuild the bundle here and fail when the committed one no longer matches.
|
|
* Fix by running `bun run gen:app-policy` from cli/.
|
|
*
|
|
* No backend required.
|
|
*/
|
|
|
|
import { expect, test, describe } from "bun:test";
|
|
import { readFileSync } from "node:fs";
|
|
import { buildAppPolicyBundle, OUT_FILE } from "../generate-app-policy.ts";
|
|
|
|
describe("raw app policy bundle", () => {
|
|
test("the committed bundle matches the frontend source", async () => {
|
|
// Line endings normalized: a CRLF checkout is the same bundle, and must not
|
|
// read as drift (the committed file's header arrives as CRLF on Windows).
|
|
const lf = (s: string) => s.replace(/\r\n/g, "\n");
|
|
expect(lf(readFileSync(OUT_FILE, "utf-8"))).toBe(
|
|
lf(await buildAppPolicyBundle()),
|
|
);
|
|
});
|
|
|
|
test("derives the keys the app editor writes", async () => {
|
|
// Exercise the committed artifact itself, not the frontend module: it is
|
|
// what actually runs on the worker.
|
|
// A module's top-level `var` is not a global, and the job prepends this
|
|
// bundle into its own module, so reach the binding the same way it does.
|
|
const { updateRawAppPolicy } = new Function(
|
|
`${readFileSync(OUT_FILE, "utf-8")}\nreturn __wmillAppPolicy`,
|
|
)();
|
|
|
|
const content = "export async function main(a: string) { return a }\n";
|
|
const sha = new Bun.CryptoHasher("sha256").update(content).digest("hex");
|
|
|
|
const policy = await updateRawAppPolicy(
|
|
{
|
|
inline: {
|
|
type: "inline",
|
|
inlineScript: { content, language: "bun" },
|
|
fields: {
|
|
pinned: { type: "static", value: "by-the-publisher" },
|
|
secret: { type: "static", value: "shh", sensitive: true },
|
|
},
|
|
},
|
|
by_flow: { type: "path", runType: "flow", path: "u/admin/f", fields: {} },
|
|
},
|
|
undefined,
|
|
);
|
|
|
|
expect(Object.keys(policy.triggerables_v2).sort()).toEqual([
|
|
"by_flow:flow/u/admin/f",
|
|
`inline:rawscript/${sha}`,
|
|
]);
|
|
// `sensitive_inputs` is what makes the server encrypt the arg before it
|
|
// reaches the job, so losing it would silently store the value in plaintext.
|
|
const inline = policy.triggerables_v2[`inline:rawscript/${sha}`];
|
|
expect(inline.static_inputs).toEqual({
|
|
pinned: "by-the-publisher",
|
|
secret: "shh",
|
|
});
|
|
expect(inline.sensitive_inputs).toEqual(["secret"]);
|
|
});
|
|
});
|