Files
OpenShell/examples/sandbox-policy-quickstart/demo.sh
Alexander Watson 158c925342 docs(examples): add sandbox policy quickstart walkthrough (#266)
* docs(examples): add sandbox policy quickstart walkthrough

Add an interactive getting-started example that demonstrates OpenShell's
network policy system end-to-end: default-deny, L7 read-only access,
and audit logging — all with a single YAML policy file.

- examples/sandbox-policy-quickstart/policy.yaml: policy with default
  static fields (filesystem, landlock, process) so it works out of the
  box with `openshell policy set`
- examples/sandbox-policy-quickstart/demo.sh: automated demo script
  using printf (portable) and openshell ssh-proxy for sandbox exec
- examples/sandbox-policy-quickstart/README.md: step-by-step manual
  walkthrough
- README.md: add "See network policy in action" section linking to the
  quickstart

Signed-off-by: Alexander Watson <zredlined@gmail.com>
Made-with: Cursor
Signed-off-by: Alexander Watson <zredlined@gmail.com>
Made-with: Cursor

* docs: soften default-deny wording to minimal outbound access

Sandbox defaults vary by type and community configs, so
"all outbound traffic is blocked" is too absolute.

Made-with: Cursor

* docs: use curl -sS so L4 deny errors are visible

curl -s suppresses stderr, hiding the 403 from the CONNECT
proxy. Adding -S ensures the error message is always shown.

Made-with: Cursor

---------

Signed-off-by: Alexander Watson <zredlined@gmail.com>
2026-03-13 11:32:32 -07:00

141 lines
4.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
# Sandbox Policy Quickstart — automated demo
#
# Runs the full walkthrough non-interactively:
# 1. Creates a sandbox with default-deny networking
# 2. Attempts a request (denied)
# 3. Applies a read-only GitHub API policy
# 4. Retries the request (allowed)
# 5. Attempts a POST (blocked by L7)
# 6. Shows logs and cleans up
#
# Usage: bash examples/sandbox-policy-quickstart/demo.sh
set -euo pipefail
SANDBOX_NAME="policy-demo"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
POLICY_FILE="${SCRIPT_DIR}/policy.yaml"
SSH_CONFIG=$(mktemp)
cleanup() {
rm -f "$SSH_CONFIG"
printf '\n'
step "Cleaning up"
openshell sandbox delete "$SANDBOX_NAME" 2>/dev/null || true
}
trap cleanup EXIT
BOLD='\033[1m'
CYAN='\033[36m'
GREEN='\033[32m'
RED='\033[31m'
YELLOW='\033[33m'
RESET='\033[0m'
step() {
printf "\n${BOLD}${CYAN}▸ %s${RESET}\n\n" "$1"
}
run() {
printf " ${BOLD}\$ %s${RESET}\n" "$*"
"$@" 2>&1 | sed 's/^/ /'
return "${PIPESTATUS[0]}"
}
sandbox_exec() {
ssh -F "$SSH_CONFIG" "$SSH_HOST" "$@" 2>&1
}
wait_for_ssh() {
local retries=15
for i in $(seq 1 "$retries"); do
if ssh -F "$SSH_CONFIG" "$SSH_HOST" true >/dev/null 2>&1; then
return 0
fi
sleep 2
done
printf " ${RED}✗ SSH connection to sandbox timed out${RESET}\n"
exit 1
}
# ------------------------------------------------------------------
step "1/7 Creating sandbox \"${SANDBOX_NAME}\" (default-deny networking)"
run openshell sandbox create \
--name "$SANDBOX_NAME" \
--keep \
--no-auto-providers \
--no-tty \
-- echo "sandbox ready"
step "Connecting to sandbox"
openshell sandbox ssh-config "$SANDBOX_NAME" > "$SSH_CONFIG"
SSH_HOST=$(awk '/^Host / { print $2; exit }' "$SSH_CONFIG")
wait_for_ssh
# ------------------------------------------------------------------
step "2/7 Attempting to reach api.github.com — should be DENIED"
printf " ${BOLD}\$ curl -sS https://api.github.com/zen${RESET}\n"
if sandbox_exec curl -sSf --max-time 5 https://api.github.com/zen 2>&1 | sed 's/^/ /'; then
printf " ${RED}✗ Expected request to be denied, but it succeeded.${RESET}\n"
exit 1
fi
printf " ${RED}✗ Blocked by default-deny policy.${RESET}\n"
# ------------------------------------------------------------------
step "3/7 Checking deny log"
sleep 2
run openshell logs "$SANDBOX_NAME" --since 1m -n 5
# ------------------------------------------------------------------
step "4/7 Applying read-only GitHub API policy"
printf " Policy file: %s\n\n" "$POLICY_FILE"
run openshell policy set "$SANDBOX_NAME" \
--policy "$POLICY_FILE" \
--wait
# ------------------------------------------------------------------
step "5/7 Retrying GET — should be ALLOWED"
sleep 1
printf " ${BOLD}\$ curl -sS https://api.github.com/zen${RESET}\n"
ZEN=$(sandbox_exec curl -sS --max-time 10 https://api.github.com/zen)
printf " ${GREEN}%s${RESET}\n" "$ZEN"
printf '\n'
printf " ${BOLD}\$ curl -sS https://api.github.com/octocat${RESET}\n"
sandbox_exec curl -sS --max-time 10 https://api.github.com/octocat | sed 's/^/ /'
# ------------------------------------------------------------------
step "6/7 Attempting POST — should be BLOCKED by L7"
printf " ${BOLD}\$ curl -sS -X POST https://api.github.com/repos/octocat/hello-world/issues -d '{\"title\":\"oops\"}'${RESET}\n"
RESPONSE=$(sandbox_exec curl -sS --max-time 10 -X POST \
https://api.github.com/repos/octocat/hello-world/issues \
-H "Content-Type: application/json" \
-d '{"title":"oops"}')
printf " ${YELLOW}%s${RESET}\n" "$RESPONSE"
# ------------------------------------------------------------------
step "7/7 Checking L7 deny log"
sleep 2
run openshell logs "$SANDBOX_NAME" --level warn --since 1m -n 5
# ------------------------------------------------------------------
printf "\n${BOLD}${GREEN}✓ Demo complete.${RESET}\n\n"
printf " What you saw:\n"
printf " 1. Default deny — all outbound traffic blocked\n"
printf " 2. L7 read-only — GET allowed, POST blocked at the HTTP method level\n"
printf " 3. Audit trail — every request logged with method, path, and decision\n\n"
printf " The policy is %s lines of YAML.\n" "$(wc -l < "$POLICY_FILE" | tr -d ' ')"