Commit Graph
282 Commits
Author SHA1 Message Date
aiongg 783793cbbc docking: document where a native window's bar docks it 2026-10-23 17:31:11 +00:00
aiongg b46b9dd5c1 docking: a native window's bar docks it at the main window's frame edges
The window docks as its groups at a frame's edge zones, as a group drag would; a body's
center still takes no whole window. Tests for Escape during a bar drag and for the
window focused last being in front.
2026-10-23 17:31:11 +00:00
aiongg 619c93ea29 docking: document drags between OS windows 2026-10-23 17:24:25 +00:00
aiongg 84b42eacc9 docking: tabs, groups and windows drag between OS windows
The window where a drag starts owns it and writes its pointer with its desktop origin.
The window under that point shows the preview with its own targets, and the release
docks there, or floats a new window over the desktop. Leaving a window is no release
with native viewports. Dragging the only tab or group of a window moves it, and its
bar docks the whole window.
2026-10-23 17:24:25 +00:00
aiongg 141ddc92f6 docking: which window lies under a desktop point 2026-10-23 17:24:19 +00:00
aiongg 48272d3932 docking: the host stand-in needs no expect, and the label count drops with New Window 2026-10-23 16:42:36 +00:00
aiongg 0ecc7d2d39 Merge remote-tracking branch 'ao/docking' into dock-windows 2026-10-23 16:42:21 +00:00
aiongg e350bfdb01 docking: the undock hint test uses contains, as clippy asks 2026-10-23 16:40:17 +00:00
aiongg e23e447f32 Merge remote-tracking branch 'ao/docking' into dock-windows 2026-10-23 16:35:58 +00:00
aiongg 53947dbfe8 docking: the undock hint test expects the platform's key 2026-10-23 16:35:35 +00:00
aiongg 99f4511e6d docking: document native windows 2026-10-23 08:27:19 +00:00
aiongg 06c1fc8825 docking: DockDriver stands in for OS windows, and native window tests
with_native_host draws native windows as their own egui frames with a
desktop rect, focus, close requests and the commands they receive. Tests
cover each way into a native window, closing, stable ids, place and
monitor, restore, the bar drag, hiding and forwarded keys.
2026-10-23 08:27:19 +00:00
aiongg 799ab4e691 docking: every float opens in its own OS window
With native-windows on a backend with viewports, each floating window
whose panels allow it is native: in-window floats open over their place
in the app window, and restored windows go back to their monitor or onto
the main window's. Windows stay on top and hide while the app is
inactive. A thin bar with title and close replaces the OS title bar and
moves the window; closing the window closes its panels. Keys a native
window leaves unused come back in DockOutput::forwarded_events, and
DockArea::monitors takes the monitor list. Move Panel to New Window goes,
since every float is native.
2026-10-23 08:27:13 +00:00
aiongg 9c869166e8 docking: floating windows keep a stable id and store their monitor
Floating::id names a window across panel moves: fresh from Floating::new
and on load, unique within a loaded layout, kept by a whole window that
moves and by the receiver of a merge. Floating::monitor and monitor_size
record where a native window is; Action::SetMonitor sets them. Equality
ignores the id.
2026-10-23 08:26:56 +00:00
aiongg 01ce7162a4 docking: Floating::stack is public, and four-way handles take the pointer only
Floating::stack builds a window from groups stacked top to bottom, so an
app's own stacked layouts migrate without building the split chain. The
four-way handle no longer takes keyboard focus: it has no label or key
action, and the two dividers it joins take arrow keys.
2026-10-23 06:11:03 +00:00
aiongg 50f9c06aa7 Merge remote-tracking branch 'upstream/main' into docking
# Conflicts:
#	crates/ui/src/docking/surface.rs
2026-10-23 05:06:13 +00:00
Dylan M. Taylor 4919088427 Merge pull request #238 from dylanmtaylor/security/media-allocation-bounds
security: bound craft-media metadata, sample reservation, header stripping and cue bookkeeping (CodeRabbit)
2026-10-22 22:42:59 -04:00
Dylan M. Taylor c67b1e16b8 Merge pull request #236 from dylanmtaylor/security/docking-group-move-permission
security: require every floating-group member to be movable for MoveFloating (CodeRabbit)
2026-10-22 22:42:36 -04:00
Dylan M. Taylor f0d9c32e67 Merge pull request #237 from dylanmtaylor/security/print-parsing-bounds
security: bound print dialog names, PPD labels, lpstat merge and inherited page geometry (CodeRabbit)
2026-10-22 22:26:23 -04:00
Dylan M. Taylor f721e1b969 Merge pull request #234 from dylanmtaylor/security/cms-eval-work
security: bound cms CLUT interpolation and inverse-curve table work (CodeRabbit)
2026-10-22 22:26:18 -04:00
Dylan M. Taylor c0a3d4c08c media: charge metadata at its converted length, before converting
Lossy UTF-8 conversion can triple invalid bytes, and a fallback key such as ©nam is five
bytes, not four. The budget now charges the length the text will be stored at, computed
without allocating, before the value is converted (CodeRabbit review).
2026-10-22 22:25:45 -04:00
Dylan M. Taylor fd9cf54c48 ui: test that a protected member blocks the floating group's resize grip
Drags the resize grip of sample()'s floating group: a movable group emits MoveFloating,
one with a protected member emits none. Fails without the surface.rs check (CodeRabbit
review nitpick).
2026-10-22 22:23:27 -04:00
Dylan M. Taylor bc8fe0eb53 cms: keep NaN propagation in multilinear interpolation
A NaN input gives a NaN fraction, which the active-dimension check dropped, returning a
finite node value. Keep any nonzero fraction, NaN included (CodeRabbit review).
2026-10-22 22:22:39 -04:00
Dylan M. Taylor 4d30617bcf Merge pull request #235 from dylanmtaylor/security/settings-section-merge
security: validate settings sections against the defaults alone (CodeRabbit)
2026-10-22 22:22:11 -04:00
Dylan M. Taylor b7d92278fe Merge pull request #233 from dylanmtaylor/security/ai-core-bounds
security: bound ai-core redaction and template rendering; consent for params-only requests (CodeRabbit)
2026-10-22 22:22:06 -04:00
Dylan M. Taylor ecf0ad47ad security: bound craft-media metadata, sample reservation, header stripping and cue bookkeeping
Follow-up to the hostile-input fixes in #196, covering findings that PR does not:

