Files
windmill/cli/generate-app-policy.ts
Ruben Fiszel 343ce6e143 fix: derive a raw app's policy on deploy, and default an omitted execution_mode (#10733)
* 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>
2026-08-18 01:52:10 +02:00

94 lines
3.2 KiB
TypeScript

/**
* Bundles the frontend's raw-app policy derivation into a script the server's
* bundle job carries, and writes it next to that job's source.
*
* The derivation is not re-implemented in Rust, and not shelled out to `wmill`
* either. `triggerables_v2` is the allowlist every component run is matched
* against, keyed by `<component>:rawscript/<sha256 of the inline code>` — a key
* derived any other way leaves a deployed app's runnables "forbidden by policy",
* which reads as a broken app rather than a failed deploy. So the app editor,
* `wmill app push` and the server all have to agree, and the way to guarantee
* that is one source.
*
* It rides in the job script rather than in the CLI the job already runs,
* because the images install `windmill-cli` unpinned: an image can carry a CLI
* older than its server, and falling back to `bun x windmill-cli@<release>`
* needs npm reachable at deploy time, which is exactly what the bundler's
* installed-CLI branch exists to avoid. The job script is `include_str!`d into
* the server binary, so it always matches the server.
*
* Run `bun run gen:app-policy` after touching
* frontend/src/lib/components/raw_apps/rawAppPolicy.ts or anything it imports;
* test/app_policy_bundle_unit.test.ts fails when the committed bundle no longer
* matches those sources.
*/
import * as esbuild from "esbuild";
import { readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
const REPO_ROOT = join(import.meta.dir, "..");
const RAW_APPS_DIR = join(
REPO_ROOT,
"frontend",
"src",
"lib",
"components",
"raw_apps",
);
export const OUT_FILE = join(
REPO_ROOT,
"backend",
"windmill-api",
"src",
"apps_raw_policy.gen.js",
);
const HEADER = `// Generated by cli/generate-app-policy.ts. Do not edit.
// Run \`bun run gen:app-policy\` from cli/ to rebuild it from
// frontend/src/lib/components/raw_apps/rawAppPolicy.ts.
//
// Prepended to the raw-app bundle job (see apps_raw_bundle.rs), which calls
// \`__wmillAppPolicy.updateRawAppPolicy\` from its own module scope.
`;
/** The bundled IIFE, header included. Exported so the staleness test can build
* it and compare, rather than keep a hash in step by hand. */
export async function buildAppPolicyBundle(): Promise<string> {
const result = await esbuild.build({
stdin: {
contents: `export { updateRawAppPolicy } from './rawAppPolicy'`,
resolveDir: RAW_APPS_DIR,
loader: "ts",
},
bundle: true,
format: "iife",
globalName: "__wmillAppPolicy",
target: "es2022",
// `hash()` falls back to this only when Web Crypto is missing, which it
// never is on a worker's bun. Left unresolved so the bundle needs nothing
// installed where it runs.
external: ["@aws-crypto/sha256-js"],
minify: true,
write: false,
legalComments: "none",
});
return HEADER + result.outputFiles[0].text;
}
if (import.meta.main) {
const js = await buildAppPolicyBundle();
const before = (() => {
try {
return readFileSync(OUT_FILE, "utf-8");
} catch {
return "";
}
})();
writeFileSync(OUT_FILE, js, "utf-8");
console.log(
`${before === js ? "Unchanged" : "Wrote"} ${OUT_FILE} (${
Math.round(js.length / 1024)
} KB)`,
);
}