Release1 august - #733
Conversation
More friendly flock purple
Just log errors to console
Say plane was turning black when glow was applied
Addresses issue with Mac Ctrl+Z not being released and triggering AZERTY movement
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
main/execution.js (1)
135-143: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winPosition the overlay after the canvas view is active.
When
currentView === "code"on a narrow screen,showStoppedOverlay()measures the canvas beforeshowCanvasView()changes its layout. The overlay can then retain stale geometry and fail to cover the canvas.Switch to the canvas view before measuring the overlay. Update the overlay when the canvas size changes. Test stopping from narrow-screen code view and assert that the overlay rectangle matches
#renderCanvas.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@main/execution.js` around lines 135 - 143, Reorder the stop flow so the narrow-screen code-view branch calls showCanvasView() before showStoppedOverlay() measures the canvas. Ensure the overlay is refreshed after any canvas-size/layout change, while preserving event-listener removal and existing view behavior; validate stopping from code view on a narrow screen produces an overlay rectangle matching `#renderCanvas`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@flock.js`:
- Around line 1343-1346: Separate application shortcut handling from Babylon
camera-input filtering in the canvas keydown handler. Ensure Ctrl- or
Alt-modified keys are blocked from reaching Babylon keyboard observers and
updating camera _keys, while application/browser shortcuts continue to be
handled normally; preserve Meta behavior as intended.
- Around line 777-785: Add a regression test covering the host-function wrapping
initialized by wrapScript: run untrusted code with a callable endowment and
computed "constructor" access, and assert it cannot execute generated source or
reach the host window or document. Include checks for both the wrapped function
endowment and performance.now, preserving the existing lockdown behavior.
In `@main/files.js`:
- Around line 380-382: Replace the response.text() buffering and
projectText.length check with byte-based streaming in the surrounding project
response flow: reject Content-Length values over 4 MiB, read response.body
incrementally, track encoded byte counts, and abort once the limit is exceeded
while preserving successful decoding at exactly 4 MiB. Add coverage for exactly
4 MiB, one byte over, and multibyte content.
In `@main/main.js`:
- Around line 237-240: Remove the inaccurate provenance comments: in
main/main.js lines 237-240 remove the claim about a button click causing a
second executeCode call; in style.css line 438 remove or correct the claim that
gizmos remain clickable while stopped; and in locale/de.js line 1072,
locale/es.js line 1066, locale/fr.js line 1065, locale/it.js line 1067,
locale/pl.js line 1065, locale/pt.js line 1057, and locale/sv.js line 1047
remove the standalone “// ai” comments. Keep only comments that accurately
describe the current implementation.
---
Outside diff comments:
In `@main/execution.js`:
- Around line 135-143: Reorder the stop flow so the narrow-screen code-view
branch calls showCanvasView() before showStoppedOverlay() measures the canvas.
Ensure the overlay is refreshed after any canvas-size/layout change, while
preserving event-listener removal and existing view behavior; validate stopping
from code view on a narrow screen produces an overlay rectangle matching
`#renderCanvas`.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 72d7ca07-0396-40f7-bb14-51b060ddc28a
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (17)
api/events.jsapi/material.jsflock.jsgenerators/generators-material.jsindex.htmllocale/de.jslocale/en.jslocale/es.jslocale/fr.jslocale/it.jslocale/pl.jslocale/pt.jslocale/sv.jsmain/execution.jsmain/files.jsmain/main.jsstyle.css
| // Re-wraps a host-realm fn into this realm; lockdown only tames this | ||
| // realm, so a raw host fn would leak the untamed Function via | ||
| // `.constructor` (sandbox escape). Must run before lockdown. | ||
| const wrapScript = doc.createElement("script"); | ||
| wrapScript.type = "text/javascript"; | ||
| wrapScript.text = | ||
| "window.__flockWrapHostFn = (fn) => (...args) => fn(...args);"; | ||
| doc.head.appendChild(wrapScript); | ||
|
|
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate existing sandbox and runCode tests for an escape-regression test.
fd -HI -t f . | rg '(test|spec)' | while IFS= read -r file; do
rg -n -C 3 'runCode|Compartment|lockdown|constructor|performance\.now' "$file" || true
doneRepository: flipcomputing/flock
Length of output: 12530
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | sed -n '1,200p'
echo "== flock.js outlines/size =="
if [ -f flock.js ]; then
wc -l flock.js
ast-grep outline flock.js --match 'startFlockSession|lockdown|constructor|performance\.now|runCode' || true
echo "== relevant flock.js lines 720-845 =="
sed -n '720,845p' flock.js | nl -ba -v720
else
echo "flock.js not found"
fi
echo "== lockfiles/config for ses and tests =="
git ls-files | rg '(^SECURITY|SECURITY|README|package.(json|lock|json5|workspaces|json$)|test|spec|playwright|vitest|jest|mocha)' || true
rg -n '"(ses|lockdown|sesify|ses-shim|SES)"|runCode|playwright|vitest|jest|mocha' package.json package-lock.json SECURITY README.md 2>/dev/null || true
echo "== runCode mentions in source =="
rg -n -C 3 'runCode|compartment|Compartment|lockdown|escape|sandbox|SES' . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' || trueRepository: flipcomputing/flock
Length of output: 4608
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | sed -n '1,200p'
echo "== flock.js outlines/size =="
if [ -f flock.js ]; then
wc -l flock.js
ast-grep outline flock.js --match 'startFlockSession|lockdown||performance\.now|runCode' || true
echo "== relevant flock.js lines 720-845 =="
sed -n '720,845p' flock.js | nl -ba -v720
else
echo "flock.js not found"
fi
echo "== lockfiles/config for ses and tests =="
git ls-files | rg '(^SECURITY|SECURITY|README|package.(json|lock|json5|json$)|test|spec|playwright|vitest|jest|mocha)' || true
rg -n '"(ses|lockdown|sesify|SES)"|runCode|playwright|vitest|jest|mocha' package.json package-lock.json SECURITY README.md 2>/dev/null || true
echo "== runCode mentions in source =="
rg -n -C 3 'runCode|compartment|Compartment|lockdown|escape|sandbox|SES' . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' || trueRepository: flipcomputing/flock
Length of output: 4752
🏁 Script executed:
#!/bin/bash
set -euo firef; set -euo pipefail
echo "== flock lines 720-850 =="
awk 'NR>=720 && NR<=850 { printf "%5d\t%s\n", NR, $0 }' flock.js
echo "== target line snippets =="
python3 - <<'PY'
from pathlib import Path
text = Path("flock.js").read_text()
lines = text.splitlines()
for start,end in [(777,785),(818,820),(829,837)]:
print(f"\n-- {start}-{end} --")
for n in range(start, end+1):
if n <= len(lines):
print(f"{n}: {lines[n-1]}")
PY
echo "== test/source matches =="
for p in API.md jest.config.* rollup.config.* vite.config.* package.json SECURITY README.md; do
if [ -e "$p" ]; then echo "-- $p --"; sed -n '1,220p' "$p"; fi
done
rg -n -C 3 'runCode|Compartment|lockdown|constructor|performance\.now|SES|escape|sandbox|test' \
flock.js test spec .github scripts docs api blocks playground demo 2>/dev/null \
| sed -n '1,220p' || true
echo "== tests and config files =="
find . -maxdepth 3 -type f \( -name '*test*' -o -name '*spec*' -o -name 'jest.config.*' -o -name 'vitest.config.*' -o -name 'package.json' -o -name 'mocha.opts' -o -name 'SECURITY*' \) \
-not -path './node_modules/*' \
-not -path './dev-dist/*' \
-not -path './dist/*' \
-not -path './build/*' \
-print | sortRepository: flipcomputing/flock
Length of output: 203
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== flock lines 720-850 =="
awk 'NR>=720 && NR<=850 { printf "%5d\t%s\n", NR, $0 }' flock.js
echo "== target line snippets =="
python3 - <<'PY'
from pathlib import Path
text = Path("flock.js").read_text()
lines = text.splitlines()
for start,end in [(777,785),(818,820),(829,837)]:
print(f"\n-- {start}-{end} --")
for n in range(start, end+1):
if n <= len(lines):
print(f"{n}: {lines[n-1]}")
PY
echo "== top-level test/config file references =="
for p in API.md jest.config.* rollup.config.* vite.config.* package.json SECURITY README.md; do
if [ -e "$p" ]; then echo "-- $p --"; sed -n '1,220p' "$p"; fi
done
echo "== focused matches in tracked text files =="
python3 - <<'PY'
import subprocess
from pathlib import Path
files = subprocess.check_output(["git", "ls-files"], text=True).splitlines()
text_files = [f for f in files if Path(f).suffix in {".js",".mjs",".cjs",".json",".md"}/>]
for f in text_files:
try:
text = Path(f).read_text(errors="ignore")
except Exception:
continue
if any(p in text for p in ["runCode","Compartment","lockdown","console.log","performance.now","constructor","SES","escape","sandbox"]):
hits = [(i+1,line.rstrip()) for i,line in enumerate(text.splitlines()) if any(p in line for p in ["runCode","Compartment","lockdown","console.log","performance.now","constructor","SES","escape","sandbox"])]
print(f"\n-- {f} hits: {len(hits)} --")
for i,line in hits[:50]:
print(f"{i}: {line}")
PY
echo "== tests and config files =="
find . -maxdepth 3 -type f \( -name '*test*' -o -name '*spec*' -o -name 'jest.config.*' -o -name 'vitest.config.*' -o -name 'package.json' -o -name 'mocha.opts' -o -name 'SECURITY*' \) \
-not -path './node_modules/*' \
-not -path './dev-dist/*' \
-not -path './dist/*' \
-not -path './build/*' \
-print | sortRepository: flipcomputing/flock
Length of output: 26446
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== focused matches in tracked text files (fixed) =="
python3 - <<'PY'
import subprocess
from pathlib import Path
files = subprocess.check_output(["git", "ls-files"], text=True).splitlines()
keywords = ["runCode", "Compartment", "lockdown", "console.log", "performance.now", "constructor", "SES", "escape", "sandbox"]
text_files = [f for f in files if Path(f).suffix in {".js", ".mjs", ".cjs", ".json", ".md"}]
for f in text_files:
try:
text = Path(f).read_text(errors="ignore")
except Exception:
continue
hits = [(i+1,line.rstrip()) for i,line in enumerate(text.splitlines()) if any(k in line for k in keywords)]
if hits:
print(f"\n-- {f} hits: {len(hits)} --")
for i,line in hits[:200]:
print(f"{i}: {line}")
PY
echo "== scripts =="
git ls-files scripts | sort | while read -r f; do
echo "-- $f --"
sed -n '1,220p' "$f"
done
echo "== tests/html/script mentions =="
git ls-files | rg '(^tests/|\.html$|\.mjs$)' | sort | while read -r f; do
if rg -q 'runCode|Compartment|lockdown|flock|performance\.now|constructor|CSP|iframe|ses' "$f" 2>/dev/null; then
echo "-- $f --"
sed -n '1,240p' "$f" | grep -n -C 3 'runCode\|Compartment\|lockdown\|flock\|performance\.now\|constructor\|iframe\|ses\|CSP\|sandbox' || true
fi
doneRepository: flipcomputing/flock
Length of output: 50375
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== exact security-related matches in tracked files =="
python3 - <<'PY'
from pathlib import Path
import subprocess
files = subprocess.check_output(["git","ls-files"], text=True).splitlines()
keywords = ["escape regression", "endowment-escape", "endowment escape", "runCode", "Compartment", "lockdown", "performance.now", "constructor", "SES", "__flockWrapHostFn"]
for f in files:
try:
text = Path(f).read_text(errors="ignore")
except Exception:
continue
if any(k in text for k in keywords):
hits = [(i+1, line.rstrip()) for i, line in enumerate(text.splitlines()) if any(k in line for k in keywords)]
print(f"\n-- {f} hits: {len(hits)} --")
for n, line in hits[:200]:
print(f"{n}: {line}")
PY
echo "== tests files for exact terms =="
git ls-files tests scripts **/*.mjs **/*.js 2>/dev/null | xargs rg -n -C 2 'endowment|constructor|runtime|sandbox|escape regression|Compartment|lockdown|performance\.now|runCode|__flockWrapHostFn' || true
echo "== tests directory files =="
find tests scripts -maxdepth 3 -type f 2>/dev/null | sortRepository: flipcomputing/flock
Length of output: 50376
Add an endowment-escape regression test.
Run untrusted code that obtains a callable endowment with a computed "constructor" property. Verify that it cannot execute generated source or access the host window or document. Test the wrapped function and performance.now.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@flock.js` around lines 777 - 785, Add a regression test covering the
host-function wrapping initialized by wrapScript: run untrusted code with a
callable endowment and computed "constructor" access, and assert it cannot
execute generated source or reach the host window or document. Include checks
for both the wrapped function endowment and performance.now, preserving the
existing lockdown behavior.
Source: Coding guidelines
| // Shortcut chords (Ctrl+Z undo, ⌘S…) belong to the app/browser, not | ||
| // gameplay — without this, undo on a focused canvas walks the player | ||
| // ("z"/"q" are bound to FORWARD/LEFT for AZERTY keyboards). | ||
| if (event.ctrlKey || event.metaKey || event.altKey) return; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify the Babylon.js 8.56.0 camera modifier behavior used by this integration.
curl -fsSL https://raw.githubusercontent.com/BabylonJS/Babylon.js/8.56.0/packages/dev/core/src/Cameras/Inputs/freeCameraKeyboardMoveInput.ts | sed -n '106,158p'
curl -fsSL https://raw.githubusercontent.com/BabylonJS/Babylon.js/8.56.0/packages/dev/core/src/Cameras/Inputs/arcRotateCameraKeyboardMoveInput.ts | sed -n '103,155p'Repository: flipcomputing/flock
Length of output: 5068
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate flock.js and inspect relevant line range =="
fd -a '^flock\.js$' . | sed 's#^\./##'
FLOCK_PATH="$(fd '^flock\.js$' . | head -n 1)"
wc -l "$FLOCK_PATH"
sed -n '1300,1370p' "$FLOCK_PATH"
echo
echo "== search for Babylon keyboard/input setup in flock.js =="
rg -n "onKeyboardObservable|keyboard|camera|FreeCamera|ArcRotate|Canvas|addEventListener|addEventListener\\(" "$FLOCK_PATH" -C 3
echo
echo "== search package metadata for Babylon version/source path =="
rg -n "babylon|`@babylonjs`|Babylon|version" package.json package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null || trueRepository: flipcomputing/flock
Length of output: 50375
Filter Ctrl and Alt chords before Babylon camera inputs update _keys.
This canvas keydown returns before Babylon’s keyboard observers. Babylon.js 8.56.0 ignores Meta, but FreeCamera and ArcRotateCamera still add Ctrl- and Alt-modified mapped keys; use a focused canvas with Ctrl/Alt plus movement keys to show it. Preserve the application shortcut handling separately from the camera-input filtering.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@flock.js` around lines 1343 - 1346, Separate application shortcut handling
from Babylon camera-input filtering in the canvas keydown handler. Ensure Ctrl-
or Alt-modified keys are blocked from reaching Babylon keyboard observers and
updating camera _keys, while application/browser shortcuts continue to be
handled normally; preserve Meta behavior as intended.
| if (projectText.length > 4 * 1024 * 1024) { | ||
| throw new Error("File content is too large"); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- candidate file map ---'
ast-grep outline main/files.js --match '$_' --view concise 2>/dev/null | head -200 || true
printf '%s\n' '--- relevant source ---'
sed -n '320,420p' main/files.js
printf '%s\n' '--- response and size-limit usages ---'
rg -n -C 4 'response\.text|projectText\.length|File content is too large|Content-Length|fetch\(' main test tests 2>/dev/null || true
printf '%s\n' '--- repository test/config files ---'
git ls-files | rg '(^|/)(package\.json|.*test.*|.*spec.*|.*jest.*|.*vitest.*|.*playwright.*|.*cypress.*)' | head -200Repository: flipcomputing/flock
Length of output: 9942
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- package and API test setup ---'
cat package.json
sed -n '1,240p' scripts/run-api-tests.mjs
sed -n '1,220p' playwright.config.js
printf '%s\n' '--- source context and test references ---'
sed -n '430,480p' main/files.js
rg -n -C 3 'fetchProjectJson|project=|File content is too large|file_too_large_alert|loadWorkspace' tests scripts test-*.js .github 2>/dev/null | head -240
printf '%s\n' '--- tracked change summary ---'
git diff --stat
git status --shortRepository: flipcomputing/flock
Length of output: 11807
🏁 Script executed:
#!/bin/bash
set -eu
node - <<'JS'
const LIMIT = 4 * 1024 * 1024;
const cases = [
{ name: "ASCII exactly at limit", text: "a".repeat(LIMIT) },
{ name: "ASCII one byte over", text: "a".repeat(LIMIT + 1) },
{ name: "2-byte UTF-8 exactly 4 MiB", text: "\u00e9".repeat(LIMIT / 2) },
{ name: "2-byte UTF-8 one byte over", text: "\u00e9".repeat(LIMIT / 2 + 1) },
{ name: "4-byte UTF-8 exactly 4 MiB", text: "\u{1f600}".repeat(LIMIT / 4) },
{ name: "4-byte UTF-8 one byte over", text: "\u{1f600}".repeat(Math.floor(LIMIT / 4) + 1) },
];
for (const { name, text } of cases) {
const utf8Bytes = new TextEncoder().encode(text).byteLength;
console.log(JSON.stringify({
name,
utf16CodeUnits: text.length,
utf8Bytes,
currentGuardRejects: text.length > LIMIT,
byteLimitRejects: utf8Bytes > LIMIT,
}));
}
JSRepository: flipcomputing/flock
Length of output: 958
Enforce the size limit before buffering the response.
response.text() reads and decodes the complete response before this check runs. A large project response can consume substantial memory before the code throws. projectText.length counts UTF-16 code units, so multibyte content can exceed 4 MiB without triggering the check.
If this is a 4 MiB response limit, reject a known-large Content-Length and count bytes while reading response.body, aborting after 4 MiB. Add tests for exactly 4 MiB, 4 MiB plus one byte, and multibyte content.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@main/files.js` around lines 380 - 382, Replace the response.text() buffering
and projectText.length check with byte-based streaming in the surrounding
project response flow: reject Content-Length values over 4 MiB, read
response.body incrementally, track encoded byte counts, and abort once the limit
is exceeded while preserving successful decoding at exactly 4 MiB. Add coverage
for exactly 4 MiB, one byte over, and multibyte content.
| // Clicking anywhere on the stopped overlay (not just the play button) starts | ||
| // the scene — matches the pointer cursor shown across the whole overlay. The | ||
| // inner button's click bubbles up here, and executeCode's isExecuting guard | ||
| // makes the resulting second call a no-op. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct or remove the new comments.
The new comments do not consistently describe the current implementation. Remove provenance-only comments.
main/main.js#L237-L240: Remove the claim that a button click causes a secondexecuteCodecall.style.css#L438-L438: Remove or correct the claim that gizmos remain clickable while stopped.locale/de.js#L1072-L1072: Remove// ai.locale/es.js#L1066-L1066: Remove// ai.locale/fr.js#L1065-L1065: Remove// ai.locale/it.js#L1067-L1067: Remove// ai.locale/pl.js#L1065-L1065: Remove// ai.locale/pt.js#L1057-L1057: Remove// ai.locale/sv.js#L1047-L1047: Remove// ai.
As per coding guidelines, “Keep comments infrequent and include them only when genuinely noteworthy” and “Comments must reflect only the current state of the code.”
📍 Affects 9 files
main/main.js#L237-L240(this comment)style.css#L438-L438locale/de.js#L1072-L1072locale/es.js#L1066-L1066locale/fr.js#L1065-L1065locale/it.js#L1067-L1067locale/pl.js#L1065-L1065locale/pt.js#L1057-L1057locale/sv.js#L1047-L1047
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@main/main.js` around lines 237 - 240, Remove the inaccurate provenance
comments: in main/main.js lines 237-240 remove the claim about a button click
causing a second executeCode call; in style.css line 438 remove or correct the
claim that gizmos remain clickable while stopped; and in locale/de.js line 1072,
locale/es.js line 1066, locale/fr.js line 1065, locale/it.js line 1067,
locale/pl.js line 1065, locale/pt.js line 1057, and locale/sv.js line 1047
remove the standalone “// ai” comments. Keep only comments that accurately
describe the current implementation.
Source: Coding guidelines
Bug fixes and security updates to main release
Summary by CodeRabbit