- ISO BMFF metadata: all udta/meta entries share a 4 MiB budget charged before a keys name
  is copied, so many ilst items naming one long key cannot multiply it (CodeRabbit CWE-400,
  isobmff/demux.rs:939)
- ISO BMFF stbl: reserve only the samples the chunk map can place, fallibly, instead of the
  declared stsz count (CodeRabbit CWE-789, isobmff/demux.rs:767)
- Matroska: a header-stripping prefix over 256 bytes is treated as unsupported compression
  rather than copied in front of every frame; Track::sample_size no longer allocates the
  prefix (CodeRabbit CWE-409, matroska/track.rs:257)
- Matroska muxer: per-track cue flags use a cluster number, so starting a cluster no longer
  clears every declared track (CodeRabbit CWE-407, matroska/mux.rs:402)
2026-10-22 21:53:10 -04:00
Dylan M. Taylor 4f85efb2b9 security: bound print dialog name resolution, PPD labels, lpstat merge and inherited geometry
- craft-ui shown_names resolves label collisions with hash-map counts and a worklist, so a
  crafted cascade is linear instead of cubic (CodeRabbit CWE-407, ui/src/printing.rs:32)
- parse_ppd caps group, option and choice labels at 256 characters before each option copies
  its group (CodeRabbit CWE-400, print/src/lib.rs:232)
- printers_parsed tracks seen destinations in a HashSet (CodeRabbit CWE-407, lib.rs:417)
- sheets::Reader::rect checks an inline array's length before reading it and borrows direct
  objects instead of deep-cloning the inherited MediaBox/CropBox/Rotate for every page
  (CodeRabbit CWE-400, print/src/sheets.rs:774)
2026-10-22 21:49:46 -04:00
Dylan M. Taylor d66e345cc7 security: require every floating-group member to be movable for MoveFloating
MoveFloating checked only the panel it named, but changes the rectangle shared by that
panel's whole floating group, so naming a movable sibling moved a panel whose policy forbids
it. The model now refuses the action unless every member is movable, and the floating
window's resize grip no longer emits it for such a group.

CodeRabbit CWE-863, crates/ui/src/docking/model.rs:392
2026-10-22 21:46:25 -04:00
Dylan M. Taylor 08109be362 security: validate settings sections against the defaults alone
deserialize_sections tried each top-level key against a document holding every key accepted
before it, cloning and deserializing the growing document per key. A config.toml with many
unknown keys took quadratic time (20k keys: >2 minutes, now <1 s). Each key is now checked
against the defaults plus that key, and accepted keys are merged once.

CodeRabbit CWE-407, crates/settings/src/document.rs:47
2026-10-22 21:42:13 -04:00
Dylan M. Taylor c900c69553 security: bound cms CLUT interpolation and inverse-curve table construction
- Clut::multilinear enumerates corners only for dimensions between two grid points, so
  singleton dimensions no longer multiply per-pixel work (CodeRabbit CWE-407, clut.rs:238)
- Transform::from_pipeline finds a sampled curve's flat ends once per curve via
  Curve::inverse64_many instead of rescanning the table for each of the 4096 output entries
  (CodeRabbit CWE-407, curve.rs:276)
