-
Notifications
You must be signed in to change notification settings - Fork 60
script-support #1230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
script-support #1230
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,8 +31,6 @@ RUN chmod +x docker-init.sh 2>/dev/null || true | |
| WORKDIR /usr/src/app/frontend | ||
| RUN bun run build | ||
|
|
||
| # Set the environment as production | ||
| ENV NODE_ENV=production | ||
|
|
||
| # Install required tools, canvas dependencies, and vespa CLI | ||
| USER root | ||
|
|
@@ -50,13 +48,28 @@ RUN apt-get update && apt-get install -y \ | |
| libpixman-1-dev \ | ||
| libfontconfig1-dev \ | ||
| libfreetype6-dev \ | ||
| python3 python3-pip nodejs npm r-base-core r-base-dev \ | ||
| build-essential libcurl4-openssl-dev libssl-dev libxml2-dev \ | ||
| jq bubblewrap \ | ||
|
Comment on lines
+51
to
+53
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setuid This line: RUN chmod u+s $(which bwrap)turns
That means a bug in your script‑executor wrapper (e.g., insufficient validation of paths/flags passed to Recommendations:
Also applies to: 94-94 🤖 Prompt for AI AgentsLanguage runtime setup works, but npm global install is non‑deterministic. The overall pattern (install Python/Node/R + requirements, create RUN npm install -g $(cat /usr/src/app/js-requirements.json | jq -r '.dependencies | keys[]')This installs only package names (no versions), so each build may pick different axios (and any future packages) depending on the current npm registry state, even though To make builds deterministic and align with -RUN npm install -g $(cat /usr/src/app/js-requirements.json | jq -r '.dependencies | keys[]')
+RUN npm install -g $(jq -r '.dependencies | to_entries[] | "\(.key)@\(.value)"' /usr/src/app/js-requirements.json)You may also want to revisit whether you need global installs at all versus a dedicated tools directory on Also applies to: 63-71, 88-89 🤖 Prompt for AI Agents |
||
| && wget https://github.com/vespa-engine/vespa/releases/download/v8.453.24/vespa-cli_8.453.24_linux_amd64.tar.gz \ | ||
| && tar -xzf vespa-cli_8.453.24_linux_amd64.tar.gz \ | ||
| && mv vespa-cli_8.453.24_linux_amd64/bin/vespa /usr/local/bin/ \ | ||
| && rm -rf vespa-cli_8.453.24_linux_amd64 vespa-cli_8.453.24_linux_amd64.tar.gz \ | ||
| && apt-get clean && rm -rf /var/lib/apt/lists/* | ||
|
|
||
|
|
||
|
|
||
| # Copy and install language requirements | ||
| COPY requirements.txt /usr/src/app/ | ||
| COPY js-requirements.json /usr/src/app/ | ||
| COPY requirements.R /usr/src/app/ | ||
|
|
||
| # Install language packages | ||
| RUN python3 -m pip install --break-system-packages -r /usr/src/app/requirements.txt | ||
| RUN npm install -g $(cat /usr/src/app/js-requirements.json | jq -r '.dependencies | keys[]') | ||
| RUN Rscript /usr/src/app/requirements.R | ||
|
Comment on lines
+68
to
+70
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Each |
||
|
|
||
|
|
||
| # Copy data restoration script and make it executable | ||
| #COPY deployment/restore-data.sh /usr/src/app/deployment/restore-data.sh | ||
| #RUN chmod +x /usr/src/app/deployment/restore-data.sh | ||
|
|
@@ -66,15 +79,19 @@ RUN apt-get update && apt-get install -y \ | |
|
|
||
| # Note: Application ports are exposed below | ||
|
|
||
| # Set the environment as production | ||
| ENV NODE_ENV=production | ||
|
|
||
| WORKDIR /usr/src/app/server | ||
|
|
||
| # Create runtime directories and set ownership for bun user | ||
| RUN mkdir -p downloads vespa-data vespa-logs uploads migrations && \ | ||
| chown bun:bun downloads vespa-data vespa-logs uploads migrations | ||
| RUN mkdir -p downloads vespa-data vespa-logs uploads migrations script_executor_utils && \ | ||
| chown bun:bun downloads vespa-data vespa-logs uploads migrations script_executor_utils | ||
|
|
||
| # Copy and setup startup script | ||
| COPY --chown=bun:bun start.sh /usr/src/app/start.sh | ||
| RUN chmod +x /usr/src/app/start.sh | ||
| RUN chmod u+s $(which bwrap) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting the |
||
|
|
||
| USER bun | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,7 +23,7 @@ services: | |
| dockerfile: Dockerfile | ||
| container_name: xyne-app | ||
| user: "${DOCKER_UID}:${DOCKER_GID}" | ||
| # Ports removed - NGINX handles external access | ||
| privileged: true | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Running a container with cap_add:
- SYS_ADMIN
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Granting full
a compromise of the script executor or an argument‑validation bug in the bubblewrap wrapper can turn into near‑host‑level access. Unless you have a very specific, documented requirement, it would be much safer to:
If this is only for a local “power user” build flow, please clearly mark it as such and keep your production/staging compose files non‑privileged. |
||
| # ports: | ||
| # - "${PORT:-3000}:${PORT:-3000}" | ||
| # - "3001:3001" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -51,7 +51,7 @@ http { | |
| add_header Cross-Origin-Embedder-Policy "require-corp" always; | ||
| add_header Cross-Origin-Opener-Policy "same-origin" always; | ||
| add_header Cross-Origin-Resource-Policy "same-origin" always; | ||
| add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https: wss: ws:; frame-ancestors 'none';" always; | ||
| add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; worker-src 'self' blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https: wss: ws:; frame-ancestors 'none';" always; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainAdding third-party CDN to CSP increases supply chain attack risk. Allowing
Note: The CSP already includes Would you like me to generate a script to verify which Monaco Editor resources are being loaded from jsdelivr, or help create a local hosting alternative? I'll verify the review comment by examining the actual code changes and context. Let me start with shell scripts to inspect the nginx.conf file and related Monaco Editor integration. 🏁 Script executed: #!/bin/bash
# Examine the nginx.conf file around line 54
echo "=== nginx.conf content around line 54 ==="
sed -n '50,60p' deployment/portable/nginx.conf
echo -e "\n=== Full CSP header (if spanning multiple lines) ==="
sed -n '54p' deployment/portable/nginx.conf | head -c 500
echo -e "\n\n=== Search for Monaco Editor references ==="
rg -i "monaco" --type-list | head -5
rg -i "monaco" -n -C 3 2>/dev/null || echo "No Monaco references found"
echo -e "\n=== Search for jsdelivr references in codebase ==="
rg "jsdelivr" -n -C 2 2>/dev/null || echo "No jsdelivr references found"
echo -e "\n=== Check for web worker configuration ==="
rg "worker-src" -n -C 2 deployment/portable/nginx.confLength of output: 11425 🏁 Script executed: #!/bin/bash
# Check HTML/template files for Monaco Editor loading
echo "=== Search for script tags loading Monaco or CDN resources ==="
find . -type f \( -name "*.html" -o -name "*.htm" -o -name "*.hjs" -o -name "*.ejs" \) -exec grep -l "monaco\|cdn.jsdelivr" {} \; 2>/dev/null | head -10
echo -e "\n=== Check HTML files for resource loading patterns ==="
rg "<script.*src" -n --type=html 2>/dev/null | grep -E "(monaco|jsdelivr|cdn)" | head -20Length of output: 118 🌐 Web query: 💡 Result: Summary — jsDelivr CDN supply‑chain risks observed 2024–2025 Key incidents and findings
Primary attack vectors and vulnerabilities
Practical mitigations (concise)
If you want, I can:
Sources Citations:
I need to verify how Monaco Editor loads its assets to determine if the SRI recommendations are feasible. 🏁 Script executed: #!/bin/bash
# Check if Monaco Editor loads from CDN or is bundled
echo "=== Check package.json Monaco configuration ==="
jq '.dependencies | keys[] | select(. | contains("monaco"))' frontend/package.json
echo -e "\n=== Check CodeEditor.tsx for loader configuration or CDN references ==="
grep -n -i "cdn\|jsdelivr\|loader\|src=" frontend/src/components/CodeEditor.tsx | head -20
echo -e "\n=== Check public directory for Monaco files ==="
find . -name "*monaco*" -type f 2>/dev/null | grep -v node_modules | head -20
echo -e "\n=== Search for webpack/build config that might bundle Monaco ==="
find . -name "webpack.config.*" -o -name "vite.config.*" -o -name "tsconfig.json" 2>/dev/null | head -5
rg "monaco" webpack.config.* vite.config.* 2>/dev/null || echo "No Monaco refs in build config"
echo -e "\n=== Check if @monaco-editor/react uses default loader or custom CDN ==="
grep -r "monacoEditorModule\|getEditorModule\|loader" frontend/src/components/CodeEditor.tsx 2>/dev/null | head -10Length of output: 581 🌐 Web query: 💡 Result: Short answer: you can use SRI when loading @monaco-editor/react from a CDN, but you must use fixed, single-file (versioned) URLs and provide matching integrity hashes for every cross‑origin resource; because Monaco also loads multiple worker and asset files at runtime, in practice it's usually easier to self‑host the Monaco assets (or pin & SRI every file) and add crossorigin="anonymous". [1][2][3] What to do (concise steps)
Useful references
If you want, tell me:
Sources: CDN supply chain risk in CSP requires alternative mitigation approach. Adding SRI hashes are not practical here. Instead, consider:
🤖 Prompt for AI Agents |
||
|
|
||
| # Rate Limiting Zones | ||
| limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,195 @@ | ||
| import React, { useRef, useEffect } from "react" | ||
| import { Editor } from "@monaco-editor/react" | ||
| import { X, Save } from "lucide-react" | ||
| import { Button } from "@/components/ui/button" | ||
| import { editor } from "monaco-editor" | ||
|
|
||
| interface CodeEditorProps { | ||
| isOpen: boolean | ||
| onClose: () => void | ||
| language: string | ||
| initialValue: string | ||
| onChange: (value: string) => void | ||
| onSave: (value: string) => void | ||
| theme?: 'light' | 'dark' // Add optional theme prop | ||
| } | ||
|
|
||
| export const CodeEditor: React.FC<CodeEditorProps> = ({ | ||
| isOpen, | ||
| onClose, | ||
| language, | ||
| initialValue, | ||
| onChange, | ||
| onSave, | ||
| theme, | ||
| }) => { | ||
| const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null) | ||
| const [currentValue, setCurrentValue] = React.useState(initialValue) | ||
| const [isMonacoLoading, setIsMonacoLoading] = React.useState(true) | ||
| const [monacoError, setMonacoError] = React.useState<string | null>(null) | ||
|
|
||
| // Simple initialization without custom loader configuration | ||
| useEffect(() => { | ||
| if (isOpen) { | ||
| // Set loading to false immediately - let Monaco handle its own loading | ||
| const timer = setTimeout(() => { | ||
| setIsMonacoLoading(false) | ||
| }, 1000) | ||
|
|
||
| return () => clearTimeout(timer) | ||
| } | ||
| }, [isOpen]) | ||
|
Comment on lines
+32
to
+41
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
|
|
||
| // Use parent theme if provided, otherwise fall back to auto-detection | ||
| const monacoTheme = theme === 'dark' ? 'vs-dark' : theme === 'light' ? 'vs' : 'vs' | ||
|
|
||
| // Update current value when initialValue changes | ||
| useEffect(() => { | ||
| setCurrentValue(initialValue) | ||
| }, [initialValue]) | ||
|
|
||
| // Handle editor mount | ||
| const handleEditorDidMount = (editor: editor.IStandaloneCodeEditor, monaco: typeof import('monaco-editor')) => { | ||
| editorRef.current = editor | ||
| setIsMonacoLoading(false) // Editor successfully mounted | ||
| setMonacoError(null) | ||
|
|
||
| // Fix for Chrome single space issue | ||
| editor.addCommand(monaco.KeyCode.Space, () => { | ||
| const position = editor.getPosition() | ||
| if (position) { | ||
| editor.trigger('keyboard', 'type', { text: ' ' }) | ||
| } | ||
| return true // Prevent default space handling | ||
| }) | ||
|
|
||
| // Focus the editor after a brief delay to ensure proper initialization | ||
| setTimeout(() => { | ||
| editor.focus() | ||
| // Set cursor to end of content if there's initial content | ||
| if (initialValue) { | ||
| const model = editor.getModel() | ||
| if (model) { | ||
| const lineCount = model.getLineCount() | ||
| const lastLineLength = model.getLineLength(lineCount) | ||
| editor.setPosition({ lineNumber: lineCount, column: lastLineLength + 1 }) | ||
| } | ||
| } | ||
| }, 100) | ||
| } | ||
|
|
||
| // Handle value change | ||
| const handleEditorChange = (value: string | undefined) => { | ||
| const newValue = value || "" | ||
| setCurrentValue(newValue) | ||
| onChange(newValue) | ||
| } | ||
|
|
||
| // Handle save | ||
| const handleSave = () => { | ||
| onSave(currentValue) | ||
| onClose() | ||
| } | ||
|
|
||
|
|
||
| if (!isOpen) return null | ||
|
|
||
| return ( | ||
| <div className="fixed inset-0 bg-black/50 z-[100] flex items-center justify-center"> | ||
| <div | ||
| className="bg-white dark:bg-gray-900 rounded-lg shadow-xl w-[90vw] h-[80vh] flex flex-col overflow-hidden" | ||
| // onKeyDown={handleKeyDown} | ||
| // tabIndex={-1} | ||
| > | ||
| {/* Header */} | ||
| <div className="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700"> | ||
| <div className="flex items-center gap-3"> | ||
| <h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100"> | ||
| Code Editor | ||
| </h2> | ||
| <span className="px-2 py-1 text-xs bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded capitalize"> | ||
| {language} | ||
| </span> | ||
| </div> | ||
| <div className="flex items-center gap-2"> | ||
| <button | ||
| onClick={onClose} | ||
| className="flex items-center justify-center w-8 h-8 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-md transition-colors" | ||
| > | ||
| <X className="w-5 h-5 text-gray-600 dark:text-gray-400" /> | ||
| </button> | ||
| </div> | ||
| </div> | ||
|
|
||
| {/* Editor */} | ||
| <div className="flex-1 overflow-hidden"> | ||
| {isMonacoLoading ? ( | ||
| <div className="flex items-center justify-center h-full"> | ||
| <div className="text-center"> | ||
| <div className="animate-spin w-8 h-8 border-2 border-gray-300 border-t-blue-600 rounded-full mx-auto mb-4"></div> | ||
| <p className="text-gray-600 dark:text-gray-400">Loading Monaco Editor...</p> | ||
| </div> | ||
| </div> | ||
| ) : monacoError ? ( | ||
| <div className="flex items-center justify-center h-full"> | ||
| <div className="text-center"> | ||
| <p className="text-red-500 mb-4">{monacoError}</p> | ||
| <textarea | ||
| className="w-full h-64 p-3 border border-gray-300 dark:border-gray-600 rounded-md bg-gray-50 dark:bg-gray-900 text-gray-800 dark:text-gray-200 font-mono text-sm resize-none" | ||
| value={currentValue} | ||
| onChange={(e) => handleEditorChange(e.target.value)} | ||
| placeholder={`Enter your ${language} code here...`} | ||
| /> | ||
| </div> | ||
| </div> | ||
| ) : ( | ||
| <Editor | ||
| height="100%" | ||
| language={language} | ||
| value={currentValue} | ||
| onChange={handleEditorChange} | ||
| onMount={handleEditorDidMount} | ||
| loading={ | ||
| <div className="flex items-center justify-center h-full"> | ||
| <div className="text-center"> | ||
| <div className="animate-spin w-8 h-8 border-2 border-gray-300 border-t-blue-600 rounded-full mx-auto mb-4"></div> | ||
| <p className="text-gray-600 dark:text-gray-400">Loading Monaco Editor...</p> | ||
| </div> | ||
| </div> | ||
| } | ||
| theme={monacoTheme} | ||
| options={{ | ||
| fontSize: 14, | ||
| minimap: { enabled: true }, | ||
| scrollBeyondLastLine: false, | ||
| automaticLayout: true, | ||
| lineNumbers: "on", | ||
| folding: true, | ||
| cursorSmoothCaretAnimation: "off", | ||
| selectOnLineNumbers: true, | ||
| insertSpaces: true, | ||
| wordWrap: "on", | ||
| contextmenu: true, | ||
| mouseWheelZoom: true, | ||
| smoothScrolling: true, | ||
| cursorBlinking: "blink" | ||
| }} | ||
| /> | ||
| )} | ||
| </div> | ||
|
|
||
| {/* Footer */} | ||
| <div className="px-6 py-3 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 flex items-center justify-end"> | ||
| <Button | ||
| onClick={handleSave} | ||
| className="bg-blue-600 hover:bg-blue-700 text-white text-sm" | ||
| size="sm" | ||
| > | ||
| <Save className="w-4 h-4 mr-2" /> | ||
| Save | ||
| </Button> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
ENV NODE_ENV=productionis set after the frontend build (RUN bun run build). The frontend build process relies onNODE_ENV=productionto create an optimized production build. Without it, the resulting frontend assets will be larger and less performant. This should be set before the build command is run.