commit b89b0f9f7cd2526f6cf5e8100dbf094df79b2806 from: mtmn date: Thu Sep 3 00:35:42 2026 UTC cleanup commit - d26b78f71c23ec0a7f30faf440d8c138327e1394 commit + b89b0f9f7cd2526f6cf5e8100dbf094df79b2806 blob - 78c916cf9665cc833a7eccbaee454e2e2472d234 blob + 625f8e5ac9cf7865777991e4dc2076f8dd955793 --- .gitignore +++ .gitignore @@ -1,6 +1,3 @@ /build/ -/src/pisol/*.so -/src/pisol/*.o -/src/pisol/*.import.scm -/*.import.scm -/.ninja_log +/src/pisol/*.c +/bin/pisol.c blob - 4724188ce7713e8e276bf6ad80537f52fa2b8d5a blob + 264f0de9c56fe8475ec036508dc367fbed7d5396 --- Makefile +++ Makefile @@ -8,7 +8,9 @@ INSTALL ?= install RM ?= rm -f CSC ?= csc CSC_LINK_FLAGS ?= -static -.PHONY: build tui test copy-config clean run install uninstall help +SHFMT ?= shfmt +SHELL_FILES = bin/pisol test/integration.sh +.PHONY: build tui test fmt fmt-check copy-config clean run install uninstall help default: help @@ -32,18 +34,24 @@ build/runtime/pisol: bin/pisol.scm $(CORE_O) $(TUI_O) tui: build build/runtime/pisol -test: build - shellcheck bin/pisol test/integration.sh +test: build fmt-check + shellcheck $(SHELL_FILES) csi -s test/test.scm sh test/integration.sh +fmt: + $(SHFMT) -w $(SHELL_FILES) + +fmt-check: + $(SHFMT) -d $(SHELL_FILES) + copy-config: @target="$${XDG_CONFIG_HOME:-$$HOME/.config}/pisol/init"; \ [ ! -e "$$target" ] || { printf 'pisol: %s already exists\n' "$$target" >&2; exit 1; }; \ $(INSTALL) -d "$${target%/*}" && $(INSTALL) -m 644 config/pisol/init "$$target" clean: - rm -rf build src/pisol/*.o src/pisol/*.so src/pisol/*.import.scm src/pisol/*.link *.import.scm bin/pisol.c src/pisol/*.c build/runtime/*.o build/runtime/*.import.scm build/runtime/*.link + rm -rf build src/pisol/*.c bin/pisol.c run: install $(DESTDIR)$(BINDIR)/pisol @@ -63,6 +71,8 @@ help: 'make build Compile pisol' \ 'make tui Run pisol' \ 'make test Test pisol' \ + 'make fmt Format the shell sources with shfmt' \ + 'make fmt-check Report shell sources that need formatting' \ 'make copy-config Copy the default global init to ~/.config/pisol/init' \ 'make clean Remove generated artifacts' \ 'make install Install pisol and its manual' \ @@ -71,4 +81,4 @@ help: '' \ 'Variables: PREFIX=/usr/local DESTDIR= BINDIR=PREFIX/bin' \ ' LIBEXECDIR=PREFIX/libexec/pisol MANDIR=PREFIX/share/man' \ - ' CSC=csc INSTALL=install' + ' CSC=csc INSTALL=install SHFMT=shfmt' blob - 682abbcb9672b57ea97d350659f1acd31ff59185 blob + cbe803f49517cbee8e5aea0b0cfdcd4e5340152b --- bin/pisol +++ bin/pisol @@ -17,7 +17,7 @@ pisol_bin_dir=$(CDPATH='' cd -- "$(dirname -- "$0")" & pisol_runtime_dir=${PISOL_RUNTIME_DIR:-$pisol_bin_dir/../libexec/pisol} case ${1:-} in --h|--help) +-h | --help) pisol_usage exit 0 ;; @@ -196,7 +196,7 @@ pisol_validate_grants() { while ((index < ${#args[@]})); do grant=${args[index]} case $grant in - --rwx|--rw|--rox|--ro|--unix) + --rwx | --rw | --rox | --ro | --unix) if ((index + 1 >= ${#args[@]})); then printf 'pisol: missing value for %s\n' "$grant" >&2 exit 2 @@ -246,7 +246,7 @@ pisol_exec_seatbelt() { while ((index < ${#args[@]})); do grant=${args[index]} case $grant in - --rwx|--rw|--rox|--ro) + --rwx | --rw | --rox | --ro) path=${args[index + 1]:-} if [[ -z $path ]]; then printf 'pisol: missing value for %s\n' "$grant" >&2 @@ -290,7 +290,7 @@ pisol_exec_seatbelt() { # explicit forwarding has no equivalent and no effect. index=$((index + 2)) ;; - --best-effort|--ignore-missing|--unrestricted-scoped) + --best-effort | --ignore-missing | --unrestricted-scoped) index=$((index + 1)) ;; *) blob - ce9f7327bcb45b381c97fc2d891d77552aa52df1 blob + 87cdc9574857faac634fd70aedf1ce7440a19d82 --- src/pisol/core.scm +++ src/pisol/core.scm @@ -10,7 +10,7 @@ (import scheme (chicken base) (chicken condition) (chicken file) (chicken file posix) (chicken format) (chicken io) (chicken process) (chicken pathname) (chicken process-context) (chicken port) (chicken sort) - (chicken string) (chicken time)) + (chicken string)) (define-record-type configuration (make-configuration project-path config-path baseline-arguments local-writable-directories @@ -19,10 +19,10 @@ configuration? (project-path configuration-project-path) (config-path configuration-config-path) - (baseline-arguments configuration-baseline-arguments configuration-baseline-arguments-set!) + (baseline-arguments configuration-baseline-arguments) (local-writable-directories configuration-local-writable-directories configuration-local-writable-directories-set!) (local-outbound-ports configuration-local-outbound-ports configuration-local-outbound-ports-set!) - (local-preserved-arguments configuration-local-preserved-arguments configuration-local-preserved-arguments-set!) + (local-preserved-arguments configuration-local-preserved-arguments) (writable-directories configuration-writable-directories configuration-writable-directories-set!) (outbound-ports configuration-outbound-ports configuration-outbound-ports-set!) (preserved-arguments configuration-preserved-arguments configuration-preserved-arguments-set!) blob - d3c58dc68cceafe9b06dfeba519a83eeb9039b6a blob + 518717fa6b39462b6c1a7b573c83c158d28cbaa0 --- test/integration.sh +++ test/integration.sh @@ -24,28 +24,28 @@ EOF chmod +x "$fake_bin/landrun" run_pisol() { - ( - cd "$project" - if [ "${ISOLATE_ENV:-}" = "$outer_isolate_env" ]; then - unset ISOLATE_ENV - fi - PATH=$fake_bin:$PATH \ - HOME=$home \ - PISOL_RUNTIME_DIR=$project_root/build/runtime \ - PISOL_TEST_CAPTURE=$capture \ - PISOL_TEST_PROFILE=$profile_capture \ - PISOL_BACKEND=${PISOL_BACKEND:-} \ - NO_COLOR=1 \ - "$project_root/bin/pisol" "$@" - ) + ( + cd "$project" + if [ "${ISOLATE_ENV:-}" = "$outer_isolate_env" ]; then + unset ISOLATE_ENV + fi + PATH=$fake_bin:$PATH \ + HOME=$home \ + PISOL_RUNTIME_DIR=$project_root/build/runtime \ + PISOL_TEST_CAPTURE=$capture \ + PISOL_TEST_PROFILE=$profile_capture \ + PISOL_BACKEND=${PISOL_BACKEND:-} \ + NO_COLOR=1 \ + "$project_root/bin/pisol" "$@" + ) } if run_pisol sh -c 'exit 7'; then - echo "pisol integration: direct command status was not propagated" >&2 - exit 1 + echo "pisol integration: direct command status was not propagated" >&2 + exit 1 else - status=$? - [ "$status" -eq 7 ] || exit 1 + status=$? + [ "$status" -eq 7 ] || exit 1 fi tr '\0' '\n' <"$capture" >"$test_root/args.txt" @@ -57,8 +57,8 @@ grep -Fx -- '/dev/null' "$test_root/args.txt" >/dev/nu grep -Fx -- '--env' "$test_root/args.txt" >/dev/null grep -Fx -- 'ISOLATE_ENV' "$test_root/args.txt" >/dev/null if grep -Fx -- '--unrestricted-network' "$test_root/args.txt" >/dev/null; then - echo "pisol integration: unrestricted network unexpectedly enabled" >&2 - exit 1 + echo "pisol integration: unrestricted network unexpectedly enabled" >&2 + exit 1 fi printf '%s\n' 'args+=(' ' --connect-tcp 443' " --rwx '$home/extra dir'" ')' >"$project/.isolate" @@ -70,10 +70,10 @@ grep -Fx -- "$home/extra dir" "$test_root/args.txt" >/ before=$(cksum "$capture") if ISOLATE_ENV=already run_pisol -- sh -c 'exit 9' 2>/dev/null; then - exit 1 + exit 1 else - status=$? - [ "$status" -eq 9 ] || exit 1 + status=$? + [ "$status" -eq 9 ] || exit 1 fi [ "$before" = "$(cksum "$capture")" ] @@ -88,19 +88,19 @@ grep -F 'x save and exit' "$test_root/tui.out" >/dev/n grep -F 'r remove dir' "$test_root/tui.out" >/dev/null grep -F 'd remove port' "$test_root/tui.out" >/dev/null if grep -E 'r NUMBER remove dir|d PORT remove' "$test_root/tui.out" >/dev/null; then - echo "pisol integration: removal commands still require inline arguments" >&2 - exit 1 + echo "pisol integration: removal commands still require inline arguments" >&2 + exit 1 fi if grep -E 'project:|p project|h home|browse/add' "$test_root/tui.out" >/dev/null; then - echo "pisol integration: location labels unexpectedly exposed" >&2 - exit 1 + echo "pisol integration: location labels unexpectedly exposed" >&2 + exit 1 fi printf 'r\n1\nd\n443\nx\n' | run_pisol >"$test_root/remove.out" if grep -F -- '--rwx' "$project/.isolate" >/dev/null || - grep -F -- '--connect-tcp' "$project/.isolate" >/dev/null; then - echo "pisol integration: prompted removal did not remove configuration" >&2 - exit 1 + grep -F -- '--connect-tcp' "$project/.isolate" >/dev/null; then + echo "pisol integration: prompted removal did not remove configuration" >&2 + exit 1 fi saved=$(cksum "$project/.isolate") @@ -112,8 +112,8 @@ printf 'p 80\nx\n' | run_pisol >/dev/null grep -F -- '/custom' "$project/.isolate" >/dev/null grep -F -- '--connect-tcp 80' "$project/.isolate" >/dev/null if grep -F 'if true' "$project/.isolate" >/dev/null; then - echo "pisol integration: custom configuration was not canonicalized on exit" >&2 - exit 1 + echo "pisol integration: custom configuration was not canonicalized on exit" >&2 + exit 1 fi # Global init defaults are sourced before the local .isolate. @@ -140,7 +140,6 @@ grep -F -- "$project/.isolate" "$test_root/showconfig. grep -F -- "$home/extra dir" "$test_root/showconfig.out" >/dev/null grep -F -- '--connect-tcp 443' "$test_root/showconfig.out" >/dev/null - # --- seatbelt (darwin) backend ------------------------------------------------ # # Driven through PISOL_BACKEND so the darwin translation is exercised from any @@ -167,17 +166,17 @@ FAKE chmod +x "$fake_bin/sandbox-exec" profile_has() { - grep -F -- "$1" "$profile_capture" >/dev/null || { - printf 'pisol integration: seatbelt profile is missing %s\n' "$1" >&2 - exit 1 - } + grep -F -- "$1" "$profile_capture" >/dev/null || { + printf 'pisol integration: seatbelt profile is missing %s\n' "$1" >&2 + exit 1 + } } profile_lacks() { - if grep -F -- "$1" "$profile_capture" >/dev/null; then - printf 'pisol integration: seatbelt profile unexpectedly contains %s\n' "$1" >&2 - exit 1 - fi + if grep -F -- "$1" "$profile_capture" >/dev/null; then + printf 'pisol integration: seatbelt profile unexpectedly contains %s\n' "$1" >&2 + exit 1 + fi } rm -f "$project/.isolate" "$global_init" @@ -213,58 +212,57 @@ profile_has "(allow file-read* (subpath \"$home/extra # An untranslatable grant is refused rather than silently dropped. printf '%s\n' 'args+=( --bogus-grant /somewhere )' >"$project/.isolate" if PISOL_BACKEND=seatbelt run_pisol -- sh -c 'exit 0' 2>/dev/null; then - echo "pisol integration: unknown grant was not rejected" >&2 - exit 1 + echo "pisol integration: unknown grant was not rejected" >&2 + exit 1 else - status=$? - [ "$status" -eq 2 ] || { - printf 'pisol integration: unknown grant exited %s, wanted 2\n' "$status" >&2 - exit 1 - } + status=$? + [ "$status" -eq 2 ] || { + printf 'pisol integration: unknown grant exited %s, wanted 2\n' "$status" >&2 + exit 1 + } fi # Command exit status is propagated through the sandbox. rm -f "$project/.isolate" if PISOL_BACKEND=seatbelt run_pisol sh -c 'exit 7'; then - echo "pisol integration: seatbelt did not propagate command status" >&2 - exit 1 + echo "pisol integration: seatbelt did not propagate command status" >&2 + exit 1 else - status=$? - [ "$status" -eq 7 ] || exit 1 + status=$? + [ "$status" -eq 7 ] || exit 1 fi # Nested isolation is detected before the backend is consulted. before=$(cksum "$profile_capture") if ISOLATE_ENV=already PISOL_BACKEND=seatbelt run_pisol -- sh -c 'exit 9' 2>/dev/null; then - exit 1 + exit 1 else - status=$? - [ "$status" -eq 9 ] || exit 1 + status=$? + [ "$status" -eq 9 ] || exit 1 fi [ "$before" = "$(cksum "$profile_capture")" ] # A missing backend executable reports unavailability rather than running the # command. Only meaningful where the host has no real sandbox-exec. if ! command -v sandbox-exec >/dev/null 2>&1; then - if ( - cd "$project" - unset ISOLATE_ENV - HOME=$home \ - PISOL_BACKEND=seatbelt \ - "$project_root/bin/pisol" -- sh -c 'exit 0' - ) 2>/dev/null; then - echo "pisol integration: missing backend did not fail" >&2 - exit 1 - else - status=$? - [ "$status" -eq 127 ] || { - printf 'pisol integration: missing backend exited %s, wanted 127\n' "$status" >&2 - exit 1 - } - fi + if ( + cd "$project" + unset ISOLATE_ENV + HOME=$home \ + PISOL_BACKEND=seatbelt \ + "$project_root/bin/pisol" -- sh -c 'exit 0' + ) 2>/dev/null; then + echo "pisol integration: missing backend did not fail" >&2 + exit 1 + else + status=$? + [ "$status" -eq 127 ] || { + printf 'pisol integration: missing backend exited %s, wanted 127\n' "$status" >&2 + exit 1 + } + fi fi - # Execution follows the grants: a read-only path does not become executable, # and the profile carries no blanket exec permission. printf '%s\n' "args+=( --ro '$home/extra dir' )" >"$project/.isolate" @@ -275,31 +273,31 @@ profile_lacks "process-exec* (subpath \"$home/extra di # The port range is checked for every backend, not only through the editor. for pisol_bad_port in 0 65536 99999; do - printf 'args+=( --connect-tcp %s )\n' "$pisol_bad_port" >"$project/.isolate" - for pisol_backend_under_test in landrun seatbelt; do - if PISOL_BACKEND=$pisol_backend_under_test run_pisol -- sh -c 'exit 0' 2>/dev/null; then - printf 'pisol integration: %s accepted out-of-range port %s\n' \ - "$pisol_backend_under_test" "$pisol_bad_port" >&2 - exit 1 - else - status=$? - [ "$status" -eq 2 ] || { - printf 'pisol integration: %s exited %s for port %s, wanted 2\n' \ - "$pisol_backend_under_test" "$status" "$pisol_bad_port" >&2 - exit 1 - } - fi - done + printf 'args+=( --connect-tcp %s )\n' "$pisol_bad_port" >"$project/.isolate" + for pisol_backend_under_test in landrun seatbelt; do + if PISOL_BACKEND=$pisol_backend_under_test run_pisol -- sh -c 'exit 0' 2>/dev/null; then + printf 'pisol integration: %s accepted out-of-range port %s\n' \ + "$pisol_backend_under_test" "$pisol_bad_port" >&2 + exit 1 + else + status=$? + [ "$status" -eq 2 ] || { + printf 'pisol integration: %s exited %s for port %s, wanted 2\n' \ + "$pisol_backend_under_test" "$status" "$pisol_bad_port" >&2 + exit 1 + } + fi + done done # A grant missing its value is refused rather than silently ignored. printf '%s\n' 'args+=( --rwx )' >"$project/.isolate" if run_pisol -- sh -c 'exit 0' 2>/dev/null; then - echo "pisol integration: grant without a value was accepted" >&2 - exit 1 + echo "pisol integration: grant without a value was accepted" >&2 + exit 1 else - status=$? - [ "$status" -eq 2 ] || exit 1 + status=$? + [ "$status" -eq 2 ] || exit 1 fi # Backend-specific arguments reach the backend that owns them unchanged. @@ -310,38 +308,38 @@ grep -Fx -- '--some-landrun-only-flag' "$test_root/arg # The backend that does not own them refuses the launch instead of guessing. if PISOL_BACKEND=seatbelt run_pisol -- sh -c 'exit 0' 2>/dev/null; then - echo "pisol integration: seatbelt accepted a landrun-only argument" >&2 - exit 1 + echo "pisol integration: seatbelt accepted a landrun-only argument" >&2 + exit 1 else - status=$? - [ "$status" -eq 2 ] || exit 1 + status=$? + [ "$status" -eq 2 ] || exit 1 fi # An operator who names no known backend gets a usage error, not a sandbox. rm -f "$project/.isolate" if PISOL_BACKEND=nonsuch run_pisol -- sh -c 'exit 0' 2>/dev/null; then - echo "pisol integration: unrecognised backend was accepted" >&2 - exit 1 + echo "pisol integration: unrecognised backend was accepted" >&2 + exit 1 else - status=$? - [ "$status" -eq 2 ] || exit 1 + status=$? + [ "$status" -eq 2 ] || exit 1 fi # An operator who selects no backend at all is told so, and nothing runs. if PISOL_BACKEND=none run_pisol -- sh -c 'exit 0' 2>/dev/null; then - echo "pisol integration: PISOL_BACKEND=none ran the command" >&2 - exit 1 + echo "pisol integration: PISOL_BACKEND=none ran the command" >&2 + exit 1 else - status=$? - [ "$status" -eq 127 ] || exit 1 + status=$? + [ "$status" -eq 127 ] || exit 1 fi # The shipped default init must not opt the machine out of network # restriction. Comments may name the flag; only live code counts. if grep -v '^[[:space:]]*#' "$project_root/config/pisol/init" | - grep -F -- '--unrestricted-network' >/dev/null; then - echo "pisol integration: shipped init grants unrestricted network" >&2 - exit 1 + grep -F -- '--unrestricted-network' >/dev/null; then + echo "pisol integration: shipped init grants unrestricted network" >&2 + exit 1 fi printf 'pisol: shell and TUI integration checks passed\n'