Skip to main content

OraFail Logo

OraFail

A live, terminal-based dashboard that polls multiple Oracle databases concurrently for failed logon attempts. Designed for DBAs and security administrators, it helps identify potential brute-force attacks, misconfigured connection scripts, and unauthorized access attempts in real-time.

Terminal output

Features

  • Concurrent Polling: Uses a thread pool (ThreadPoolExecutor) to monitor multiple Oracle databases concurrently without blocking the UI.
  • Terminal UI Dashboard: A beautiful, responsive console interface built with Rich featuring:
    • Live Aggregates: Displays logon failure counts grouped by sliding time-windows: 1 minute, 10 minutes, and 1 hour.
    • Trend Indicators: Up, down, and neutral arrows comparison to the previous polling cycle.
    • Connection Latency: Tracks response time (in milliseconds) for each target database.
    • Highlight Aging: Color-codes new failure events in bold red and fades them through bold yellow over customizable cycles before returning to normal text.
    • Integrated Log Viewer: Real-time log capture and display directly on the dashboard.
  • Headless Daemon Mode: Run the monitor as a background service (--headless) that streams structured log entries to stdout and log files.
  • Demo Mode: Run with synthetic data (--demo) to explore the dashboard without Oracle connectivity.
  • Sortable Failure View: Sort the unified failure table by time, user, database, or count via --sort-by or the sort_by config option.
  • Connection Caching & Resiliency: Caches connections, performs active ping health-checks, handles automatic reconnects, and enforces TCP connect and query execution timeouts.
  • Auditing Source: Queries Oracle's unified_audit_trail (where action_name = 'LOGON' and return_code != 0).

Installation

This project is built using Python 3.13+ and managed via the uv package manager.

  1. Clone the repository:

    git clone https://github.com/balddba/orafail.git
    cd orafail
    
  2. Sync dependencies: This automatically configures a virtual environment and installs required packages (oracledb, pydantic, pyyaml, rich, loguru):

    uv sync
    

Configuration

Copy the example configuration to create your local config file:

cp config.example.yaml config.yaml

Update config.yaml with your connection parameters. Do not commit config.yaml to source control, as it contains sensitive database credentials.

Configuration Options

Option Type Default Description
databases list Required List of databases to monitor (each requiring name, dsn, user, and password).
max_workers int 5 Maximum number of concurrent database query worker threads.
refresh_seconds int 15 Polling frequency / UI refresh interval in seconds.
highlight_ttl int 3 Number of refresh cycles a new logon failure row remains highlighted.
log_file str null Path to a log file for logging output.
log_level str "INFO" Logging severity threshold (TRACE, DEBUG, INFO, WARNING, ERROR, CRITICAL).
tcp_connect_timeout int 10 Timeout in seconds when establishing database TCP connections.
query_timeout int 10 Timeout in seconds for executing the database audit query.
sort_by str "time" Default sort column for the unified failure table (time, user, database, count).

Sample config.yaml

databases:
  - name: homelab
    dsn: oracle26ai.aaronslab.net:1521/homelab
    user: system
    password: "YourSecurePassword"

max_workers: 5
refresh_seconds: 15
highlight_ttl: 3
sort_by: time
log_file: "monitor.log"
log_level: "INFO"
tcp_connect_timeout: 10
query_timeout: 10

Usage

You can use the bundled helper script orafail to run the application. The launcher will automatically prefer your uv environment, falling back to a virtual environment or system Python if necessary.

Command Line Interface

./orafail --help
usage: orafail [-h] [--config CONFIG] [--headless] [--demo]
               [--sort-by {time,user,database,count}]

Oracle Login Failure Monitor

options:
  -h, --help            show this help message and exit
  --config CONFIG       Path to the YAML configuration file (default: config.yaml)
  --headless            Run in headless daemon mode (no terminal UI)
  --demo                Run in demo mode with synthetic data (no database connection required)
  --sort-by {time,user,database,count}
                        Column to sort failures by (default: time)

Running the Live TUI Dashboard

./orafail

Running as a Headless Daemon

To run the monitor in the background or stream events to standard logging (e.g., for ingestion by SIEM tools like Splunk or ELK):

./orafail --headless

Demo Mode

Explore the dashboard with synthetic data — no config.yaml or Oracle connection required:

./orafail --demo

Demo mode uses three sample databases (prod-oltp, dw-warehouse, auth-db) and generates randomized failure events. If config.yaml exists, other settings (refresh interval, workers, etc.) are still loaded from it.

Sorting Failures

Sort the unified failure table from the CLI or config:

./orafail --sort-by user
./orafail --sort-by count

