Skip to content

0.4.0#12

Merged
orenlab merged 36 commits intomainfrom
0.4.0
Feb 13, 2026
Merged

0.4.0#12
orenlab merged 36 commits intomainfrom
0.4.0

Conversation

@orenlab
Copy link
Owner

@orenlab orenlab commented Feb 13, 2026

No description provided.

orenlab added 30 commits June 8, 2025 18:17
…eatures are as follows. However, the code in this commit is not stable and contains errors and artifacts, making it unsuitable for productive use.

### Added

- **Circuit Breaker Pattern**:
    - Full circuit breaker implementation with `AsyncCircuitBreaker` class
    - Three states: CLOSED, OPEN, HALF_OPEN with automatic transitions
    - Configurable failure thresholds, recovery timeouts, and success thresholds
    - Sliding window failure rate calculation with exponential backoff
    - Event callbacks for state changes and call results monitoring
    - Health checker integration for automatic recovery detection
    - Background monitoring tasks for health checks and metrics cleanup

- **Advanced Health Monitoring**:
    - `HealthMonitoringMixin` for comprehensive health tracking
    - `OutlineHealthChecker` with cached health verification
    - `PerformanceMetrics` for detailed performance tracking
    - Real-time metrics collection: success rates, response times, circuit trips
    - Comprehensive health checks with individual component status
    - `health_check()` method with detailed metrics and circuit breaker status

- **Enhanced Configuration Management**:
    - `OutlineClientConfig` dataclass for immutable configuration
    - Environment variable loading with `from_env()` factory method
    - `.env` file support with automatic template generation
    - Comprehensive validation for all configuration parameters
    - `create_env_template()` utility for setup assistance
    - Configuration validation with detailed error messages

- **Batch Operations**:
    - `BatchOperationsMixin` with generic batch processor
    - `batch_create_access_keys()` for multiple key creation
    - `batch_delete_access_keys()` for bulk key deletion
    - `batch_rename_access_keys()` for mass key renaming
    - `batch_operations_with_resilience()` for custom batch operations
    - Configurable concurrency control and fail-fast options

- **Advanced Error Handling**:
    - Enhanced `ResponseParser` with detailed validation error formatting
    - Helpful error suggestions and context for common issues
    - Safe parsing with fallback to raw JSON on validation errors
    - Improved error messages with field paths and input values
    - Graceful handling of empty names and missing fields from API

- **Modular Architecture**:
    - Mixin-based design for clean separation of concerns
    - `ServerManagementMixin`, `MetricsMixin`, `AccessKeyMixin`, `DataLimitMixin`
    - Protocol-based type safety with `HTTPClientProtocol`
    - Enhanced type annotations with proper generic support

- **Enhanced Client Features**:
    - `create_resilient_client()` factory with conservative settings
    - `get_server_summary()` for comprehensive server overview
    - `wait_for_healthy_state()` for health state monitoring
    - Dynamic circuit breaker reconfiguration
    - Connection info and detailed status properties

- **Utility Functions**:
    - `quick_setup()` for interactive development setup
    - `get_version_info()` for package information
    - `create_config_template()` convenience wrapper
    - Interactive help display when imported in Python REPL
    - Comprehensive masking of sensitive data in logs

### Changed

- **Breaking Changes**:
    - Version bumped to 0.4.0 to reflect major feature additions
    - Client constructor now accepts many new parameters for circuit breaker and health monitoring
    - Default user agent updated to "PyOutlineAPI/0.4.0"
    - Enhanced error handling may change exception types in some edge cases

- **Enhanced Base Client**:
    - `BaseHTTPClient` now includes circuit breaker integration
    - Comprehensive logging setup without duplication
    - Enhanced session management with proper SSL context handling
    - Improved retry logic with circuit breaker awareness
    - Rate limiting support with configurable delays

- **Improved Type Safety**:
    - Better protocol definitions for HTTP client capabilities
    - Enhanced type hints with proper generic constraints
    - Improved overloads for response parsing methods
    - Stronger validation with `CommonValidators` utilities

