Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"ghcr.io/devcontainers/features/copilot-cli:1": {}
},

"postCreateCommand": "bash .devcontainer/post-create.sh",
"onCreateCommand": "bash .devcontainer/post-create.sh",

"customizations": {
"vscode": {
Expand Down
72 changes: 65 additions & 7 deletions .devcontainer/post-create.sh
Original file line number Diff line number Diff line change
@@ -1,18 +1,76 @@
#!/bin/bash
set -euo pipefail

echo "==> Installing IaC security tools..."
# This script runs as `onCreateCommand` so its results are captured by
# Codespaces prebuilds. The three installs below are independent, so we
# run them in parallel and skip work that has already been done.

echo "==> Installing IaC security tools (parallel)..."

log_dir="$(mktemp -d)"
declare -A pids=()

# Checkov — IaC security scanner (ARM, Bicep, Terraform)
pip install --user --only-binary :all: checkov
(
if command -v checkov >/dev/null 2>&1; then
echo "checkov already installed, skipping"
else
pip install --user --only-binary :all: --no-compile --disable-pip-version-check checkov
fi
) >"$log_dir/checkov.log" 2>&1 &
pids[checkov]=$!

# PSRule for Azure — WAF-aligned rules for ARM/Bicep
pwsh -Command "Install-Module -Name PSRule.Rules.Azure -Scope CurrentUser -Force"
(
pwsh -NoProfile -Command "
if (-not (Get-Module -ListAvailable -Name PSRule.Rules.Azure)) {
Install-Module -Name PSRule.Rules.Azure -Scope CurrentUser -Force -AcceptLicense -SkipPublisherCheck
} else {
Write-Host 'PSRule.Rules.Azure already installed, skipping'
}
"
) >"$log_dir/psrule.log" 2>&1 &
pids[psrule]=$!

# ARM-TTK — Microsoft ARM template test toolkit
mkdir -p /home/vscode/.arm-ttk
git clone --depth 1 https://github.com/Azure/arm-ttk.git /home/vscode/.arm-ttk
mkdir -p /home/vscode/.config/powershell
echo 'Import-Module /home/vscode/.arm-ttk/arm-ttk/arm-ttk.psd1' >> /home/vscode/.config/powershell/Microsoft.PowerShell_profile.ps1
(
if [ ! -f /home/vscode/.arm-ttk/arm-ttk/arm-ttk.psd1 ]; then
rm -rf /home/vscode/.arm-ttk
mkdir -p /home/vscode/.arm-ttk
git clone --depth 1 --single-branch --filter=blob:none \
https://github.com/Azure/arm-ttk.git /home/vscode/.arm-ttk
else
echo "arm-ttk already cloned, skipping"
fi
mkdir -p /home/vscode/.config/powershell
profile=/home/vscode/.config/powershell/Microsoft.PowerShell_profile.ps1
import_line='Import-Module /home/vscode/.arm-ttk/arm-ttk/arm-ttk.psd1'
if ! grep -qxF "$import_line" "$profile" 2>/dev/null; then
echo "$import_line" >> "$profile"
fi
) >"$log_dir/armttk.log" 2>&1 &
pids[armttk]=$!

# Wait for all background jobs and surface logs/failures.
status=0
for name in "${!pids[@]}"; do
if ! wait "${pids[$name]}"; then
rc=$?
echo "==> '$name' install failed with exit code $rc" >&2
status=1
fi
done

for f in "$log_dir"/*.log; do
echo "----- $(basename "$f") -----"
cat "$f"
done

rm -rf "$log_dir"

if [ "$status" -ne 0 ]; then
echo "==> One or more install steps failed" >&2
exit "$status"
fi

echo "==> Dev environment ready"