`Prefs::set` makes a JSON pointer of the key (`key.replace('.', "/")`), so
`scripting/allowScriptsWriteFiles` resolves as well as the dotted spelling, and
the page on its own (`{key: "scripting", value: {…}}`) replaces every setting on
it — `coerce` takes an object for an object, and the page deserializes with
`serde(default)`. A prefix check on `scripting.` let both through. The page is
now read from the key's first segment, split on either separator.
Found by CodeRabbit on the pull request; reproduced before fixing, with
`prefs.set {key: "scripting/allowScriptsWriteFiles", value: true}` answering
`{"scripting/allowScriptsWriteFiles": true}` under confinement.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
EffectCraft writes its own templates as `media/<item id>/<file>` entries, and
extraction trusted both halves. `base_name` splits on `/` and `\`, but the item
id was taken with `split('/')` alone, and it is pasted in front of a base name
another item already used. So a second `media/..\..\..\Startup\x/clip.mp4`
entry became `<dir>/..\..\..\Startup\x-clip.mp4`, which on Windows is three
folders up, with the attacker choosing how the name ends.
The id is now used only when it is one, and the name goes through
`safe_file_name`: separators, drive colons and NUL become `_`, and `.` / `..`
become `footage`. Reached from `templates.create` with `path`, from File ▸ New
from Template, and from a template dropped in the user Templates folder.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The CLI installed no logger, so GPU warnings (a declined frame, out of
memory, fallback to the CPU) were dropped and an export silently rendered
on the CPU. Install the engine logger with a `warn` default (RUST_LOG
still overrides). Split out of #1415.
`script.run` and the Scripts menu are refused while file access is confined,
but a ScriptUI panel's script was not: `window.scriptPanel` runs it to build
the panel, `window.restoreScriptPanels` runs every remembered one,
`scriptui.click` / `set` / `mouse` / `close` dispatch events to its handlers,
and `script.runTasks` runs its `app.scheduleTask` tasks. A script reads and
writes files and reaches the network, so none of that may start while confined.
`prefs.set` is refused for the `scripting.*` settings for the same reason: the
engine already stops a script from granting itself the access the user withheld
(`Scripting::same_permissions`), and a confined agent writing it to the settings
file would hand it to every script run afterwards, long after the session.
`prefs.get` and the read-only `scriptui.list` / `scriptui.get` are untouched.
This is the "Running code" part of the F-11 audit; the other parts of #2131
are separate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Upstream split lib.rs files into modules and moved engine commands/ to cmd/; this branch's change merges without textual conflicts.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Upstream split lib.rs files into modules and moved engine commands/ to cmd/; this branch's change merges without textual conflicts.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
H.264 and ProRes exports of a 60-frame comp (several render batches, a
rotating stroked ring, a fading solid at a fractional position, a
Screen-mode shape, 8 bpc) must keep the exact bytes main wrote before the
two previous commits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Much of a layer buffer is often transparent (a stroked ring, a glow-padded
text layer, a precomp canvas), yet every destination pixel sampled it
bilinearly, and 8/16 bpc comps then re-quantised the layer's whole rotated
bounding box.
- Bilinear warps skip 16x16 source tiles whose pixels (and a one-pixel
apron) all have zero alpha: their samples are transparent and were never
drawn.
- The fast affine warp reports the rectangle it changed and, given the
comp's levels, quantises each pixel as it blends it, so draw_comp has
nothing left to re-quantise for that layer. quantize_px moves to
effectcraft-raster for this.
- quantize_rect skips runs of four all-zero (+0.0) pixels, which quantise
to themselves.
- to_rgba8 / to_rgba8_over convert row by row instead of per 4-byte item.
Every pixel stays bit-identical: tests compare the warp against the
reference path, fused quantising against quantising after blending, and
the zero-run skip against per-pixel quantising.
With the previous commit, demo comp to H.264 (`cargo xtask bench --scenario
demo --format h264 --frames 300`, 11 interleaved runs on a 16-thread Ryzen):
wall 9.26 s -> 6.97 s median (-24.8%), 8.55 s -> 6.55 s min (-23.3%); CPU
time -23%. Output byte-identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Movie exports (H.264, HEVC, AV1, ProRes, uncompressed) rendered a batch of
frames on every core, then encoded it frame by frame while the render
threads waited. Each batch now encodes on a pool shared by all exports while the
next batch renders (Cx::frames_beside). With deferred GPU readbacks, or
where no thread can be started (wasm without threads), the two still take
turns. A panicking encoder becomes an export error.
H.264 frames are converted to 4:2:0 on the render threads, per frame, instead
of on the encoder's critical path. The conversion reads 8-bit levels from a
table and rounds without a libm call; both give the same values as before
(tested against the previous formula).
Demo comp (1920x1080, 300 frames) to H.264 on a 16-thread Ryzen, export
wall time -6% (median of 7 interleaved runs); output byte-identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts came from upstream splitting crates/project/src/lib.rs and moving the
frames tests. Re-applied the branch's change in the new places:
- Layer::same_pixels_with now in crates/project/src/layer.rs
- Comp::same_pixels_with, same_settings(o, with_markers), pixel_form_with and the
timing-marker helpers in crates/project/src/comp.rs (same_pixels_ignoring_markers
stays removed)
- Project::reads_markers in crates/project/src/item.rs
- crates/ui-egui/src/frames.rs uses reads_markers/same_pixels_with; the branch's
two marker tests replace the old ones in crates/ui-egui/src/frames/tests.rs
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
text/layout: upstream split paragraph() into Para/place_line helpers and moved the tests to
layout/tests.rs. The branch's changes are re-applied there: the resolved paragraph direction
is passed to margins_for/avail_for/align_for (RTL point text with Justify sits flush right),
first_ascent/plausible_first and ParaLine.first/style_first (box first baseline is the d
height, vertical text keeps the ascent), and the Justify All last-line cost in
optimal_breaks. The branch's seven new layout tests moved to layout/tests.rs.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Keeps the already-pushed branch history; the resolved tree is unchanged: render tests live in
crates/render/src/tests/ (mask_feather.rs registered in tests.rs).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
render: upstream moved the tests_*.rs modules into crates/render/src/tests/; the branch's
tests_mask_feather.rs now lives at tests/mask_feather.rs and is registered in tests.rs.
path: rect() keeps the branch's explicit-outline version with an added NaN guard on the
roundness clamp bound (main's fix for the same panic).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Real msiexec runs (per-user and all-users, silent and wizard) found two defects
that the metadata fixtures cannot see:
- "Only for me" published ALLUSERS=2, so FindRelatedProducts treated the run as
per-machine and skipped the existing per-user copy. An interactive upgrade
left two registered products and uninstall left files behind. The page now
leaves ALLUSERS unset for a per-user choice.
- Windows Installer resolves Program Files once, for the context it started in,
so choosing "Everyone" in the wizard installed into the user profile with a
machine-wide registration. The wizard now sets the new-install folder itself
after the choice (Program Files, Program Files (x86) for 32-bit, or the
per-user Programs folder). Silent installs are unchanged.
check-install-policy.ps1 now fails if either regresses.
* fix(ui-egui): craft_ui::ComboBox for every combo box, so open menus grow back (egui#5225)
Repins craft-libs to aiongg/craft-libs 60d60d48 (storytold main with the shared
dropdown) and bans egui::ComboBox in clippy.toml.
* fix(ui-egui): font menu under the font field is a craft_ui combo menu that grows back
The filter row is the menu's header and only the font list scrolls, so a search
that matched nothing grows the menu back when it is cleared.
* chore(deps): craft-libs 4d7b82f7 (dropdown fixes)
* chore(deps): craft-libs 92d392cf (#387 merged)
* chore(xtask): pdf-deps expects craft-libs 92d392cf