- **Better Resource Management**:
    - Proper async context manager support throughout
    - Background task management in circuit breaker
    - Cleanup tasks for old metrics and call history
    - Enhanced session lifecycle management

- **Configuration Enhancements**:
    - All configuration now validated at initialization
    - Support for multiple environment variable prefixes
    - Comprehensive default values for all optional settings
    - Better error messages for configuration issues

### Fixed

- **Response Parsing**:
    - Better handling of empty name fields from Outline API
    - Improved validation error messages with actionable suggestions
    - Graceful fallback for unexpected response formats
    - Fixed handling of edge cases in metric responses

- **Connection Stability**:
    - Enhanced SSL certificate validation with proper error handling
    - Better handling of connection timeouts and retries
    - Improved cleanup of resources during failures
    - More robust session management

- **Logging**:
    - Eliminated duplicate log messages
    - Proper logger hierarchy setup
    - Configurable logging levels and formats
    - Performance-aware logging with conditional execution

- **Memory Management**:
    - Proper cleanup of circuit breaker background tasks
    - Sliding window size limits for call history
    - Weak references for callback management
    - Better resource cleanup in error scenarios

### Enhanced

- **Documentation**:
    - Comprehensive docstrings with usage examples
    - Better type annotations for IDE support
    - Enhanced error messages with troubleshooting hints
    - Interactive help and setup assistance

- **Developer Experience**:
    - Interactive setup with `quick_setup()` function
    - Automatic environment template creation
    - Better error messages for common configuration issues
    - Enhanced debugging capabilities with detailed metrics

- **Monitoring and Observability**:
    - Comprehensive performance metrics collection
    - Circuit breaker state monitoring with callbacks
    - Health check results with individual component status
    - Request/response time tracking and analysis
- code base optimization
- code refactoring
- new audit module
- multiple improvements in logic and performance
- a large number of utility methods for easier work with answers
- code base optimization
- code refactoring
- new audit module
- multiple improvements in logic and performance
- a large number of utility methods for easier work with answers
Multiple improvements in security, performance, and code quality (wop)
- code base optimization
- code refactoring
- new audit module
- multiple improvements in logic and performance
- a large number of utility methods for easier work with answers
- API Fix: Corrected DataLimit payload structure by wrapping it in a "limit" key as required by the Outline Server API (fixes issues with limits not being enforced).
- Security: Updated CredentialSanitizer regex to support complex API keys containing underscores, dashes, and dots (e.g., sk_live_ prefixes).
- Docs: Removed non-existent [metrics] dependency group from README and updated guides to reflect the latest changes.
- Tests: Synchronized model tests with the new API payload requirements.
json_format=True,
)
client = AsyncOutlineClient(config=config)
assert client.config.api_url.startswith("https://example.com")

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization

The string [https://example.com](1) may be at an arbitrary position in the sanitized URL.

Copilot Autofix

AI about 1 month ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

allow_private_networks=False,
resolve_dns=True,
)
assert url.startswith("https://example.com")

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization

The string [https://example.com](1) may be at an arbitrary position in the sanitized URL.

Copilot Autofix

AI about 1 month ago

In general, the way to fix this kind of problem is to avoid making security or correctness assertions about URLs using raw string substring/startswith/endswith checks. Instead, parse the URL using a standard library (urllib.parse.urlparse in Python) and assert on its structured components (scheme, hostname, port, path), or compare full canonical URLs when appropriate.

For this specific test, the safest and most precise fix that preserves existing functionality is to assert that the validated URL exactly matches the original URL string, rather than just checking that it starts with "https://example.com". The test currently wants to verify that when DNS resolution indicates a public IP address, Validators.validate_url returns a URL that begins with the expected host. If the validator is meant to return the input unchanged in this case (which is consistent with the other tests that do strict equality checks), then changing the assertion to assert url == "https://example.com" both avoids the problematic prefix check and tightens the test. This change is local to tests/test_common_types.py, around line 148, and requires no new imports or helpers.

Suggested changeset 1
tests/test_common_types.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/tests/test_common_types.py b/tests/test_common_types.py
--- a/tests/test_common_types.py
+++ b/tests/test_common_types.py
@@ -145,7 +145,7 @@
         allow_private_networks=False,
         resolve_dns=True,
     )
