Files
Marius CiepluchandClaude Opus 5 adbb824eac feat(ops): a sourceable wrapper so docker is nobody's problem
source ops/shell/ousast.sh     # bash / zsh
    . ops\shell\ousast.ps1         # powershell

    ousast scan .
    ousast scan src/api

The container becomes an implementation detail. The engine is a JVM and ~2 GB
of Joern, and a contributor evaluating this tool should not have to install
either to try it -- what they get is a command.

Path rewriting is what makes it feel local: arguments under the working
directory are mapped to their mounted equivalents, so `src/api` means what the
user expects. Anything outside the mount is passed through unchanged WITH A
WARNING rather than silently rewritten into a path the container cannot see --
a wrong path that looks like it worked is worse than one that complains.

A native install wins when it is present. Someone who installed Joern
deliberately should not be quietly routed through a container, so the wrapper
uses a local joern-parse and venv when both exist; OUSAST_PREFER_NATIVE=0
forces the container. Verified end to end from an unrelated directory.

The image builds itself on first use and says why it is pausing. A first run
that prints a wall of build output and then works is worse than one that
explains itself.

Defaults stay conservative: the working directory mounts READ-ONLY, findings go
to ./.ousast as the only writable mount, and the network is off unless
`ousast-with-judge` asks for it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
2026-09-08 19:37:58 +02:00

53 lines
2.2 KiB
PowerShell

# OpenUltraSAST as a local command. Dot-source this from your PowerShell profile:
#
# . C:\path\to\OpenUltraSAST\ops\shell\ousast.ps1
#
# Then use it from any directory:
#
# ousast scan .
# ousast scan src\api
#
# Docker is an implementation detail. Your working directory is mounted READ-ONLY and findings are written
# to .\.ousast, the only writable mount.
$script:OusastHome = if ($env:OUSAST_HOME) { $env:OUSAST_HOME }
else { Split-Path -Parent (Split-Path -Parent $PSScriptRoot) }
function ousast {
$compose = Join-Path $script:OusastHome 'docker-compose.yml'
if (-not (Test-Path $compose)) {
Write-Error "ousast: cannot find $compose (set OUSAST_HOME to the checkout)"; return
}
if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
Write-Error "ousast: docker is not installed"; return
}
$version = if ($env:OUSAST_VERSION) { $env:OUSAST_VERSION } else { 'dev' }
docker image inspect "openultrasast:$version" *> $null
if ($LASTEXITCODE -ne 0) {
Write-Host "ousast: building the analysis image once (~2 GB of engine; later runs are instant)"
Push-Location $script:OusastHome; docker compose build; Pop-Location
}
# Rewrite paths under the current directory to their mounted equivalent; leave anything outside alone
# and say so, rather than silently rewriting it into a path the container cannot see.
$cwd = (Get-Location).Path
$mapped = foreach ($a in $args) {
if (Test-Path $a) {
$abs = (Resolve-Path $a).Path
if ($abs -eq $cwd) { '/target' }
elseif ($abs.StartsWith($cwd)) { '/target' + $abs.Substring($cwd.Length).Replace('\', '/') }
else { Write-Warning "ousast: $a is outside $cwd and is not mounted"; $a }
} else { $a }
}
New-Item -ItemType Directory -Force -Path (Join-Path $cwd '.ousast') | Out-Null
$env:TARGET = $cwd
$env:OUSAST_REPORTS = Join-Path $cwd '.ousast'
if (-not $env:OUSAST_NETWORK) { $env:OUSAST_NETWORK = 'none' }
docker compose -f $compose run --rm ousast @mapped
}
# The LLM judge needs network and a key; opt in explicitly.
function ousast-with-judge { $env:OUSAST_NETWORK = 'bridge'; ousast @args }