Honest CI: fix ruff lint and harden gates
This commit is contained in:
@@ -49,7 +49,7 @@ jobs:
|
|||||||
pip install bandit pip-audit ruff --break-system-packages
|
pip install bandit pip-audit ruff --break-system-packages
|
||||||
|
|
||||||
- name: Ruff lint
|
- name: Ruff lint
|
||||||
run: ruff check . || true
|
run: ruff check .
|
||||||
|
|
||||||
- name: Bandit (advisory)
|
- name: Bandit (advisory)
|
||||||
run: bandit -r . -q || true
|
run: bandit -r . -q || true
|
||||||
@@ -61,7 +61,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
if [ -d tests ] || ls test_*.py *_test.py 2>/dev/null; then
|
if [ -d tests ] || ls test_*.py *_test.py 2>/dev/null; then
|
||||||
pip install pytest --break-system-packages
|
pip install pytest --break-system-packages
|
||||||
pytest -q || true
|
pytest -q
|
||||||
else
|
else
|
||||||
echo "No tests found — skip"
|
echo "No tests found — skip"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Regular → Executable
+3
-9
@@ -171,9 +171,7 @@ def text_is_factual(text: str) -> bool:
|
|||||||
return True
|
return True
|
||||||
if DATA_PHONE.search(text) or DATA_MONEY.search(text) or DATA_EMAIL.search(text):
|
if DATA_PHONE.search(text) or DATA_MONEY.search(text) or DATA_EMAIL.search(text):
|
||||||
return True
|
return True
|
||||||
if DATA_ADDRESS.search(text) and DATA_DATE.search(text):
|
return bool(DATA_ADDRESS.search(text) and DATA_DATE.search(text))
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def looks_conversational(text: str) -> bool:
|
def looks_conversational(text: str) -> bool:
|
||||||
@@ -184,9 +182,7 @@ def looks_conversational(text: str) -> bool:
|
|||||||
if text.count("?") >= 2 and len(text) < 500:
|
if text.count("?") >= 2 and len(text) < 500:
|
||||||
return True
|
return True
|
||||||
# Short back-and-forth without hard facts.
|
# Short back-and-forth without hard facts.
|
||||||
if len(text) < 80 and not has_data_signals(text):
|
return len(text) < 80 and not has_data_signals(text)
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def is_name_list_message(text: str) -> bool:
|
def is_name_list_message(text: str) -> bool:
|
||||||
@@ -295,9 +291,7 @@ def msg_selection(
|
|||||||
if latest_draft_files and fid in latest_draft_files:
|
if latest_draft_files and fid in latest_draft_files:
|
||||||
files[fid] = True
|
files[fid] = True
|
||||||
continue
|
continue
|
||||||
if is_doc(f) or informative_filename(f.get("name") or ""):
|
if is_doc(f) or informative_filename(f.get("name") or "") or is_image(f) and informative_image(f, text):
|
||||||
files[fid] = True
|
|
||||||
elif is_image(f) and informative_image(f, text):
|
|
||||||
files[fid] = True
|
files[fid] = True
|
||||||
return {
|
return {
|
||||||
"action": "import",
|
"action": "import",
|
||||||
|
|||||||
Regular → Executable
Regular → Executable
@@ -9,8 +9,8 @@ import json
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import zipfile
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
import zipfile
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
@@ -115,7 +115,7 @@ class ReviewHandler(BaseHTTPRequestHandler):
|
|||||||
export: SlackExport
|
export: SlackExport
|
||||||
manifest_path: Path
|
manifest_path: Path
|
||||||
|
|
||||||
def log_message(self, format: str, *args) -> None: # noqa: A003
|
def log_message(self, format: str, *args) -> None:
|
||||||
if os.environ.get("SLACK_IMPORT_QUIET") != "1":
|
if os.environ.get("SLACK_IMPORT_QUIET") != "1":
|
||||||
super().log_message(format, *args)
|
super().log_message(format, *args)
|
||||||
|
|
||||||
@@ -166,14 +166,14 @@ class ReviewHandler(BaseHTTPRequestHandler):
|
|||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def do_OPTIONS(self) -> None: # noqa: N802
|
def do_OPTIONS(self) -> None:
|
||||||
self.send_response(HTTPStatus.NO_CONTENT)
|
self.send_response(HTTPStatus.NO_CONTENT)
|
||||||
self.send_header("Access-Control-Allow-Origin", "*")
|
self.send_header("Access-Control-Allow-Origin", "*")
|
||||||
self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||||
self.send_header("Access-Control-Allow-Headers", "Content-Type")
|
self.send_header("Access-Control-Allow-Headers", "Content-Type")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
def do_GET(self) -> None: # noqa: N802
|
def do_GET(self) -> None:
|
||||||
parsed = urlparse(self.path)
|
parsed = urlparse(self.path)
|
||||||
path = parsed.path
|
path = parsed.path
|
||||||
qs = parse_qs(parsed.query)
|
qs = parse_qs(parsed.query)
|
||||||
@@ -364,7 +364,7 @@ class ReviewHandler(BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
self.send_error(HTTPStatus.NOT_FOUND)
|
self.send_error(HTTPStatus.NOT_FOUND)
|
||||||
|
|
||||||
def do_POST(self) -> None: # noqa: N802
|
def do_POST(self) -> None:
|
||||||
parsed = urlparse(self.path)
|
parsed = urlparse(self.path)
|
||||||
if parsed.path != "/api/manifest":
|
if parsed.path != "/api/manifest":
|
||||||
self.send_error(HTTPStatus.NOT_FOUND)
|
self.send_error(HTTPStatus.NOT_FOUND)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from datetime import datetime, timezone
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_EXPORT = Path.home() / "Downloads" / "slack-export"
|
DEFAULT_EXPORT = Path.home() / "Downloads" / "slack-export"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ def test_wilson_not_in_auto_channels(cherry_pick):
|
|||||||
|
|
||||||
|
|
||||||
def test_dry_run_pick_count(cherry_pick, export, empty_manifest, tmp_path, monkeypatch):
|
def test_dry_run_pick_count(cherry_pick, export, empty_manifest, tmp_path, monkeypatch):
|
||||||
path, manifest = empty_manifest
|
_path, manifest = empty_manifest
|
||||||
monkeypatch.setattr(cherry_pick, "MANIFEST_PATH", tmp_path / "manifest.json")
|
monkeypatch.setattr(cherry_pick, "MANIFEST_PATH", tmp_path / "manifest.json")
|
||||||
monkeypatch.setattr(cherry_pick, "DEFAULT_EXPORT", export.paths.root)
|
monkeypatch.setattr(cherry_pick, "DEFAULT_EXPORT", export.paths.root)
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,11 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import io
|
|
||||||
import json
|
import json
|
||||||
import urllib.error
|
import urllib.error
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import zipfile
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
@@ -117,9 +116,10 @@ def test_manifest_post_skips_non_dict_user(api):
|
|||||||
|
|
||||||
|
|
||||||
def test_safe_export_path_rejects_dotdot():
|
def test_safe_export_path_rejects_dotdot():
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
import server
|
import server
|
||||||
from slack_export import SlackExport
|
from slack_export import SlackExport
|
||||||
from unittest.mock import Mock
|
|
||||||
|
|
||||||
root = Path(__file__).resolve().parents[1] / "tests/fixtures/mini-export"
|
root = Path(__file__).resolve().parents[1] / "tests/fixtures/mini-export"
|
||||||
handler = Mock(spec=server.ReviewHandler)
|
handler = Mock(spec=server.ReviewHandler)
|
||||||
|
|||||||
@@ -5,11 +5,16 @@ from __future__ import annotations
|
|||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import zipfile
|
import zipfile
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from slack_export import SlackExport, load_json, resolve_paths, slack_ts_to_iso, user_display
|
from slack_export import (
|
||||||
|
SlackExport,
|
||||||
|
load_json,
|
||||||
|
resolve_paths,
|
||||||
|
slack_ts_to_iso,
|
||||||
|
user_display,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_slack_ts_to_iso():
|
def test_slack_ts_to_iso():
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import shutil
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import importlib.util
|
|||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
REPO = Path(__file__).resolve().parents[1]
|
REPO = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
def test_health(api):
|
def test_health(api):
|
||||||
data = api["get"]("/api/health")
|
data = api["get"]("/api/health")
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user