fix(claude): apply shell rules and platform sandbox
This commit is contained in:
1 parent
3973ed48f3
commit
060d3724d6
3 files changed
+37
-13
No files matched your search
@@ -4,12 +4,7 @@
|
|||||||
"allow": [
|
"allow": [
|
||||||
"Agent"
|
"Agent"
|
||||||
],
|
],
|
||||||
"deny": [
|
"deny": __CLAUDE_DENY_RULES__
|
||||||
"Bash(git reset --hard*)",
|
|
||||||
"Bash(git clean*)",
|
|
||||||
"Bash(rm -rf*)",
|
|
||||||
"Bash(Remove-Item -Recurse*)"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"sandbox": __CLAUDE_SANDBOX__,
|
"sandbox": __CLAUDE_SANDBOX__,
|
||||||
"env": {
|
"env": {
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ $ErrorActionPreference = 'Stop'
|
|||||||
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
|
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
|
||||||
$shared = Join-Path $root 'shared'
|
$shared = Join-Path $root 'shared'
|
||||||
$output = Join-Path $root 'generated'
|
$output = Join-Path $root 'generated'
|
||||||
|
$sandboxSupported = [Environment]::OSVersion.Platform -eq [PlatformID]::Unix
|
||||||
|
if ($sandboxSupported) {
|
||||||
|
$kernel = (& uname -r 2>$null | Out-String).Trim()
|
||||||
|
if ($kernel -match '(?i)microsoft') { $sandboxSupported = $kernel -match '(?i)microsoft-standard-WSL2' }
|
||||||
|
}
|
||||||
|
$claudeSandbox = if ($sandboxSupported) { '{"enabled": true, "allowUnsandboxedCommands": false, "failIfUnavailable": true}' } else { '{"enabled": false}' }
|
||||||
$pluginManifest = Join-Path $root 'adapters/plugins.tsv'
|
$pluginManifest = Join-Path $root 'adapters/plugins.tsv'
|
||||||
$capabilityManifest = Join-Path $root 'adapters/claude/capabilities.tsv'
|
$capabilityManifest = Join-Path $root 'adapters/claude/capabilities.tsv'
|
||||||
|
|
||||||
@@ -173,10 +179,15 @@ foreach ($shell in @('powershell','bash')) {
|
|||||||
$script = if ($shell -eq 'powershell') { 'flashbang.ps1' } else { 'flashbang.sh' }
|
$script = if ($shell -eq 'powershell') { 'flashbang.ps1' } else { 'flashbang.sh' }
|
||||||
$statusLineScript = if ($shell -eq 'powershell') { 'statusline.ps1' } else { 'statusline.sh' }
|
$statusLineScript = if ($shell -eq 'powershell') { 'statusline.ps1' } else { 'statusline.sh' }
|
||||||
$content = Get-Content -LiteralPath $path -Raw
|
$content = Get-Content -LiteralPath $path -Raw
|
||||||
$sandbox = if ($shell -eq 'powershell') { '{"enabled": false}' } else { '{"enabled": true, "allowUnsandboxedCommands": false, "failIfUnavailable": true}' }
|
$denyRules = if ($shell -eq 'powershell') {
|
||||||
|
@('PowerShell(git reset --hard*)','PowerShell(git clean*)','PowerShell(Remove-Item *-Recurse*)')
|
||||||
|
} else {
|
||||||
|
@('Bash(git reset --hard*)','Bash(git clean*)','Bash(rm -rf*)')
|
||||||
|
}
|
||||||
|
$denyRulesJson = ConvertTo-Json -InputObject $denyRules -Compress
|
||||||
$compactScript = if ($shell -eq 'powershell') { 'Record-Compact.ps1' } else { 'record-compact.sh' }
|
$compactScript = if ($shell -eq 'powershell') { 'Record-Compact.ps1' } else { 'record-compact.sh' }
|
||||||
$pointerScript = if ($shell -eq 'powershell') { 'Show-SessionStatePointer.ps1' } else { 'show-session-state-pointer.sh' }
|
$pointerScript = if ($shell -eq 'powershell') { 'Show-SessionStatePointer.ps1' } else { 'show-session-state-pointer.sh' }
|
||||||
$content = $content.Replace('__HOOK_COMMAND__', $command).Replace('__POWERSHELL_HOOK_COMMAND__', $command).Replace('__HOOK_SCRIPT__', $script).Replace('__POWERSHELL_HOOK_SCRIPT__', $script).Replace('__COMPACT_SCRIPT__', $compactScript).Replace('__SESSION_POINTER_SCRIPT__', $pointerScript).Replace('__STATUSLINE_COMMAND__', $command).Replace('__STATUSLINE_SCRIPT__', $statusLineScript).Replace('__CLAUDE_SANDBOX__', $sandbox)
|
$content = $content.Replace('__HOOK_COMMAND__', $command).Replace('__POWERSHELL_HOOK_COMMAND__', $command).Replace('__HOOK_SCRIPT__', $script).Replace('__POWERSHELL_HOOK_SCRIPT__', $script).Replace('__COMPACT_SCRIPT__', $compactScript).Replace('__SESSION_POINTER_SCRIPT__', $pointerScript).Replace('__STATUSLINE_COMMAND__', $command).Replace('__STATUSLINE_SCRIPT__', $statusLineScript).Replace('__CLAUDE_SANDBOX__', $claudeSandbox).Replace('__CLAUDE_DENY_RULES__', $denyRulesJson)
|
||||||
Set-Content -LiteralPath $path -Value $content -Encoding UTF8
|
Set-Content -LiteralPath $path -Value $content -Encoding UTF8
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +203,7 @@ $leftoverPlaceholders = @(Get-ChildItem $output -File -Recurse | ForEach-Object
|
|||||||
# expected to remain in generated output. -cmatch keeps this case-sensitive so Python
|
# expected to remain in generated output. -cmatch keeps this case-sensitive so Python
|
||||||
# dunder names (__main__, __name__) in flashbang.sh are not mistaken for placeholders.
|
# dunder names (__main__, __name__) in flashbang.sh are not mistaken for placeholders.
|
||||||
$content = (Get-Content -LiteralPath $_.FullName -Raw) -replace '__AI_CONFIG_ROOT__|__POWERSHELL_COMMAND__|__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__', ''
|
$content = (Get-Content -LiteralPath $_.FullName -Raw) -replace '__AI_CONFIG_ROOT__|__POWERSHELL_COMMAND__|__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__', ''
|
||||||
if ($content -cmatch '__[A-Z0-9_]+__') { $_.FullName }
|
if ($content -cmatch '__[A-Z0-9_]*[A-Z0-9][A-Z0-9_]*__') { $_.FullName }
|
||||||
})
|
})
|
||||||
if ($leftoverPlaceholders.Count) { throw "Unresolved template placeholders in: $($leftoverPlaceholders -join ', ')" }
|
if ($leftoverPlaceholders.Count) { throw "Unresolved template placeholders in: $($leftoverPlaceholders -join ', ')" }
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,20 @@ done
|
|||||||
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
|
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
|
||||||
shared="$root/shared"
|
shared="$root/shared"
|
||||||
output="$root/generated"
|
output="$root/generated"
|
||||||
|
sandbox_supported=false
|
||||||
|
platform=$(uname -s 2>/dev/null || true)
|
||||||
|
case "$platform" in
|
||||||
|
Darwin) sandbox_supported=true ;;
|
||||||
|
Linux)
|
||||||
|
kernel=$(uname -r 2>/dev/null || true)
|
||||||
|
case "$kernel" in
|
||||||
|
*microsoft*) [[ "$kernel" == *microsoft-standard-WSL2* ]] && sandbox_supported=true ;;
|
||||||
|
*) sandbox_supported=true ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
sandbox='{"enabled": false}'
|
||||||
|
[ "$sandbox_supported" != true ] || sandbox='{"enabled": true, "allowUnsandboxedCommands": false, "failIfUnavailable": true}'
|
||||||
plugin_manifest="$root/adapters/plugins.tsv"
|
plugin_manifest="$root/adapters/plugins.tsv"
|
||||||
capability_manifest="$root/adapters/claude/capabilities.tsv"
|
capability_manifest="$root/adapters/claude/capabilities.tsv"
|
||||||
|
|
||||||
@@ -158,8 +172,11 @@ for client in codex claude; do
|
|||||||
fi
|
fi
|
||||||
path="$output/$client-$shell/$file"
|
path="$output/$client-$shell/$file"
|
||||||
content=$(<"$path")
|
content=$(<"$path")
|
||||||
sandbox='{"enabled": true, "allowUnsandboxedCommands": false, "failIfUnavailable": true}'
|
if [ "$shell" = powershell ]; then
|
||||||
[ "$shell" != powershell ] || sandbox='{"enabled": false}'
|
deny_rules='["PowerShell(git reset --hard*)","PowerShell(git clean*)","PowerShell(Remove-Item *-Recurse*)"]'
|
||||||
|
else
|
||||||
|
deny_rules='["Bash(git reset --hard*)","Bash(git clean*)","Bash(rm -rf*)"]'
|
||||||
|
fi
|
||||||
content=${content//__HOOK_COMMAND__/$command}
|
content=${content//__HOOK_COMMAND__/$command}
|
||||||
content=${content//__POWERSHELL_HOOK_COMMAND__/$command}
|
content=${content//__POWERSHELL_HOOK_COMMAND__/$command}
|
||||||
content=${content//__HOOK_SCRIPT__/$script}
|
content=${content//__HOOK_SCRIPT__/$script}
|
||||||
@@ -169,6 +186,7 @@ for client in codex claude; do
|
|||||||
content=${content//__STATUSLINE_COMMAND__/$command}
|
content=${content//__STATUSLINE_COMMAND__/$command}
|
||||||
content=${content//__STATUSLINE_SCRIPT__/$statusline_script}
|
content=${content//__STATUSLINE_SCRIPT__/$statusline_script}
|
||||||
content=${content//__CLAUDE_SANDBOX__/$sandbox}
|
content=${content//__CLAUDE_SANDBOX__/$sandbox}
|
||||||
|
content=${content//__CLAUDE_DENY_RULES__/$deny_rules}
|
||||||
printf '%s\n' "$content" > "$path"
|
printf '%s\n' "$content" > "$path"
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -191,9 +209,9 @@ done
|
|||||||
# __AI_CONFIG_ROOT__ is resolved at install time, once the destination is known; it is
|
# __AI_CONFIG_ROOT__ is resolved at install time, once the destination is known; it is
|
||||||
# expected to remain in generated output, so it is excluded from the leftover check. A
|
# expected to remain in generated output, so it is excluded from the leftover check. A
|
||||||
# single tree-wide grep (rather than one process per file) keeps this fast.
|
# single tree-wide grep (rather than one process per file) keeps this fast.
|
||||||
leftover_tokens=$(grep -RohE '__[A-Z0-9_]+__' "$output" 2>/dev/null | sort -u | grep -Ev '^(__AI_CONFIG_ROOT__|__POWERSHELL_COMMAND__|__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__)$' || true)
|
leftover_tokens=$(grep -RohE '__[A-Z0-9_]*[A-Z0-9][A-Z0-9_]*__' "$output" 2>/dev/null | sort -u | grep -Ev '^(__AI_CONFIG_ROOT__|__POWERSHELL_COMMAND__|__CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY__)$' || true)
|
||||||
if [ -n "$leftover_tokens" ]; then
|
if [ -n "$leftover_tokens" ]; then
|
||||||
offending_files=$(grep -RlE '__[A-Z0-9_]+__' "$output" 2>/dev/null | tr '\n' ' ')
|
offending_files=$(grep -RlE '__[A-Z0-9_]*[A-Z0-9][A-Z0-9_]*__' "$output" 2>/dev/null | tr '\n' ' ')
|
||||||
printf 'Unresolved template placeholders (%s) in: %s\n' "$(printf '%s' "$leftover_tokens" | tr '\n' ' ')" "$offending_files" >&2
|
printf 'Unresolved template placeholders (%s) in: %s\n' "$(printf '%s' "$leftover_tokens" | tr '\n' ' ')" "$offending_files" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in new issue
Block a user