diff --git a/Makefile b/Makefile index cdce94e..8848517 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ MANDIR ?= $(PREFIX)/share/man SYSTEMD_UNIT_DIR ?= $(PREFIX)/lib/systemd/system CI_TEST_PORT ?= $(if $(PORT),$(PORT),2222) -.PHONY: all clean install install-systemd uninstall uninstall-systemd debug release release-check release-check-strict asan valgrind check test test-advisory ci-test unit-test integration-test connection-limit-test security-test info +.PHONY: all clean install install-systemd uninstall uninstall-systemd debug release release-check release-check-strict asan valgrind check test test-advisory ci-test unit-test integration-test anonymous-access-test connection-limit-test security-test info all: $(TARGET) @@ -113,6 +113,10 @@ integration-test: all @cd tests && PORT=$$(($${PORT:-2222} + 1)) ./test_exec_mode.sh @cd tests && PORT=$$(($${PORT:-2222} + 2)) ./test_interactive_input.sh +anonymous-access-test: all + @echo "Running anonymous access tests..." + @cd tests && PORT=$${PORT:-2222} ./test_anonymous_access.sh + connection-limit-test: all @echo "Running connection limit tests..." @cd tests && PORT=$${PORT:-2222} ./test_connection_limits.sh @@ -123,6 +127,7 @@ security-test: all ci-test: @$(MAKE) test PORT=$(CI_TEST_PORT) + @$(MAKE) anonymous-access-test PORT=$$(($(CI_TEST_PORT) + 5)) @$(MAKE) connection-limit-test PORT=$$(($(CI_TEST_PORT) + 10)) @$(MAKE) security-test PORT=$$(($(CI_TEST_PORT) + 20)) diff --git a/README.md b/README.md index a04ef40..002fe26 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,7 @@ make clean # clean build artifacts ```sh make test # run comprehensive test suite and fail on regressions make test-advisory # run integration tests as advisory checks +make anonymous-access-test # verify default anonymous login behavior make connection-limit-test # verify per-IP concurrency and rate limits make security-test # run security feature checks make ci-test # run the same checks as GitHub Actions @@ -218,7 +219,7 @@ cd tests **Test coverage:** - Basic functionality: 3 tests - Anonymous access: 2 tests -- Security features: 11 tests +- Security features: 12 tests - Stress test: concurrent connections ### Dependencies diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 77f4c89..d4379bf 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -53,6 +53,9 @@ `host_key` / `messages.log` into the test directory. - Added `make security-test` and `make ci-test` so local runs can use the same full verification path as GitHub Actions. +- Anonymous access checks now use isolated state, wait for real SSH health, + avoid external `timeout` helpers, and run through `make anonymous-access-test` + as part of `make ci-test`. - Refreshed README and quick-reference module maps to match the current `cli_text`, `help_text`, `support_text`, i18n, exec, and rate-limit modules. - NORMAL mode now opens at the latest visible messages instead of the oldest diff --git a/docs/CICD.md b/docs/CICD.md index 3d2672b..a399e41 100644 --- a/docs/CICD.md +++ b/docs/CICD.md @@ -6,7 +6,8 @@ AUTOMATIC TESTING Every push or PR automatically runs: - Build on Ubuntu - AddressSanitizer build - - `make ci-test` + - `make ci-test` (strict integration, anonymous access, connection limits, + and security feature checks) - Release/package preflight (`make release-check`) Check status: diff --git a/docs/Development-Guide.md b/docs/Development-Guide.md index 163a33b..bc01312 100644 --- a/docs/Development-Guide.md +++ b/docs/Development-Guide.md @@ -161,6 +161,7 @@ make install # Install to /usr/local/bin ```sh make test # Run all tests and fail on regressions make test-advisory # Run integration tests as advisory checks +make anonymous-access-test # Verify default anonymous login behavior make connection-limit-test # Verify per-IP concurrency and rate limits make security-test # Run security feature checks make ci-test # Run the same checks as GitHub Actions diff --git a/docs/QUICKREF.md b/docs/QUICKREF.md index 20e678d..a593a85 100644 --- a/docs/QUICKREF.md +++ b/docs/QUICKREF.md @@ -11,6 +11,7 @@ BUILD TEST make test strict unit + integration tests make test-advisory unit tests + advisory integration checks + make anonymous-access-test default anonymous login checks make connection-limit-test per-IP concurrency/rate-limit checks make security-test security feature checks make ci-test same checks as GitHub Actions diff --git a/tests/test_anonymous_access.sh b/tests/test_anonymous_access.sh index f325d0b..7345196 100755 --- a/tests/test_anonymous_access.sh +++ b/tests/test_anonymous_access.sh @@ -1,90 +1,112 @@ #!/bin/bash -# Test anonymous SSH access +# Anonymous SSH access regression tests for TNT BIN="../tnt" PORT=${PORT:-2222} +PASS=0 +FAIL=0 +STATE_DIR=$(mktemp -d "${TMPDIR:-/tmp}/tnt-anonymous-test.XXXXXX") +SERVER_PID="" + +cleanup() { + if [ -n "$SERVER_PID" ]; then + kill "$SERVER_PID" 2>/dev/null || true + wait "$SERVER_PID" 2>/dev/null || true + fi + rm -rf "$STATE_DIR" +} + +trap cleanup EXIT if [ ! -f "$BIN" ]; then echo "Error: Binary $BIN not found." exit 1 fi -echo "Starting TNT server on port $PORT..." -TNT_LANG=zh $BIN -p $PORT > /dev/null 2>&1 & +SSH_BASE="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PubkeyAuthentication=no -p $PORT" + +wait_for_health() { + local out + + for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do + if [ -n "$SERVER_PID" ] && ! kill -0 "$SERVER_PID" 2>/dev/null; then + return 1 + fi + out=$(ssh -n $SSH_BASE localhost health 2>/dev/null || true) + [ "$out" = "ok" ] && return 0 + sleep 1 + done + return 1 +} + +run_password_test() { + local name="$1" + local user="$2" + local password="$3" + local display_name="$4" + local script="$STATE_DIR/$name.expect" + local log="$STATE_DIR/$name.log" + + cat >"$script" <"$log" 2>&1; then + return 0 + fi + + sed -n '1,120p' "$log" + return 1 +} + +echo "=== TNT Anonymous Access Tests ===" + +TNT_LANG=zh TNT_RATE_LIMIT=0 "$BIN" -p "$PORT" -d "$STATE_DIR" \ + >"$STATE_DIR/server.log" 2>&1 & SERVER_PID=$! -sleep 2 -cleanup() { - kill $SERVER_PID 2>/dev/null - wait 2>/dev/null -} -trap cleanup EXIT - -# Detect timeout command -TIMEOUT_CMD="timeout" -if command -v gtimeout >/dev/null 2>&1; then - TIMEOUT_CMD="gtimeout" -fi - -echo "Testing anonymous SSH access to TNT server..." -echo "" - -# Test 1: Connection with any username and password -echo "Test 1: Connection with any username (should succeed)" -$TIMEOUT_CMD 10 expect -c " -spawn ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p $PORT testuser@localhost -expect { - \"password:\" { - send \"anypassword\r\" - expect { - \"请输入用户名\" { - send \"TestUser\r\" - send \"\003\" - exit 0 - } - timeout { exit 1 } - } - } - timeout { exit 1 } -} -" 2>&1 | grep -q "请输入用户名" - -if [ $? -eq 0 ]; then - echo "✓ Test 1 PASSED: Can connect with any password" +if wait_for_health; then + echo "✓ server started" + PASS=$((PASS + 1)) else - echo "✗ Test 1 FAILED: Cannot connect with any password" + echo "✗ server failed to start" + sed -n '1,120p' "$STATE_DIR/server.log" exit 1 fi -echo "" - -# Test 2: Connection should work with empty password -echo "Test 2: Simple connection (standard SSH command)" -$TIMEOUT_CMD 10 expect -c " -spawn ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p $PORT anonymous@localhost -expect { - \"password:\" { - send \"\r\" - expect { - \"请输入用户名\" { - send \"\r\" - send \"\003\" - exit 0 - } - timeout { exit 1 } - } - } - timeout { exit 1 } -} -" 2>&1 | grep -q "请输入用户名" - -if [ $? -eq 0 ]; then - echo "✓ Test 2 PASSED: Can connect with empty password" +if run_password_test "any-password" "testuser" "anypassword" "TestUser"; then + echo "✓ accepts any password when no access token is configured" + PASS=$((PASS + 1)) else - echo "✗ Test 2 FAILED: Cannot connect with empty password" - exit 1 + echo "✗ any-password login failed" + FAIL=$((FAIL + 1)) +fi + +if run_password_test "empty-password" "anonymous" "" ""; then + echo "✓ accepts empty password when no access token is configured" + PASS=$((PASS + 1)) +else + echo "✗ empty-password login failed" + FAIL=$((FAIL + 1)) fi echo "" -echo "Anonymous access test completed." -exit 0 +echo "PASSED: $PASS" +echo "FAILED: $FAIL" +[ "$FAIL" -eq 0 ] && echo "All tests passed" || echo "Some tests failed" +exit "$FAIL"