turnstone/tests
pyr0ball 81a9b0f49d feat: SSH remote host glean — transport layer and pipeline integration (closes #22, backend)
Adds SSH-based log collection from remote hosts via Paramiko.
One SSH connection per host, multiple log types per connection.

New files:
- app/glean/ssh.py: SSHTransport context manager + command builders
  for journald, syslog, plaintext, and docker log types
- tests/test_glean_ssh.py: 18 tests for transport layer (all mocked)
- tests/test_glean_pipeline_ssh.py: 15 tests for pipeline integration

Pipeline changes (app/glean/pipeline.py):
- glean_sources() now splits sources into local-file and SSH categories
- SSH sources use transport: ssh + glean: list schema in sources.yaml
- _glean_ssh_source(): one SSHTransport per host, N commands per connection
- _stream_and_write(): SSHCommandError caught per-item so one bad
  command does not abort the rest of the host's glean items
- SSHConnectionError skips the entire host with a warning log

SSH source schema (sources.yaml):
  - id: rack01
    transport: ssh
    host: 192.168.1.10
    user: admin
    key_path: ~/.ssh/id_ed25519
    glean:
      - type: journald
        args: [--since, 2 hours ago]
      - type: syslog
        path: /var/log/syslog
      - type: plaintext
        path: /var/log/app/error.log
      - type: docker
        containers: [myapp, nginx]

Key design decisions:
- Key-based auth only (no password prompts in daemon context)
- exit-status check fires after all stdout lines yielded; callers
  drain the iterator to trigger it
- Local file sources path unchanged; SSH sources co-exist in same yaml
- Docker multi-container: one exec_stream call per container,
  source_id scoped as host_id/type/container_name

Remaining for #22: REST endpoint, SourcesView UI, sources.yaml docs.
285 → 285 tests passing (33 new SSH tests).
2026-05-20 23:03:13 -07:00
..
context refactor: rename ingest → glean throughout codebase 2026-05-20 23:02:55 -07:00
__init__.py feat: initial Turnstone POC — ingest, FTS search, MCP server 2026-05-08 12:12:34 -07:00
test_blocklist_endpoints.py refactor: rename ingest → glean throughout codebase 2026-05-20 23:02:55 -07:00
test_export_corpus.py feat: periodic corpus export — push ERROR/CRITICAL entries and incidents to Avocet 2026-05-11 17:08:35 -07:00
test_glean_dmesg.py refactor: rename ingest → glean throughout codebase 2026-05-20 23:02:55 -07:00
test_glean_pipeline_ssh.py feat: SSH remote host glean — transport layer and pipeline integration (closes #22, backend) 2026-05-20 23:03:13 -07:00
test_glean_qbittorrent.py refactor: rename ingest → glean throughout codebase 2026-05-20 23:02:55 -07:00
test_glean_ssh.py feat: SSH remote host glean — transport layer and pipeline integration (closes #22, backend) 2026-05-20 23:03:13 -07:00
test_glean_syslog.py refactor: rename ingest → glean throughout codebase 2026-05-20 23:02:55 -07:00
test_glean_tautulli.py refactor: rename ingest → glean throughout codebase 2026-05-20 23:02:55 -07:00
test_glean_wazuh.py refactor: rename ingest → glean throughout codebase 2026-05-20 23:02:55 -07:00
test_service_blocklist.py refactor: rename ingest → glean throughout codebase 2026-05-20 23:02:55 -07:00
test_service_pihole.py fix(blocklist): validate _v6_auth session JSON, add auth-failure test 2026-05-15 21:03:03 -07:00
test_services_diagnose.py refactor: rename ingest → glean throughout codebase 2026-05-20 23:02:55 -07:00
test_services_llm.py feat: switch LLM backend to OpenAI-compat; add cf-orch remote inference support 2026-05-12 12:58:38 -07:00
test_watch_watcher.py feat: add file tail source type; configure xanderland watchers 2026-05-11 15:44:10 -07:00