@@ -1117,4 +1117,293 @@ def test_cli_invalid_choice_fails(args, expected_error):
11171117def test_cli_invalid_path_prints_error ():
11181118 result = run_cli ("does_not_exist" )
11191119
1120- assert "[ERROR]" in result .stdout or "[ERROR]" in result .stderr
1120+ assert "[ERROR]" in result .stdout or "[ERROR]" in result .stderr
1121+
1122+ def test_cli_json_inline_ignore_suppresses_finding (tmp_path ):
1123+ write_python_file (
1124+ tmp_path ,
1125+ "ignored.py" ,
1126+ 'password = "abcdef" # sentinelscan: ignore\n ' ,
1127+ )
1128+
1129+ result = run_cli (tmp_path , "--json" )
1130+ assert_success (result )
1131+
1132+ data = parse_json_output (result )
1133+
1134+ assert data == []
1135+
1136+
1137+ def test_cli_json_inline_ignore_keeps_non_ignored_findings (tmp_path ):
1138+ findings_file = write_python_file (
1139+ tmp_path ,
1140+ "findings.py" ,
1141+ 'password = "abcdef" # sentinelscan: ignore\n '
1142+ 'token = "abc1234567890j"\n ' ,
1143+ )
1144+
1145+ result = run_cli (tmp_path , "--json" )
1146+ assert_success (result )
1147+
1148+ data = parse_json_output (result )
1149+
1150+ assert_single_json_finding (
1151+ data ,
1152+ line = 2 ,
1153+ file = findings_file ,
1154+ var_name = "token" ,
1155+ rule_id = "TOKEN" ,
1156+ rule = "Token" ,
1157+ severity = "MEDIUM" ,
1158+ value = "abc1234567890j" ,
1159+ reason = TOKEN_REASON ,
1160+ confidence = "HIGH" ,
1161+ )
1162+
1163+
1164+ def test_cli_json_unrelated_comment_does_not_suppress_finding (tmp_path ):
1165+ findings_file = write_python_file (
1166+ tmp_path ,
1167+ "findings.py" ,
1168+ 'password = "abcdef" # normal comment\n ' ,
1169+ )
1170+
1171+ result = run_cli (tmp_path , "--json" )
1172+ assert_success (result )
1173+
1174+ data = parse_json_output (result )
1175+
1176+ assert_single_json_finding (
1177+ data ,
1178+ line = 1 ,
1179+ file = findings_file ,
1180+ var_name = "password" ,
1181+ rule_id = "PASSWORD" ,
1182+ rule = "Password" ,
1183+ severity = "HIGH" ,
1184+ value = "abcdef" ,
1185+ reason = PASSWORD_REASON ,
1186+ confidence = "LOW" ,
1187+ )
1188+
1189+
1190+ def test_cli_json_inline_ignore_suppresses_multiple_findings_on_same_line (tmp_path ):
1191+ write_python_file (
1192+ tmp_path ,
1193+ "findings.py" ,
1194+ 'api_key = "AKIAEXAMPLE123456789" # sentinelscan: ignore\n ' ,
1195+ )
1196+
1197+ result = run_cli (tmp_path , "--json" )
1198+ assert_success (result )
1199+
1200+ data = parse_json_output (result )
1201+
1202+ assert data == []
1203+
1204+
1205+ def test_cli_json_inline_ignore_works_with_severity_filter (tmp_path ):
1206+ findings_file = write_python_file (
1207+ tmp_path ,
1208+ "findings.py" ,
1209+ 'password = "abcdef" # sentinelscan: ignore\n '
1210+ 'random_var = "AKIAEXAMPLE123456789"\n ' ,
1211+ )
1212+
1213+ result = run_cli (tmp_path , "--json" , "--severity" , "HIGH" )
1214+ assert_success (result )
1215+
1216+ data = parse_json_output (result )
1217+
1218+ assert_single_json_finding (
1219+ data ,
1220+ line = 2 ,
1221+ file = findings_file ,
1222+ var_name = "random_var" ,
1223+ rule_id = "AWS_ACCESS_KEY" ,
1224+ rule = "AWS Access Key" ,
1225+ severity = "HIGH" ,
1226+ value = "AKIAEXAMPLE123456789" ,
1227+ reason = "value matched AKIA-prefixed AWS access key pattern" ,
1228+ confidence = "HIGH" ,
1229+ )
1230+
1231+
1232+ def test_cli_json_inline_ignore_works_with_confidence_filter (tmp_path ):
1233+ findings_file = write_python_file (
1234+ tmp_path ,
1235+ "findings.py" ,
1236+ 'password = "abcdef" # sentinelscan: ignore\n '
1237+ 'token = "abc1234567890j"\n ' ,
1238+ )
1239+
1240+ result = run_cli (tmp_path , "--json" , "--confidence" , "HIGH" )
1241+ assert_success (result )
1242+
1243+ data = parse_json_output (result )
1244+
1245+ assert_single_json_finding (
1246+ data ,
1247+ line = 2 ,
1248+ file = findings_file ,
1249+ var_name = "token" ,
1250+ rule_id = "TOKEN" ,
1251+ rule = "Token" ,
1252+ severity = "MEDIUM" ,
1253+ value = "abc1234567890j" ,
1254+ reason = TOKEN_REASON ,
1255+ confidence = "HIGH" ,
1256+ )
1257+
1258+
1259+ def test_cli_json_inline_ignore_works_with_redaction (tmp_path ):
1260+ findings_file = write_python_file (
1261+ tmp_path ,
1262+ "findings.py" ,
1263+ 'password = "abcdef" # sentinelscan: ignore\n '
1264+ 'token = "abc1234567890j"\n ' ,
1265+ )
1266+
1267+ result = run_cli (tmp_path , "--json" , "--redact" )
1268+ assert_success (result )
1269+
1270+ data = parse_json_output (result )
1271+
1272+ assert_single_json_finding (
1273+ data ,
1274+ line = 2 ,
1275+ file = findings_file ,
1276+ var_name = "token" ,
1277+ rule_id = "TOKEN" ,
1278+ rule = "Token" ,
1279+ severity = "MEDIUM" ,
1280+ value = "ab**********0j" ,
1281+ reason = TOKEN_REASON ,
1282+ confidence = "HIGH" ,
1283+ )
1284+
1285+
1286+ def test_cli_json_inline_ignore_and_sentinelscanignore_work_together (tmp_path ):
1287+ findings_file = write_python_file (
1288+ tmp_path ,
1289+ "src/findings.py" ,
1290+ 'password = "abcdef" # sentinelscan: ignore\n '
1291+ 'token = "abc1234567890j"\n ' ,
1292+ )
1293+ write_python_file (
1294+ tmp_path ,
1295+ "ignored.py" ,
1296+ 'random_var = "AKIAEXAMPLE123456789"\n ' ,
1297+ )
1298+
1299+ ignore_file = tmp_path / ".sentinelscanignore"
1300+ ignore_file .write_text ("ignored.py\n " , encoding = "utf-8" )
1301+
1302+ result = run_cli (tmp_path , "--json" )
1303+ assert_success (result )
1304+
1305+ data = parse_json_output (result )
1306+
1307+ assert_single_json_finding (
1308+ data ,
1309+ line = 2 ,
1310+ file = findings_file ,
1311+ var_name = "token" ,
1312+ rule_id = "TOKEN" ,
1313+ rule = "Token" ,
1314+ severity = "MEDIUM" ,
1315+ value = "abc1234567890j" ,
1316+ reason = TOKEN_REASON ,
1317+ confidence = "HIGH" ,
1318+ )
1319+
1320+
1321+ # -------------------------
1322+ # CLI text inline ignore behavior
1323+ # -------------------------
1324+
1325+
1326+ def test_cli_text_inline_ignore_suppresses_finding (tmp_path ):
1327+ write_python_file (
1328+ tmp_path ,
1329+ "ignored.py" ,
1330+ 'password = "abcdef" # sentinelscan: ignore\n ' ,
1331+ )
1332+
1333+ result = run_cli (tmp_path )
1334+ assert_success (result )
1335+
1336+ assert "No vulnerabilities found." in result .stdout
1337+ assert "abcdef" not in result .stdout
1338+ assert "Reason:" not in result .stdout
1339+ assert "Confidence:" not in result .stdout
1340+
1341+
1342+ def test_cli_text_inline_ignore_keeps_non_ignored_findings (tmp_path ):
1343+ write_python_file (
1344+ tmp_path ,
1345+ "findings.py" ,
1346+ 'password = "abcdef" # sentinelscan: ignore\n '
1347+ 'token = "abc1234567890j"\n ' ,
1348+ )
1349+
1350+ result = run_cli (tmp_path )
1351+ assert_success (result )
1352+
1353+ assert "password" not in result .stdout
1354+ assert "abcdef" not in result .stdout
1355+ assert "Token" in result .stdout
1356+ assert "abc1234567890j" in result .stdout
1357+ assert "Reason:" in result .stdout
1358+ assert "Confidence:" in result .stdout
1359+
1360+
1361+ def test_cli_text_unrelated_comment_does_not_suppress_finding (tmp_path ):
1362+ write_python_file (
1363+ tmp_path ,
1364+ "findings.py" ,
1365+ 'password = "abcdef" # normal comment\n ' ,
1366+ )
1367+
1368+ result = run_cli (tmp_path )
1369+ assert_success (result )
1370+
1371+ assert "[HIGH]" in result .stdout
1372+ assert "Password" in result .stdout
1373+ assert "abcdef" in result .stdout
1374+ assert "Reason:" in result .stdout
1375+ assert "Confidence:" in result .stdout
1376+
1377+
1378+ def test_cli_text_inline_ignore_suppresses_multiple_findings_on_same_line (tmp_path ):
1379+ write_python_file (
1380+ tmp_path ,
1381+ "findings.py" ,
1382+ 'api_key = "AKIAEXAMPLE123456789" # sentinelscan: ignore\n ' ,
1383+ )
1384+
1385+ result = run_cli (tmp_path )
1386+ assert_success (result )
1387+
1388+ assert "No vulnerabilities found." in result .stdout
1389+ assert "AWS Access Key" not in result .stdout
1390+ assert "API Key" not in result .stdout
1391+ assert "AKIAEXAMPLE123456789" not in result .stdout
1392+
1393+
1394+ def test_cli_text_inline_ignore_works_with_redaction (tmp_path ):
1395+ write_python_file (
1396+ tmp_path ,
1397+ "findings.py" ,
1398+ 'password = "abcdef" # sentinelscan: ignore\n '
1399+ 'token = "abc1234567890j"\n ' ,
1400+ )
1401+
1402+ result = run_cli (tmp_path , "--redact" )
1403+ assert_success (result )
1404+
1405+ assert "abcdef" not in result .stdout
1406+ assert "a****f" not in result .stdout
1407+ assert "abc1234567890j" not in result .stdout
1408+ assert "ab**********0j" in result .stdout
1409+ assert "Token" in result .stdout
0 commit comments