@@ -23,7 +23,7 @@ echo '{}' > package.json
2323git add -A && git commit -q -m " init"
2424
2525# 1. SQLite DB created after first run
26- echo " [1/7 ] SQLite DB creation..."
26+ echo " [1/10 ] SQLite DB creation..."
2727if [ -n " ${ANTHROPIC_API_KEY:- } " ]; then
2828 altimate_run " db-create" " say hello" || true
2929 # Find the DB — could be opencode.db, opencode-latest.db, or opencode-{channel}.db
4242fi
4343
4444# 2. WAL mode enabled
45- echo " [2/7 ] WAL mode..."
45+ echo " [2/10 ] WAL mode..."
4646if [ -n " $DB_PATH " ] && [ -f " $DB_PATH " ] && command -v sqlite3 > /dev/null 2>&1 ; then
4747 WAL_MODE=$( sqlite3 " $DB_PATH " " PRAGMA journal_mode;" 2> /dev/null || echo " unknown" )
4848 assert_eq " $WAL_MODE " " wal" " WAL mode enabled"
5151fi
5252
5353# 3. Session persisted
54- echo " [3/7 ] Session persistence..."
54+ echo " [3/10 ] Session persistence..."
5555if [ -n " $DB_PATH " ] && [ -f " $DB_PATH " ] && command -v sqlite3 > /dev/null 2>&1 ; then
5656 SESSION_COUNT=$( sqlite3 " $DB_PATH " " SELECT count(*) FROM session;" 2> /dev/null || echo " 0" )
5757 assert_ge " $SESSION_COUNT " 1 " session persisted (got $SESSION_COUNT )"
6060fi
6161
6262# 4. Session continue (DB survives restart)
63- echo " [4/7 ] Session continue..."
63+ echo " [4/10 ] Session continue..."
6464if [ -n " ${ANTHROPIC_API_KEY:- } " ]; then
6565 altimate_run " continue" --continue " what was my last message" || true
6666 assert_not_contains " $( get_output continue) " " TIMEOUT" " session continue works"
6969fi
7070
7171# 5. Compaction doesn't crash (best-effort — seed if fixture available)
72- echo " [5/7 ] Compaction resilience..."
72+ echo " [5/10 ] Compaction resilience..."
7373if [ -n " $DB_PATH " ] && [ -f " $SCRIPT_DIR /fixtures/compaction-session.sql" ] && command -v sqlite3 > /dev/null 2>&1 ; then
7474 sqlite3 " $DB_PATH " < " $SCRIPT_DIR /fixtures/compaction-session.sql" 2> /dev/null || true
7575 if [ -n " ${ANTHROPIC_API_KEY:- } " ]; then
9090 skip_test " Compaction resilience" " fixture or sqlite3 not available"
9191fi
9292
93- # 6. Graceful on missing provider key
94- echo " [6/7] Missing API key handling..."
95- SAVED_KEY=" ${ANTHROPIC_API_KEY:- } "
96- unset ANTHROPIC_API_KEY
97- OUTPUT=$( timeout 10 altimate run --max-turns 1 --yolo " hello" 2>&1 || true)
98- # Should get a clean error, not an unhandled exception / stack trace
99- assert_not_contains " $OUTPUT " " TypeError" " no TypeError on missing key"
100- assert_not_contains " $OUTPUT " " Cannot read properties" " no unhandled error on missing key"
101- if [ -n " $SAVED_KEY " ]; then
102- export ANTHROPIC_API_KEY=" $SAVED_KEY "
103- fi
104-
105- # 7. Config backwards compatibility
106- echo " [7/7] Config backwards compat..."
93+ # 6. Config backwards compatibility
94+ echo " [6/10] Config backwards compat..."
10795CONFIG_DIR=" ${XDG_CONFIG_HOME:- $HOME / .config} /altimate-code"
10896mkdir -p " $CONFIG_DIR "
10997if [ -f " $SCRIPT_DIR /fixtures/old-config.json" ]; then
119107 skip_test " Config backwards compat" " old-config.json fixture not found"
120108fi
121109
122- # 8 . Broken config graceful handling
123- echo " [8/8 ] Broken config handling..."
110+ # 7 . Broken config graceful handling
111+ echo " [7/10 ] Broken config handling..."
124112if [ -f " $SCRIPT_DIR /fixtures/broken-config.json" ]; then
125113 cp " $SCRIPT_DIR /fixtures/broken-config.json" " $CONFIG_DIR /opencode.json"
126114 if [ -n " ${ANTHROPIC_API_KEY:- } " ]; then
@@ -135,6 +123,76 @@ else
135123 skip_test " Broken config handling" " broken-config.json fixture not found"
136124fi
137125
126+ # 8. Yolo deny enforcement — deny rules block even with --yolo (#372, #377)
127+ echo " [8/10] Yolo deny enforcement..."
128+ if [ -n " ${ANTHROPIC_API_KEY:- } " ]; then
129+ # Create a config with an explicit deny rule
130+ # App reads from $XDG_CONFIG_HOME/altimate-code/opencode.jsonc
131+ DENY_CONFIG_DIR=$( mktemp -d /tmp/sanity-deny-config-XXXXXX)
132+ DENY_MARKER=" $DENY_CONFIG_DIR /deny-marker"
133+ mkdir -p " $DENY_CONFIG_DIR /altimate-code"
134+ cat > " $DENY_CONFIG_DIR /altimate-code/opencode.jsonc" << DENYEOF
135+ {
136+ "permission": {
137+ "bash": {
138+ "*": "allow",
139+ "touch ${DENY_MARKER} ": "deny",
140+ "touch /tmp/sanity-deny-*": "deny"
141+ }
142+ }
143+ }
144+ DENYEOF
145+ # Use an observable side-effect: deny "touch" on a marker file.
146+ # If deny enforcement works, the marker file will NOT be created.
147+ DENY_OUTPUT=$( XDG_CONFIG_HOME=" $DENY_CONFIG_DIR " timeout 30 altimate run --max-turns 2 --yolo --format json \
148+ " run this exact bash command: touch $DENY_MARKER " 2>&1 || true)
149+ # Primary check: the marker file must not exist (deny blocked execution)
150+ if [ -f " $DENY_MARKER " ]; then
151+ echo " FAIL: yolo mode bypassed deny rule — denied command was executed"
152+ FAIL_COUNT=$(( FAIL_COUNT + 1 ))
153+ elif echo " $DENY_OUTPUT " | grep -qi " denied\|blocked\|BLOCKED by deny rule\|not allowed" ; then
154+ echo " PASS: yolo deny rule explicitly blocked command"
155+ PASS_COUNT=$(( PASS_COUNT + 1 ))
156+ elif [ -z " $DENY_OUTPUT " ]; then
157+ echo " FAIL: no output from deny enforcement test"
158+ FAIL_COUNT=$(( FAIL_COUNT + 1 ))
159+ else
160+ # Model may have refused on its own — marker absent so still safe
161+ echo " PASS: yolo deny rule (command not executed, marker absent)"
162+ PASS_COUNT=$(( PASS_COUNT + 1 ))
163+ fi
164+ rm -rf " $DENY_CONFIG_DIR "
165+ else
166+ skip_test " Yolo deny enforcement" " no ANTHROPIC_API_KEY"
167+ fi
168+
169+ # 9. Missing API key handling (no unhandled exceptions)
170+ echo " [9/10] Missing API key handling..."
171+ SAVED_KEY=" ${ANTHROPIC_API_KEY:- } "
172+ unset ANTHROPIC_API_KEY
173+ OUTPUT=$( timeout 10 altimate run --max-turns 1 --yolo " hello" 2>&1 || true)
174+ assert_not_contains " $OUTPUT " " TypeError" " no TypeError on missing key"
175+ assert_not_contains " $OUTPUT " " Cannot read properties" " no unhandled error on missing key"
176+ if [ -n " $SAVED_KEY " ]; then
177+ export ANTHROPIC_API_KEY=" $SAVED_KEY "
178+ fi
179+
180+ # 10. No internet — graceful error, not blank screen (#181)
181+ echo " [10/10] No internet graceful handling..."
182+ # Use an unreachable DNS to simulate no internet (timeout quickly)
183+ NO_NET_OUTPUT=$( timeout 15 env https_proxy=http://192.0.2.1:1 http_proxy=http://192.0.2.1:1 \
184+ altimate run --max-turns 1 --yolo " hello" 2>&1 || true)
185+ assert_not_contains " $NO_NET_OUTPUT " " TypeError" " no TypeError without internet"
186+ assert_not_contains " $NO_NET_OUTPUT " " Cannot read properties" " no unhandled error without internet"
187+ # Should get some kind of connection/auth error, not a blank hang
188+ if [ -z " $NO_NET_OUTPUT " ]; then
189+ echo " FAIL: no output at all without internet (blank screen)"
190+ FAIL_COUNT=$(( FAIL_COUNT + 1 ))
191+ else
192+ echo " PASS: produced output without internet ($( echo " $NO_NET_OUTPUT " | wc -l) lines)"
193+ PASS_COUNT=$(( PASS_COUNT + 1 ))
194+ fi
195+
138196# Cleanup
139197rm -rf " $WORKDIR "
140198
0 commit comments