-    assert url.startswith("https://example.com")
+    assert url == "https://example.com"
 
 
 def test_validate_url_strict_ssrf_rebinding_guard(monkeypatch):
EOF
@@ -145,7 +145,7 @@
allow_private_networks=False,
resolve_dns=True,
)
assert url.startswith("https://example.com")
assert url == "https://example.com"


def test_validate_url_strict_ssrf_rebinding_guard(monkeypatch):
Copilot is powered by AI and may make mistakes. Always verify output.
allow_private_networks=False,
resolve_dns=True,
)
assert url.startswith("https://example.com")

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization

The string [https://example.com](1) may be at an arbitrary position in the sanitized URL.

Copilot Autofix

AI about 1 month ago

In general, to avoid incomplete URL substring sanitization, you should parse the URL and inspect its structured components (like hostname and scheme) rather than relying on substring or naive prefix checks. For domains, ensure that you either match exactly or correctly handle subdomains (for example, require hostname == "example.com" or hostname.endswith(".example.com") depending on the policy).

For this specific test, instead of asserting that the sanitized URL “starts with” the string "https://example.com", we should parse the returned url and assert on its structural parts: the scheme must be https and the hostname must be example.com. This keeps the test’s underlying intent (“the validated URL is an https URL to example.com”) while avoiding substring logic. Since this is a test file and we should not assume anything about other modules, we’ll add a local import of urllib.parse.urlparse in this file (or reuse it if already imported elsewhere in the snippet) and modify only the assertion at line 199.

Concretely:

  • In tests/test_common_types.py, around lines 194–199, replace assert url.startswith("https://example.com") with code that:
    • imports urlparse from urllib.parse at the top of the file if not already present.
    • parses url with urlparse(url).
    • asserts parsed.scheme == "https" and parsed.hostname == "example.com".
      This change keeps the semantics of the test while aligning with the recommendation to work with parsed URLs, and it does not alter the external behavior of Validators.validate_url.
Suggested changeset 1
tests/test_common_types.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/tests/test_common_types.py b/tests/test_common_types.py
--- a/tests/test_common_types.py
+++ b/tests/test_common_types.py
@@ -2,6 +2,7 @@
 
 import time
 from datetime import datetime, timezone
+from urllib.parse import urlparse
 
 import pytest
 
@@ -196,7 +197,9 @@
         allow_private_networks=False,
         resolve_dns=True,
     )
-    assert url.startswith("https://example.com")
+    parsed = urlparse(url)
+    assert parsed.scheme == "https"
+    assert parsed.hostname == "example.com"
 
 
 def test_validate_url_strict_ssrf_blocks_mixed_ipv6(monkeypatch):
EOF
@@ -2,6 +2,7 @@

import time
from datetime import datetime, timezone
from urllib.parse import urlparse

import pytest

@@ -196,7 +197,9 @@
allow_private_networks=False,
resolve_dns=True,
)
assert url.startswith("https://example.com")
parsed = urlparse(url)
assert parsed.scheme == "https"
assert parsed.hostname == "example.com"


def test_validate_url_strict_ssrf_blocks_mixed_ipv6(monkeypatch):
Copilot is powered by AI and may make mistakes. Always verify output.
env_file = tmp_path / ".env"
_write_env(env_file)
config = OutlineClientConfig.from_env(env_file=env_file)
assert config.api_url.startswith("https://example.com")

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization

