Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 58 additions & 39 deletions bootstrap.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
# Copyright 2019-2025, Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
# SPDX-License-Identifier: GPL-3.0-or-later
# https://github.com/gnh1201/welsonjs
#
#
# Usage:
#
# Quick start (no arguments):
# irm https://catswords.blob.core.windows.net/welsonjs/bootstrap.ps1 | iex
# irm https://catswords.blob.core.windows.net/welsonjs/bootstrap.ps1 | iex -dev main
# irm https://catswords.blob.core.windows.net/welsonjs/bootstrap.ps1 | iex -dev dev
# irm https://catswords.blob.core.windows.net/welsonjs/bootstrap.ps1 | iex main
#
# Central default branch configuration for this install script.
# Update this value if the repository's default branch changes.
$defaultBranch = "master"
#
# With arguments (recommended):
# irm https://catswords.blob.core.windows.net/welsonjs/bootstrap.ps1 -OutFile bootstrap.ps1
# .\bootstrap.ps1 -dev main
# .\bootstrap.ps1 -file test.js

$defaultBranch = "master"
$ErrorActionPreference = "Stop"

function Write-Step($msg) {
Expand All @@ -29,27 +30,36 @@ function Write-Err($msg) {

try {
# Step 0: Parse arguments (iex-compatible)
# Supports:
# iex -dev main
# iex main
# iex
$branch = $defaultBranch
$fileArg = $null

for ($i = 0; $i -lt $args.Count; $i++) {
$arg = $args[$i]

if ($arg -eq "-dev" -and ($i + 1) -lt $args.Count) {
$branch = $args[$i + 1]
break
$i++
}
elseif ($arg -eq "-file" -and ($i + 1) -lt $args.Count) {
$fileArg = $args[$i + 1]
$i++
}
elseif ($arg -notmatch "^-") {
$branch = $arg
}
}

# Auto-append .js if no extension
if ($fileArg -and -not ($fileArg -match "\.")) {
$fileArg = "$fileArg.js"
}
Comment on lines +52 to +55
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Extension check matches any dot in the path, not just an extension.

$fileArg -match "\." returns true for inputs like my.app, sub.dir/test, or any path containing a dot, so .js will not be appended even when there is no real extension. Use a proper extension check instead.

Proposed fix
-    # Auto-append .js if no extension
-    if ($fileArg -and -not ($fileArg -match "\.")) {
-        $fileArg = "$fileArg.js"
-    }
+    # Auto-append .js if no extension on the file name
+    if ($fileArg -and -not [System.IO.Path]::GetExtension($fileArg)) {
+        $fileArg = "$fileArg.js"
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Auto-append .js if no extension
if ($fileArg -and -not ($fileArg -match "\.")) {
$fileArg = "$fileArg.js"
}
# Auto-append .js if no extension on the file name
if ($fileArg -and -not [System.IO.Path]::GetExtension($fileArg)) {
$fileArg = "$fileArg.js"
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bootstrap.ps1` around lines 52 - 55, The current extension check uses -match
"\." on $fileArg which triggers for any dot anywhere in the path (e.g.,
"sub.dir/file"), so change the condition to test for a real filename extension
instead; update the if that currently reads `if ($fileArg -and -not ($fileArg
-match "\."))` to use a proper extension check such as verifying
[System.IO.Path]::GetExtension($fileArg) is empty (or use a regex that matches
an extension at the end like '\.[^\\/]+$') before appending ".js" so $fileArg
only gets ".js" when it truly lacks an extension.


Write-Step "Using branch: $branch"
if ($fileArg) {
Write-Step "File argument: $fileArg"
}

# Step 1: Create a temporary working directory using a UUID
# Step 1: Create temporary workspace
Write-Step "Creating temporary workspace..."

$uuid = [guid]::NewGuid().ToString()
Expand All @@ -62,56 +72,65 @@ try {
$repo = "gnh1201/welsonjs"
$zipPath = Join-Path $tempDir "package.zip"

# Step 2: Build download URL
# Step 2: Download from branch
$downloadUrl = "https://github.com/$repo/archive/refs/heads/$branch.zip"

Write-Ok "Download URL: $downloadUrl"

# Step 3: Download the ZIP package
Write-Step "Downloading package..."

irm $downloadUrl -OutFile $zipPath

Write-Ok "Downloaded: $zipPath"

# Step 4: Extract the ZIP archive
# Step 3: Extract
Write-Step "Extracting package..."

Expand-Archive -Path $zipPath -DestinationPath $tempDir

Write-Ok "Extraction completed"

# Step 5: Locate bootstrap.bat within extracted files
Write-Step "Locating bootstrap.bat..."
if ($fileArg) {
# Step 4A: Run cscript via cmd (with visible console)
Write-Step "Locating app.js..."

$bootstrap = Get-ChildItem -Path $tempDir -Recurse -Filter "bootstrap.bat" | Select-Object -First 1
$app = Get-ChildItem -Path $tempDir -Recurse -Filter "app.js" | Select-Object -First 1

if (-not $bootstrap) {
throw "bootstrap.bat not found"
}
if (-not $app) {
throw "app.js not found"
}

Write-Ok "Found: $($bootstrap.FullName)"
Write-Ok "Found: $($app.FullName)"

# Step 6: Execute bootstrap.bat via cmd.exe for compatibility
Write-Step "Executing bootstrap..."
Write-Step "Executing via cscript (interactive)..."

$proc = Start-Process -FilePath "cmd.exe" `
-ArgumentList "/c `"$($bootstrap.FullName)`"" `
-Wait -PassThru
Start-Process "cmd.exe" `
-ArgumentList "/k cscript `"$($app.FullName)`" `"$fileArg`""
Comment on lines +103 to +104
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "bootstrap.ps1" 2>/dev/null

Repository: gnh1201/welsonjs

Length of output: 75


🏁 Script executed:

cat -n bootstrap.ps1 | head -120 | tail -40

Repository: gnh1201/welsonjs

Length of output: 1557


🏁 Script executed:

cat > /tmp/test_quoting.md << 'EOF'
# PowerShell Start-Process argument passing behavior

When using Start-Process with -ArgumentList, PowerShell passes arguments as a single command line string to the process. For cmd.exe /k:

1. Start-Process receives: "/k cscript `"C:\path with spaces\app.js`" `"arg with spaces`""
2. This becomes the full command line argument to cmd.exe
3. cmd.exe /k then processes this string with its own parsing rules

cmd.exe /k quoting rules (from cmd /?):
- cmd /k interprets the first unquoted string as the command to execute
- Everything after /k becomes the command line to execute
- If the command contains spaces and is NOT quoted, cmd will split at the first space

The issue: If $app.FullName contains spaces, the backtick-escaped quotes may not protect it properly
because cmd.exe receives the entire ArgumentList as a single parameter and applies its own quote parsing.

Proposed fix syntax check:
/k `"cscript `"`"$($app.FullName)`"`" `"`"$fileArg`"`"`"

This would result in nested quotes being passed to cmd.exe which could be problematic.
EOF
cat /tmp/test_quoting.md

Repository: gnh1201/welsonjs

Length of output: 1106


🏁 Script executed:

# Let me check what actual behavior occurs with Start-Process and cmd.exe argument passing
python3 << 'EOF'
# Analyze the proposed fix syntax
original = '/k cscript `"$($app.FullName)`" `"$fileArg`"'
proposed = '/k `"cscript `"`"$($app.FullName)`"`" `"`"$fileArg`"`"`"'

print("Original quoting:")
print(f"  {original}")
print()
print("Proposed quoting:")
print(f"  {proposed}")
print()
print("Issue analysis:")
print("- Start-Process passes -ArgumentList as a single string to cmd.exe")
print("- cmd.exe /k applies its own quote-stripping rules")
print("- Backtick escaping in PowerShell handles PowerShell parsing, not cmd.exe parsing")
print()
print("The real issue:")
print("- If $app.FullName contains spaces and cmd.exe strips/misinterprets quotes,")
print("  the command may be split incorrectly")
print("- Example: /k cscript \"C:\\Program Files\\app.js\" \"arg\"")
print("  If cmd strips outer quotes, it becomes: cscript C:\\Program Files\\app.js ...")
print("  And cmd treats 'C:\\Program' as one argument and 'Files\\app.js' as another")
EOF

Repository: gnh1201/welsonjs

Length of output: 759


🌐 Web query:

PowerShell Start-Process cmd.exe ArgumentList cmd /k quoting spaces paths

💡 Result:

To start cmd.exe using PowerShell's Start-Process cmdlet with the /k switch (to execute a command and keep the window open) while properly handling paths containing spaces in ArgumentList, use embedded double-quoting with escaped quotes in PowerShell strings. Official Microsoft documentation recommends using a single string for ArgumentList when dealing with complex quoting: Start-Process -FilePath cmd.exe -ArgumentList "/k dir "%SystemDrive%\Program Files"" This passes cmd.exe /k dir "C:\Program Files" (assuming C: drive), correctly quoting the path with spaces. The "" is PowerShell's escaped double quote. For an array: Start-Process -FilePath cmd.exe -ArgumentList "/k", "dir", ""%SystemDrive%\Program Files"" Both work per docs (results 7,9,10,17 from first search; similar in second). For a custom path with spaces, e.g., $path = "C:\My Folder\script.bat": - Single string (recommended for cmd /k): Start-Process cmd.exe -ArgumentList "/k "$path"" The resulting command line is: cmd.exe /k "C:\My Folder\script.bat" - Array: Start-Process cmd.exe -ArgumentList "/k", ""$path"" Due to a longstanding Start-Process bug (GitHub #5576, mentioned in results 1,2,11), arguments with spaces must have embedded "..." in PowerShell strings using "" . For cmd /k followed by multiple commands or complex args, enclose the entire command after /k in additional quotes to avoid cmd.exe parsing bugs (result 1): "/k "dir "C:\My Folder" & pause"" Here-strings simplify multi-line: $args = @" /k dir "$env:SystemDrive\Program Files" "@ Start-Process cmd.exe -ArgumentList $args Examples tested in recent PowerShell 7.x docs (up to 7.6 as of 2026).

Citations:


🏁 Script executed:

python3 << 'EOF'
# Verify the proposed fix syntax against PowerShell quoting rules

original = r'/k cscript `"$($app.FullName)`" `"$fileArg`"'
proposed = r'/k `"cscript `"`"$($app.FullName)`"`" `"`"$fileArg`"`"`"'
recommended = r'/k `"cscript `"$($app.FullName)`" `"$fileArg`"`"'

print("Current code (as in bootstrap.ps1):")
print(f"  -ArgumentList \"{original}\"")
print("  → cmd.exe receives: /k cscript \"...path...\" \"...arg...\"")
print()

print("Proposed fix (from review):")
print(f"  -ArgumentList \"{proposed}\"")
print("  Analysis: Multiple nested backtick escapes appear to double-escape")
print()

print("Recommended fix (per cmd /k best practices):")
print(f"  -ArgumentList \"{recommended}\"")
print("  → cmd.exe receives: /k \"cscript \"...path...\" \"...arg...\"\"")
print()

print("Key difference:")
print("  - Current: /k cscript ... (if path has spaces, cmd splits incorrectly)")
print("  - Recommended: /k \"cscript ...\" (entire command wrapped, cmd /k respects quotes)")
print()

print("Proposed fix assessment:")
print("  - Syntax is convoluted and may not escape correctly in PowerShell")
print("  - The extra backtick escapes don't follow standard PowerShell quoting patterns")
print("  - A simpler, cleaner fix would be the 'recommended' form above")
EOF

Repository: gnh1201/welsonjs

Length of output: 975


🏁 Script executed:

# Verify the proposed syntax would even be valid PowerShell
python3 << 'EOF'
import re

# Count backtick escapes in proposed fix
proposed = r'/k `"cscript `"`"$($app.FullName)`"`" `"`"$fileArg`"`"`"'

# Each `" should become a literal " in the string
# Let's trace through what PowerShell would produce:
backtick_escaped = re.findall(r'`"', proposed)
print(f"Number of `\" sequences in proposed fix: {len(backtick_escaped)}")
print(f"Positions: {[m.start() for m in re.finditer(r'`\"', proposed)]}")
print()
print("This creates a very complex quoting pattern that may be error-prone")
print("and doesn't match standard PowerShell/cmd quoting conventions")
EOF

Repository: gnh1201/welsonjs

Length of output: 306


Correct the cmd.exe /k argument quoting to handle paths with spaces.

The concern about cmd.exe /k quote-stripping is valid when $app.FullName or $fileArg contains spaces. The proper fix wraps the entire command after /k in quotes:

Proposed fix
-        Start-Process "cmd.exe" `
-            -ArgumentList "/k cscript `"$($app.FullName)`" `"$fileArg`""
+        Start-Process "cmd.exe" `
+            -ArgumentList "/k `"cscript `"$($app.FullName)`" `"$fileArg`"`""

Alternatively, Set-Location to the app directory and pass just the file name, or invoke cscript.exe directly via Start-Process without going through cmd.exe.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Start-Process "cmd.exe" `
-ArgumentList "/k cscript `"$($app.FullName)`" `"$fileArg`""
Start-Process "cmd.exe" `
-ArgumentList "/k `"cscript `"$($app.FullName)`" `"$fileArg`"`"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bootstrap.ps1` around lines 103 - 104, The current Start-Process call
invoking cmd.exe with -ArgumentList "/k cscript `"$($app.FullName)`"
`"$fileArg`"" fails for paths with spaces because cmd.exe /k strips inner
quotes; update the invocation so the entire command after /k is wrapped in a
single quoted string (e.g. "/k \"cscript \"<path>\" \"<arg>\"\"") or, better,
avoid cmd.exe entirely by calling Start-Process directly with FilePath
"cscript.exe" and Arguments built from $app.FullName and $fileArg, or change to
Set-Location to the app directory and pass only the file name; target the
Start-Process line that references cmd.exe, $app.FullName and $fileArg.


Comment on lines +103 to 105
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Unvalidated $filearg in cmd.exe 📘 Rule violation ⛨ Security

$fileArg (user-controlled via -file) is interpolated into a cmd.exe command line without
validation/escaping, so quotes/metacharacters can break argument parsing or enable command
injection. This violates the requirement to validate inputs/constraints before operating on them.
Agent Prompt
## Issue description
`$fileArg` is user-controlled and is embedded into a `cmd.exe` command line without strict validation/escaping, which can lead to command-line injection or unexpected parsing.

## Issue Context
`-file` is parsed from `$args` and later used to build `Start-Process "cmd.exe" -ArgumentList ...`.

## Fix Focus Areas
- bootstrap.ps1[89-106]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +103 to 105
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Wrong cscript bitness 🐞 Bug ≡ Correctness

In -file mode, bootstrap.ps1 launches cscript via cmd.exe without forcing the 32-bit
SysWOW64\cscript.exe that bootstrap.bat uses, which can break scripts that depend on the 32-bit
WelsonJS.Toolkit COM registration. This can cause runtime failures (e.g.,
CreateObject('WelsonJS.Toolkit')) in the launched session even though bootstrap.ps1 reports it
started successfully.
Agent Prompt
### Issue description
`-file` mode launches `cscript` via `cmd.exe` without pinning bitness. On 64-bit Windows this commonly resolves to 64-bit `cscript.exe`, which is incompatible with the x86 WelsonJS.Toolkit COM registration performed by `bootstrap.bat`.

### Issue Context
- `bootstrap.bat` registers an x86 toolkit DLL and then runs `%SystemRoot%\SysWOW64\cscript.exe`.
- User scripts and libraries may call `CreateObject("WelsonJS.Toolkit")`.

### Fix Focus Areas
- bootstrap.ps1[89-107]
- bootstrap.bat[8-13]
- bootstrap.bat[44-50]

### Suggested change
- In `-file` mode, launch `"$env:SystemRoot\SysWOW64\cscript.exe"` explicitly (or otherwise ensure 32-bit host) instead of relying on `cscript` from PATH.
- Consider also setting `-WorkingDirectory` to the extracted repo root (where `app.js` resides) for consistency with bootstrap.bat’s `pushd %~dp0` behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

if ($proc.ExitCode -ne 0) {
throw "bootstrap failed with exit code $($proc.ExitCode)"
Write-Ok "cscript launched (interactive console)"
}
else {
# Step 4B: Default bootstrap (non-blocking)
Write-Step "Locating bootstrap.bat..."

$bootstrap = Get-ChildItem -Path $tempDir -Recurse -Filter "bootstrap.bat" | Select-Object -First 1

if (-not $bootstrap) {
throw "bootstrap.bat not found"
}

Write-Ok "Bootstrap executed successfully"
Write-Ok "Found: $($bootstrap.FullName)"

Write-Step "Executing bootstrap (non-blocking)..."

Start-Process "cmd.exe" `
-ArgumentList "/c `"$($bootstrap.FullName)`""

Write-Ok "Bootstrap launched"
Comment on lines +120 to +125
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Fire-and-forget start-process call 📘 Rule violation ☼ Reliability

The script launches bootstrap.bat with Start-Process without -Wait/-PassThru, so failures
and non-zero exit codes are not observed or reported. This matches the checklist’s prohibition on
unobserved fire-and-forget operations where faults can be lost.
Agent Prompt
## Issue description
`Start-Process` is used in a fire-and-forget way, which prevents observing failures (exit code) and reporting them.

## Issue Context
The default bootstrap flow used to be blocking and could validate success; now it launches and immediately reports "Bootstrap launched".

## Fix Focus Areas
- bootstrap.ps1[120-126]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

}

# Step 7: Final message
Write-Host ""
Write-Host "WelsonJS installation completed!" -ForegroundColor Green
Write-Host "WelsonJS execution started!" -ForegroundColor Green
Write-Host ""

}
catch {
Write-Err $_
exit 1
}
}
Loading