test: add resource limit regression tests
ober
e37c4e764a5a2e3d9db066d9ff04408240c9398c
--- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ SBOM_DIR ?= dist/sbom REPRO_DIR ?= dist/reproducibility TARGET_EVIDENCE_DIR ?= dist/target-evidence -.PHONY: all build binary test test-parser parser-corpus test-cli-policy import-check clean-generated security audit verify sbom reproducibility-report target-evidence release-evidence clean install lint +.PHONY: all build binary test test-parser test-limits parser-corpus test-cli-policy import-check clean-generated security audit verify sbom reproducibility-report target-evidence release-evidence clean install lint all: binary @@ -42,6 +42,9 @@ install: binary test-parser: @$(JEXEC) tests/test-parser.ss +test-limits: + @$(JEXEC) tests/test-limits.ss + parser-corpus: @$(JEXEC) support/parser-corpus-evidence.ss @@ -52,10 +55,12 @@ test-cli-policy: binary @echo "--- system opt-in ---"; JAWK_ALLOW_SYSTEM=1 ./$(JAWK_BIN) 'BEGIN{print system("true")}' | grep -qx 0 @echo "--- pipe opt-in ---"; JAWK_ALLOW_SYSTEM=1 ./$(JAWK_BIN) 'BEGIN{print "ok" | "cat"}' @echo "--- file I/O opt-in ---"; rm -f .jawk-test-out; JAWK_ALLOW_FILE_IO=1 ./$(JAWK_BIN) 'BEGIN{print "ok" > ".jawk-test-out"}'; grep -qx ok .jawk-test-out; rm -f .jawk-test-out + @echo "--- absolute path rejected ---"; if JAWK_ALLOW_FILE_IO=1 ./$(JAWK_BIN) 'BEGIN{print "PWNED" > "/tmp/jawk-abs-test"}' 2>/dev/null; then echo "FAIL: absolute path write succeeded"; exit 1; fi + @echo "--- dotdot path rejected ---"; if JAWK_ALLOW_FILE_IO=1 ./$(JAWK_BIN) 'BEGIN{print "PWNED" > "sub/../jawk-dotdot-test"}' 2>/dev/null; then echo "FAIL: dotdot path write succeeded"; exit 1; fi @echo "--- ENVIRON hidden by default ---"; ./$(JAWK_BIN) 'BEGIN{print ("PATH" in ENVIRON)}' | grep -qx 0 @echo "--- ENVIRON allowlist opt-in ---"; JAWK_EXPOSE_ENVIRON=1 ./$(JAWK_BIN) 'BEGIN{print ("PATH" in ENVIRON)}' | grep -qx 1 -test: test-parser binary +test: test-parser test-limits binary @echo "--- print field ---"; echo "hello world" | ./$(JAWK_BIN) '{print $$1}' @echo "--- -F, ---"; echo "a,b,c" | ./$(JAWK_BIN) -F, '{print $$2}' @echo "--- BEGIN/END ---"; echo "" | ./$(JAWK_BIN) 'BEGIN{print "start"} END{print "end"}' new file mode 100644 --- /dev/null +++ b/tests/test-limits.ss @@ -0,0 +1,88 @@ +#!chezscheme + +(import (scheme) + (jerboa-awk parser) + (jerboa-awk ast) + (jerboa-awk main) + (jerboa-awk value) + (jerboa-awk runtime) + (jerboa-awk builtins string)) + +(define pass 0) +(define fail 0) + +(define-syntax test + (syntax-rules () + ((_ name expr expected) + (guard (exn (else + (set! fail (+ fail 1)) + (printf "FAIL ~a: ~a~%" name + (if (message-condition? exn) (condition-message exn) exn)))) + (let ((got expr)) + (if (equal? got expected) + (begin + (set! pass (+ pass 1)) + (printf " ok ~a~%" name)) + (begin + (set! fail (+ fail 1)) + (printf "FAIL ~a: got ~s expected ~s~%" name got expected)))))))) + +(define-syntax test-raises + (syntax-rules () + ((_ name body ...) + (let ((raised? #f)) + (guard (exn (else (set! raised? #t))) + body ...) + (if raised? + (begin + (set! pass (+ pass 1)) + (printf " ok ~a~%" name)) + (begin + (set! fail (+ fail 1)) + (printf "FAIL ~a: expected exception~%" name))))))) + +(printf "--- jawk resource limit tests ---~%") + +(test-raises "NF=300000000 raises limit error" + (let ((env (make-initial-env))) + (env-set! env 'NF (make-awk-number 300000000)))) + +(test-raises "$1000000000 assignment raises limit error" + (let ((env (make-initial-env))) + (env-set-field! env 1000000000 (make-awk-string "x")))) + +(test-raises "infinite user-function recursion raises depth error" + (run-awk '("function f(){return f()} BEGIN{f()}"))) + +(test-raises "printf width 20000000 raises limit error" + (awk-sprintf "%20000000d" (list (make-awk-number 5)))) + +(test-raises "printf precision 20000000 raises limit error" + (awk-sprintf "%.20000000f" (list (make-awk-number 5)))) + +(test-raises "absolute path rejected without JAWK_FILE_ROOT" + (let ((env (make-initial-env))) + (env-get-output-port env "/tmp/jawk-pwned" #f))) + +(test-raises "dotdot path rejected without JAWK_FILE_ROOT" + (let ((env (make-initial-env))) + (env-get-output-port env "dir/sub/../x" #f))) + +(test "NF within limit succeeds" + (let ((env (make-initial-env))) + (env-set! env 'NF (make-awk-number 10)) + (awk-env-nf env)) + 10) + +(test "printf within limit succeeds" + (awk-sprintf "%10d" (list (make-awk-number 5))) + " 5") + +(test "array within limit succeeds" + (let ((env (make-initial-env))) + (env-array-set! env 'a "k1" (make-awk-number 1)) + (= (awk->number (env-array-ref env 'a "k1")) 1)) + #t) + +(printf "~%pass: ~a fail: ~a~%" pass fail) +(when (> fail 0) (exit 1))