Valid values: time (default), user, database, count.


Project Structure

Path Purpose
src/orafail/main.py Entry point, OracleLoginFailureMonitor, dashboard rendering
src/orafail/config.py Re-exports AppConfig and DatabaseConfig
src/orafail/models/ Pydantic models (AppConfig, DatabaseConfig, FailureDetail, DatabaseResult, AllResults, EventKey)
config.example.yaml Configuration template
config.yaml Active config with credentials — not committed
scripts/publish.py Release automation (version bump, GitHub release, PyPI publish)
orafail Bash launcher script

Example Outputs

Headless Mode Logs

When running in --headless mode, the monitor logs connection statuses and logon failure events to stdout/log files:

2026-07-08 15:52:25.704 | INFO     | orafail.main:run:573 - Oracle Login Failure Monitor starting...
2026-07-08 15:52:25.911 | INFO     | orafail.main:run:589 - Database: homelab | Status: ONLINE | Latency: 204ms | Failures (1m/10m/1h): 0/0/1
2026-07-08 15:52:25.911 | WARNING  | orafail.main:run:599 - NEW FAILURE on homelab | User: STEVE | IP: oracle26ai.aaronslab.net | Last Failed: 2026-07-08 15:38:15.064532
2026-07-08 15:52:25.911 | WARNING  | orafail.main:run:599 - NEW FAILURE on homelab | User: SYSTEM | IP: Mac.aaronslab.net | Last Failed: 2026-07-08 13:58:53.295442
2026-07-08 15:52:25.911 | WARNING  | orafail.main:run:599 - NEW FAILURE on homelab | User: AMYERS | IP: Mac.aaronslab.net | Last Failed: 2026-07-08 13:54:11.958124
2026-07-08 15:52:25.911 | WARNING  | orafail.main:run:599 - NEW FAILURE on homelab | User: SYSTEM | IP: oracle-password-rotation-ui | Last Failed: 2026-06-30 14:36:37.579003
2026-07-08 15:52:25.911 | WARNING  | orafail.main:run:599 - NEW FAILURE on homelab | User: C##DBA_PW_ROTATION | IP: dcc61bbb7878 | Last Failed: 2026-06-19 10:35:23.796769

Development & Testing

Running Tests

Execute the unit tests using pytest inside the workspace environment:

uv run --with pytest pytest

Formatting & Linting

We enforce codebase standards using Ruff. Run the formatter and linter before submitting PRs:

# Format codebase
uv run --with ruff ruff format src/ tests/

# Check lints
uv run --with ruff ruff check src/ tests/

Publishing Releases

The scripts/publish.py script automates version bumps, git commits, GitHub releases, and PyPI publishing:

# Interactive release (prompts for bump type)
uv run python scripts/publish.py

# Patch bump with confirmation bypass
uv run python scripts/publish.py --bump patch --yes

# Dry-run to preview steps
uv run python scripts/publish.py --bump patch --dry-run

# Build and publish to PyPI only (skip version bump and GitHub release)
uv run python scripts/publish.py --only-publish

Requires uv, gh (authenticated), and PyPI credentials (UV_PUBLISH_TOKEN or keyring).

Security Best Practices

  1. Least-Privilege Database Account: Create a dedicated read-only database user for monitoring. The user only needs access to SYS.UNIFIED_AUDIT_TRAIL or equivalent audit views.
  2. Credential Management: Avoid embedding passwords in scripts. Keep config.yaml securely on the system and restrict read permissions.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

orafail-0.2.0.tar.gz (656.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

orafail-0.2.0-py3-none-any.whl (42.9 kB view details)

Uploaded Python 3

File details

Details for the file orafail-0.2.0.tar.gz.

File metadata

  • Download URL: orafail-0.2.0.tar.gz
  • Upload date:
  • Size: 656.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for orafail-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f57173a5ff45d94cd51b22f889dd79d8ff631ceec3944f4ac53da80eb2bd99a0
MD5 72a76c94ce9c880ea1bf8b2d48f4d1e4
BLAKE2b-256 7d35dd600b26cd4c06e7d96167218a40f36a5c82424f8fa9d6d8df75f6faf43d

See more details on using hashes here.

File details

Details for the file orafail-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: orafail-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 42.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for orafail-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 87cc4e72ef777747cf82a40749d13a978928ae93f46c1af6c773b7407d983a3c
MD5 9f882753e0039ff6333a9a588e4a0c38
BLAKE2b-256 c78d2b095e30d865cf005d6e0655cdf5d870a6fd487d0a3f8d75c47f5f63034c

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.6

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page