2026-10-22 21:39:20 -04:00
Dylan M. Taylor a719521c13 security: bound ai-core redaction, template rendering and model checks; consent for params-only requests
- redact matches secrets in the original text only, so markers are never searched again
  (CodeRabbit CWE-400, secret.rs:47)
- render_text/render_value share one MAX_RENDERED_BYTES budget across repeated slots
  (CodeRabbit CWE-400, spec/template.rs:122)
- Connection::validate checks model-ID uniqueness with a set instead of a pairwise scan
  (CodeRabbit CWE-407, connection.rs:205)
- Disclosure::kinds counts parameters as text, so a request carrying only params still needs
  an agreement (CodeRabbit CWE-863, consent.rs:123)
2026-10-22 21:37:34 -04:00
Dylan M. Taylor 514db92b77 Merge pull request #229 from storytold/sonar-fix/path-cmd-hardening
security: validate CLI paths/args in dev tools (SonarCloud S2083/S8707/S8705)
2026-10-22 19:33:13 -04:00
Dylan M. Taylor 7a6d60a285 security: enforce HTTPS redirects and atomic write in fetch-pdf-test-fonts.py 2026-10-22 19:28:55 -04:00
aiongg 9ff107c2c1 docking: rustfmt, and doc comments for floating trees 2026-10-22 20:23:27 +00:00
aiongg deec5af9cf docking: random drops reach floating windows and move panels between windows
The property test starts with a split floating window beside Info's,
drags tabs and drag bars into, out of and between windows, floats some
with Ctrl/Cmd, and checks after every drop that no panel is lost, every
group in every window keeps its minimum and every divider can travel
both ways.
2026-10-22 20:22:00 +00:00
aiongg 281ea71f5b docking: the drop preview shows the zone under the pointer
With side_edge_zones, a drop on a group fills the zone the pointer is in
(a side's trapezoid, or the center rectangle with the tab strip) and
outlines the rect the drop gives what moves. zone_shape gives a zone's
outline; DockDriver::filled_polygon checks it. The dock-and-canvas
arrangement keeps its filled half and insertion lines.
2026-10-22 20:20:26 +00:00
aiongg 809bf90936 docking: a floating window holds a tree like the docked layout
Floating::root replaces the stack of groups. A floating window takes
splits in any direction, tab groups and accordions; its groups split,
join and resize like frames, with the Sizer, four-way handles
(Divider::WindowSplit, Divider::WindowIntersection,
Action::ResizeWindowSplit) and the room check. Tabs and drag bars inside
it show the targets of every window and dock; Undock Panel Group floats
one group of a window that has several. Floating::minimized replaces
per-group minimizing in a window.

Saved layouts keep loading: a stored stack of groups becomes a vertical
split sized by the groups' heights. Placement::Group on a floating anchor
splits its group above or below. A window moved onto a dock keeps its
groups as stacked groups.
2026-10-22 20:19:09 +00:00
aiongg 5abc37e454 docking: a release over no target cancels; the title bar only moves a window
Two DockStyle settings, on by default so the dock-and-canvas arrangement
keeps its behaviour. Without float_on_empty_drop, a tab or group released
over no target inside the app window (the gap between groups, a menu bar,
a status bar) cancels the drag; Ctrl/Cmd or a release outside the window
floats it. Without title_bar_docks, dragging a floating window's title bar
only moves the window.
2026-10-22 20:08:18 +00:00
aiongg d30c207c8d docking: one model; profile differences are style data
Remove `Profile`. What it switched is now a `DockStyle` setting with the
dock-and-canvas behaviour as the default: `side_edge_zones`,
`new_dock_zones`, `maximize_item`, `close_others_item`,
`command_press_floats`, `float_hint`, and plain bools for
`wheel_selects_tabs` and `middle_click_closes_tabs`. The undock and
Close Panel Group labels go; an app sets `float_label`,
`float_group_label` and `close_group_label` instead.

Remove the size machinery that made frames stick: `DockContent::bare`,
`FixedSlot` and the split that took a parent's or sibling's half beside
a fixed-size frame, and the gap snapping to the nearest frame. A tab
group takes the largest maximum of its panels, so a panel without one
lifts the cap of the group it joins. A dragged divider stores a ratio
whatever mode it was saved with.

Sizes follow the reference rules: a divider resizes only the groups
that touch it and stops at their minimums; a four-way handle where a
divider ends on another moves both (`Divider::Intersection`); a split or
outer-edge drop that would leave a group without `min_pane` is not
offered, and a group too small to halve takes the drop as a tab.

Tests: one per rule, the stuck cases from the FilmCraft map, and a
property test over random drops checking minimums and divider travel.
2026-10-22 20:01:31 +00:00
skylar taylor-barrick b1401e33b1 Share browser download resource ownership (#226)
Add opt-in browser download helpers that own detached links and object URLs, clean up failed or abandoned preparation, and register delayed URL cleanup before issuing a click. Applications retain filename, MIME type, pacing, and user-activation policy.

Include browser lifecycle and failure-path tests, public API documentation, and Sonar test-source classification. All 32 PR checks passed; targeted WASM Clippy and formatting passed in local validation.
2026-10-22 20:49:41 +02:00
James ChapmanandClaude Code f20f364d55 hayro-jbig2: cap long-form referred-to segment count (#176)
* hayro-jbig2: cap long-form referred-to-segment count

A crafted JBIG2 segment header can claim a 29-bit referred-to-segment count;
Vec::with_capacity reserved ~2 GiB from that field before a single
referred-to number was read, and the resulting allocation failure aborts
the process in a way catch_unwind cannot contain (fatal on wasm32, where
memory is capped well below 2 GiB). A ~100 KB Flate-compressed PDF was
enough to reach it inside the 256 MiB stream budget.

Real files refer to a handful of segments, so the count is now capped at
u16::MAX; larger claims fail as InvalidReferredCount before any
retention-flag bytes are consumed. Regression test included.

Updates SOURCE.json's local hash for src/segment.rs and records the patch
in vendor/README.craft-reader.md, following the vendored tree's provenance
practice.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* hayro-jbig2: record git-blob sha256 for patched segment.rs

The previous entry hashed the Windows working-tree checkout (CRLF) of
src/segment.rs instead of the LF content git stores, so every other
manifest entry's convention (git-blob content hash) was broken by this
one file. Re-hash against `git show HEAD:vendor/hayro-jbig2/src/segment.rs`
as the vendored manifests' other 30 entries do.

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-10-22 13:10:36 -04:00
skylar taylor-barrickandskylartaylor ffe7f8fce8 Share Linux and BSD desktop appearance observation (#225)
* platform: share desktop appearance observation

* Align appearance target guards and document watcher contracts

* Replace appearance wildcard imports with explicit dependencies

---------

Co-authored-by: skylartaylor <skylartaylor@users.noreply.github.com>
2026-10-22 10:13:09 -04:00
skylar taylor-barrickandskylartaylor b9c1a1105e Add craft-platform with shared native dialog lifecycle helpers (#224)
* platform: add native dialog lifecycle services

* Document dialog outcomes and lifecycle contracts

---------

Co-authored-by: skylartaylor <skylartaylor@users.noreply.github.com>
2026-10-22 10:13:08 -04:00
Dylan M. Taylor 1b9cf1973a ci: pin GitHub Actions to full commit SHA (SonarCloud githubactions:S7637) (#228)
Pin third-party actions to full-length commit SHAs (with version comments)
instead of mutable tags/branches to prevent supply-chain tampering via
retagged releases. Resolves SonarCloud rule githubactions:S7637.
2026-10-21 20:14:01 -04:00
Dylan M. Taylor e25b6ec6e6 security: validate CLI paths/args in dev tools (SonarCloud S2083/S8707/S8705/S7044)
Resolve and validate command-line path arguments before use, enforce HTTPS at
download sinks, and confirm path containment. Hardens local codegen/fetch tools
against path-traversal and command-argument-injection findings.
2026-10-21 17:12:54 -04:00
Dylan M. Taylor ce89625521 ci: add sonar-project.properties for CI-based analysis
Marks the project ineligible for SonarCloud Automatic Analysis, resolving the
CI-vs-automatic-analysis conflict so the SonarCloud workflow succeeds.
2026-10-21 16:00:28 -04:00
Dylan M. Taylor 20b2c1a1eb ci: add SonarCloud scan via shared reusable workflow
Calls storytold/craft-common-actions/.github/workflows/sonarcloud.yml@main
with secrets: inherit. Adds SonarCloud badge to README where missing and
removes the redundant sonar-project.properties (config now passed by the
reusable workflow).
2026-10-21 15:46:51 -04:00
aiongg 958c5ada58 docking: the Frame profile's drop hint says undock, as its menus do 2026-10-21 16:46:50 +00:00
aiongg 7d786e5108 docking: the Frame profile drop preview says which key floats
While a drag offers a docking target, a hint under the pointer reads
"Hold Ctrl to float" ("Hold ⌘ to float" on macOS), from the
localizable float_hint_label (key dock.floatHint).
2026-10-21 16:45:29 +00:00
aiongg 899807ff19 docking: a split beside a fixed-size frame keeps that frame's size
A side split replaced the anchor frame in place, so a split beside a
fixed-width frame such as a tool strip took the frame's fixed slot:
the two frames shared its width, and the parent's divider resized both.
The frame now keeps its size: on its outer side the new split wraps the
parent, on its inner side it halves the parent's other child. The drop
preview shows the half the new frame takes.
2026-10-21 16:44:06 +00:00