The string [https://example.com](1) may be at an arbitrary position in the sanitized URL.

Copilot Autofix

AI about 1 month ago

In general, the fix is to avoid using substring or prefix/suffix checks on the raw URL string to validate what host it points to. Instead, parse the URL and assert on structured components such as the scheme and hostname. In this test, we should not assert that the URL merely “starts with” "https://example.com"; we should instead ensure that config.api_url is exactly the expected URL string, or else inspect its parsed components.

The most direct, non‑behavior‑changing fix here is:

  • Keep _write_env and the value it writes (https://example.com/secret) unchanged.
  • In test_from_env_and_sanitized, replace assert config.api_url.startswith("https://example.com") with a stronger assertion like assert config.api_url == "https://example.com/secret". This exactly matches what _write_env set, removes substring logic, and retains the intended semantics (the configuration should reflect the environment variable).
  • Similarly, in test_from_env_str_path, replace assert config.api_url.startswith("https://example.com") with assert config.api_url == "https://example.com/secret".

No new methods or classes are needed. We don’t need to import any URL parsing libraries because we can use equality against the known constant string written in the env file. All required edits are confined to tests/test_config.py around lines 34–35 and 45–46.

Suggested changeset 1
tests/test_config.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/tests/test_config.py b/tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -31,7 +31,7 @@
     env_file = tmp_path / ".env"
     _write_env(env_file)
     config = OutlineClientConfig.from_env(env_file=env_file)
-    assert config.api_url.startswith("https://example.com")
+    assert config.api_url == "https://example.com/secret"
     assert config.timeout == 15
     sanitized = config.get_sanitized_config
     assert sanitized["cert_sha256"] == "***MASKED***"
@@ -42,7 +42,7 @@
     env_file = tmp_path / ".env"
     _write_env(env_file)
     config = OutlineClientConfig.from_env(env_file=str(env_file))
-    assert config.api_url.startswith("https://example.com")
+    assert config.api_url == "https://example.com/secret"
 
 
 def test_create_minimal():
EOF
@@ -31,7 +31,7 @@
env_file = tmp_path / ".env"
_write_env(env_file)
config = OutlineClientConfig.from_env(env_file=env_file)
assert config.api_url.startswith("https://example.com")
assert config.api_url == "https://example.com/secret"
assert config.timeout == 15
sanitized = config.get_sanitized_config
assert sanitized["cert_sha256"] == "***MASKED***"
@@ -42,7 +42,7 @@
env_file = tmp_path / ".env"
_write_env(env_file)
config = OutlineClientConfig.from_env(env_file=str(env_file))
assert config.api_url.startswith("https://example.com")
assert config.api_url == "https://example.com/secret"


def test_create_minimal():
Copilot is powered by AI and may make mistakes. Always verify output.
env_file = tmp_path / ".env"
_write_env(env_file)
config = OutlineClientConfig.from_env(env_file=str(env_file))
assert config.api_url.startswith("https://example.com")

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization

The string [https://example.com](1) may be at an arbitrary position in the sanitized URL.

Copilot Autofix

AI about 1 month ago

General approach: Instead of checking whether the URL string starts with "https://example.com", parse the URL and assert on its components (e.g., scheme and hostname). This aligns with the recommendation to parse URLs before checking host values and avoids any substring-based assumptions.

Best specific fix here: In tests/test_config.py, update the assertions on config.api_url that use .startswith("https://example.com") to instead:

  1. Parse config.api_url with urllib.parse.urlparse.
  2. Assert that parsed.scheme == "https" and parsed.hostname == "example.com".

Because the tests are the only code we’re allowed to change and they already import only standard libraries plus project modules, we can safely add an import of urlparse from urllib.parse at the top of this test module.

Concretely:

  • Add from urllib.parse import urlparse near the other imports at the top of tests/test_config.py.
  • In test_from_env_and_sanitized, replace assert config.api_url.startswith("https://example.com") with a urlparse call and assertions on scheme and hostname.
  • In test_from_env_str_path, similarly replace the .startswith assertion with the parsed-url assertions.

This preserves the intent of the tests (ensuring the configuration URL targets https://example.com) while removing substring-based URL checks.


Suggested changeset 1
tests/test_config.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/tests/test_config.py b/tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -2,6 +2,7 @@
 
 import logging
 from pathlib import Path
+from urllib.parse import urlparse
 
 import pytest
 from pydantic import SecretStr
@@ -31,7 +32,9 @@
     env_file = tmp_path / ".env"
     _write_env(env_file)
     config = OutlineClientConfig.from_env(env_file=env_file)
-    assert config.api_url.startswith("https://example.com")
+    parsed = urlparse(config.api_url)
+    assert parsed.scheme == "https"
+    assert parsed.hostname == "example.com"
     assert config.timeout == 15
     sanitized = config.get_sanitized_config
     assert sanitized["cert_sha256"] == "***MASKED***"
@@ -42,7 +45,9 @@
     env_file = tmp_path / ".env"
     _write_env(env_file)
     config = OutlineClientConfig.from_env(env_file=str(env_file))
-    assert config.api_url.startswith("https://example.com")
+    parsed = urlparse(config.api_url)
+    assert parsed.scheme == "https"
+    assert parsed.hostname == "example.com"
 
 
 def test_create_minimal():
EOF
@@ -2,6 +2,7 @@

import logging
from pathlib import Path
from urllib.parse import urlparse

import pytest
from pydantic import SecretStr
@@ -31,7 +32,9 @@
env_file = tmp_path / ".env"
_write_env(env_file)
config = OutlineClientConfig.from_env(env_file=env_file)
assert config.api_url.startswith("https://example.com")
parsed = urlparse(config.api_url)
assert parsed.scheme == "https"
assert parsed.hostname == "example.com"
assert config.timeout == 15
sanitized = config.get_sanitized_config
assert sanitized["cert_sha256"] == "***MASKED***"
@@ -42,7 +45,9 @@
env_file = tmp_path / ".env"
_write_env(env_file)
config = OutlineClientConfig.from_env(env_file=str(env_file))
assert config.api_url.startswith("https://example.com")
parsed = urlparse(config.api_url)
assert parsed.scheme == "https"
assert parsed.hostname == "example.com"


def test_create_minimal():
Copilot is powered by AI and may make mistakes. Always verify output.
@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 13, 2026

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.1% Duplication on New Code

See analysis details on SonarQube Cloud

@codecov
Copy link

codecov bot commented Feb 13, 2026

Codecov Report

❌ Patch coverage is 97.83359% with 69 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pyoutlineapi/audit.py 92.88% 8 Missing and 11 partials ⚠️
pyoutlineapi/client.py 95.63% 0 Missing and 12 partials ⚠️
pyoutlineapi/metrics_collector.py 97.06% 0 Missing and 10 partials ⚠️
pyoutlineapi/circuit_breaker.py 95.31% 0 Missing and 9 partials ⚠️
pyoutlineapi/base_client.py 98.19% 1 Missing and 6 partials ⚠️
pyoutlineapi/common_types.py 98.78% 0 Missing and 4 partials ⚠️
pyoutlineapi/health_monitoring.py 98.81% 0 Missing and 3 partials ⚠️
pyoutlineapi/response_parser.py 96.80% 0 Missing and 3 partials ⚠️
pyoutlineapi/exceptions.py 99.50% 0 Missing and 1 partial ⚠️
pyoutlineapi/models.py 99.55% 0 Missing and 1 partial ⚠️
Files with missing lines Coverage Δ
pyoutlineapi/__init__.py 100.00% <100.00%> (+14.28%) ⬆️
pyoutlineapi/api_mixins.py 100.00% <100.00%> (ø)
pyoutlineapi/batch_operations.py 100.00% <100.00%> (ø)
pyoutlineapi/config.py 100.00% <100.00%> (ø)
pyoutlineapi/exceptions.py 99.50% <99.50%> (-0.50%) ⬇️
pyoutlineapi/models.py 99.56% <99.55%> (+8.47%) ⬆️
pyoutlineapi/health_monitoring.py 98.81% <98.81%> (ø)
pyoutlineapi/response_parser.py 96.80% <96.80%> (ø)
pyoutlineapi/common_types.py 98.78% <98.78%> (ø)
pyoutlineapi/base_client.py 98.19% <98.19%> (ø)
... and 4 more

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant