Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,106 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- TBD

## [0.2.0] - 2026-04-13

# 📦 CertMonitor v0.2.0 – Dynamic Validator Args & sensitive_date validator

**Release Date:** April 13, 2026
**Repository:** [bradh11/certmonitor](https://github.com/bradh11/certmonitor)

---

## 🚀 Overview

CertMonitor v0.2.0 overhauls how validators receive arguments. New validators can now declare their user arguments directly on the `validate()` method signature — the dispatcher discovers them automatically and no core changes are needed. As part of the same effort, the `sensitive_date` validator — which has been sitting on `develop` since #15 back in June 2025 — finally makes it into a release, and gets ergonomic input forms, a structured match field, and structured error handling along the way.

This is a **minor version bump** to reflect the scale of the changes, not because of any hard break in the public API. Existing callers using `validator_args={"subject_alt_names": [...]}` still work with a `DeprecationWarning`, and no validator output shape has changed for users.

---

## ✨ Added

- **Dynamic validator argument dispatch** ([#18](https://github.com/bradh11/certmonitor/issues/18)): validators declare their user-configurable arguments directly on the `validate()` method signature, and `CertMonitor.validate(validator_args=...)` discovers them automatically. New validators get argument passing for free — zero core changes needed.
- **`CertMonitor.describe_validators()`**: new introspection helper that returns every registered validator's name, docstring, and argument schema (name, annotation, default). Useful for building CLI `--help` pages, config validators, or dashboards.
- **`sensitive_date` validator** finally ships: flags certificates that expire on weekends, leap days, or user-specified dates (e.g. Black Friday, Cyber Monday, go-live dates).
- **`sensitive_date` input ergonomics**: the `dates` argument accepts `SensitiveDate` named tuples, plain `date` / `datetime` values, ISO 8601 strings (`"2025-12-25"`), or `(name, date)` tuples — all mixable in a single call. No need to import `SensitiveDate` from a deeply nested module path just to pass a list of blackout dates.
- **`sensitive_date_matches` structured field**: matching sensitive dates are surfaced as a machine-readable list of `{"name", "date"}` entries in addition to the existing human-readable `warnings` strings.
- **Weekend / leap-day warning strings**: when the `sensitive_date` validator flags a weekend or leap-day expiry, a human-readable warning line is now emitted alongside the existing boolean fields, so log output is self-explanatory when `is_valid` is false.
- **Shared `parse_not_after` helper** (`certmonitor/validators/_utils.py`): centralizes the `notAfter` format string shared by `expiration` and `sensitive_date`.

---

## 🔄 Changed

- **Validator author contract**: user arguments on `validate()` must be keyword-only, type-annotated, and have a default value. Enforcement runs in `BaseCertValidator` / `BaseCipherValidator` `__init_subclass__` at import time, so a malformed validator raises `TypeError` the moment its module is imported. No user-facing impact — every built-in validator conforms, and the dispatcher continues to accept the pre-0.2.0 `validator_args` call style via a deprecation shim.
- **`subject_alt_names` and `sensitive_date` signatures** migrated to keyword-only user arguments (`alternate_names=...`, `dates=...`). Existing users of `monitor.validate(validator_args={...})` are unaffected; callers invoking the validator classes directly with positional arguments need the keyword form.
- **`validator_args` canonical form** is now a nested dict: `validator_args={"subject_alt_names": {"alternate_names": [...]}}`. The pre-0.2.0 bare-list form still works and is transparently rewritten by the dispatcher — with a `DeprecationWarning` — so no user code needs to change immediately.
- **`sensitive_date` error handling**: malformed `dates` input (wrong type, invalid ISO string, bad tuple shape) now returns a structured error dict instead of raising `TypeError`, matching the rest of the validator suite.
- **`expiration` validator**: now uses the shared `parse_not_after` helper; behavior unchanged.
- **`mkdocs.yml`**: added the previously-missing `SensitiveDate` nav entry so the validator's auto-generated reference page is reachable.
- **`docs/usage/validator_args.md`**: rewritten to document the canonical nested-dict form, `describe_validators()`, the bare-list deprecation, and a worked `sensitive_date` example showing all four input forms.
- **Rust toolchain floor** moved to `rustc >= 1.88.0` (transitively via the `time 0.3.47` security bump, see below). Affects contributors and source builds only — published wheels are unaffected.

---

## ⚠️ Deprecated

- **Bare-list shorthand for single-argument validators** (`validator_args={"subject_alt_names": [...]}`) still works but now emits a `DeprecationWarning`. Migrate to the canonical nested-dict form. Scheduled for removal in a future release.

---

## 🔒 Security

- **RUSTSEC-2026-0009**: bumped the `time` crate from `0.3.41` to `0.3.47` (transitively via `x509-parser`) to address the denial-of-service-via-stack-exhaustion advisory.

---

## 🛠️ Fixed

- **`subject_alt_names` core dispatch**: the hardcoded `if validator.name == "subject_alt_names"` special case in `core.validate()` is gone — replaced with the generic argument-resolution helper used by every validator.
- **`CHANGELOG.md`**: backfilled the missing `[0.1.4]` section from the published release notes so the historical record is complete.

---

## 📚 Documentation

Comprehensive documentation is available at [certmonitor.readthedocs.io](https://certmonitor.readthedocs.io/).

---

## 🐍 Python Compatibility

Tested with Python 3.8 and above with 98%+ code coverage across all supported versions.

---

## 📝 License

This project is licensed under the MIT License. See the [LICENSE](https://github.com/bradh11/certmonitor/blob/main/LICENSE) file for details.

**Full Changelog**: https://github.com/bradh11/certmonitor/compare/v0.1.4...v0.2.0

## [0.1.4] - 2025-06-02

Focus: test coverage and CI optimization ([#16](https://github.com/bradh11/certmonitor/issues/16)).

### Added
- Achieved 99% test coverage (up from 95%) with comprehensive edge case testing.
- Instance convenience methods for improved developer experience:
- `monitor.get_enabled_validators()` — get validators enabled for this specific instance.
- `monitor.list_validators()` — get all available validators.
- Enhanced test suite with 323 tests covering all edge cases.

### Changed
- Streamlined security scanning: removed heavy semgrep dependency, kept focused bandit scanning.
- Improved test descriptions — removed line-number references for maintainable, functionality-focused tests.
- Enhanced validator configuration: proper distinction between empty lists vs config defaults.

### Fixed
- Default validator behavior: `enabled_validators=[]` now properly means "no validators", vs `None` meaning "use defaults" (see [#16](https://github.com/bradh11/certmonitor/issues/16)).
- Configuration environment handling: proper string parsing for the `ENABLED_VALIDATORS` environment variable.
- Test coverage gaps — targeted testing for previously uncovered edge cases: SSL handler retry exception scenarios, certificate parsing fallback mechanisms, handler-None conditions in raw data operations, and public key parsing error paths.

## [0.1.3] - 2025-05-25

### Added
Expand Down
52 changes: 52 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Contributor Code of Conduct

As contributors and maintainers of the CertMonitor project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

## Our Pledge

- We pledge to be respectful to all contributors, users, and maintainers of this project.
- We are committed to making participation in this project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others’ private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting

## Responsible Use

CertMonitor is designed for legitimate, ethical, and legal use only.
**This library must not be used for malicious, unlawful, or unethical purposes, including but not limited to unauthorized surveillance, data theft, or any activity that violates privacy, security, or applicable laws.**
By contributing to or using this project, you agree to use it responsibly and in good faith.

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainer at [bradh11@gmail.com](mailto:bradh11@gmail.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4.

[homepage]: https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
34 changes: 17 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "certinfo"
version = "0.1.4"
version = "0.2.0"
edition = "2021"

[lib]
Expand Down
36 changes: 19 additions & 17 deletions MODULARIZATION_REPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@

### Test Modularization Status
- **Modular test files:** 8 files
- **Total test lines:** 1,744 lines
- **Average file size:** 218 lines
- **Total test lines:** 1,932 lines
- **Average file size:** 241 lines
- **Main test file:** 22 lines

### Test Coverage
- **Overall coverage:** 98.5%
- **Total tests:** 323
- **Statements covered:** 723/734
- **Files with coverage:** 19
- **Overall coverage:** 98.7%
- **Total tests:** 360
- **Statements covered:** 852/863
- **Files with coverage:** 21

### Type Hint Coverage
- **Files analyzed:** 16
- **Files with type hints:** 14
- **Type hint coverage:** 87.5%
- **Files analyzed:** 18
- **Files with type hints:** 16
- **Type hint coverage:** 88.9%

### Code Quality
- **Ruff issues:** 0
Expand All @@ -29,8 +29,8 @@
- **Rust vulnerabilities found:** 0
- **Python security scanning:** ✅ Enabled
- **Python security issues found:** 0
- **Files scanned by bandit:** 19
- **Lines scanned by bandit:** 1,657
- **Files scanned by bandit:** 21
- **Lines scanned by bandit:** 2,002
- **Overall security status:** 🔒 Clean
- **PyO3 version:** 0.24.1

Expand All @@ -47,11 +47,11 @@

### Modular Test Files
- **test_certificate_operations.py**: 401 lines, 23 functions
- **test_validation.py**: 301 lines, 12 functions
- **test_validation.py**: 424 lines, 17 functions
- **test_public_key_operations.py**: 211 lines, 12 functions
- **test_initialization.py**: 209 lines, 17 functions
- **test_raw_data_operations.py**: 70 lines, 4 functions
- **test_utility_methods.py**: 74 lines, 4 functions
- **test_utility_methods.py**: 139 lines, 11 functions
- **test_connection_management.py**: 315 lines, 20 functions
- **test_cipher_operations.py**: 163 lines, 9 functions

Expand All @@ -64,21 +64,23 @@

### Files with Type Hints
- **config.py**: ❌ (14 lines)
- **core.py**: ✅ (658 lines)
- **core.py**: ✅ (772 lines)
- **error_handlers.py**: ✅ (29 lines)
- **cipher_algorithms.py**: ✅ (145 lines)
- **protocol_handlers/ssl_handler.py**: ✅ (193 lines)
- **protocol_handlers/ssh_handler.py**: ✅ (77 lines)
- **protocol_handlers/base.py**: ✅ (28 lines)
- **utils/utils.py**: ❌ (1 lines)
- **validators/weak_cipher.py**: ✅ (68 lines)
- **validators/subject_alt_names.py**: ✅ (238 lines)
- **validators/expiration.py**: ✅ (88 lines)
- **validators/sensitive_date.py**: ✅ (204 lines)
- **validators/subject_alt_names.py**: ✅ (239 lines)
- **validators/expiration.py**: ✅ (87 lines)
- **validators/root_certificate_validator.py**: ✅ (113 lines)
- **validators/tls_version.py**: ✅ (70 lines)
- **validators/key_info.py**: ✅ (106 lines)
- **validators/base.py**: ✅ (55 lines)
- **validators/base.py**: ✅ (141 lines)
- **validators/hostname.py**: ✅ (148 lines)
- **validators/_utils.py**: ✅ (23 lines)

---

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ You can enable, disable, or extend validators to fit your needs, making CertMoni
- `key_info`: Validates the public key type and strength.
- `tls_version`: Validates the negotiated TLS version.
- `weak_cipher`: Validates that the negotiated cipher suite is in the allowed list.
- `sensitive_date`: Validates that the certificate doesn't expire on built-in or user specified sensitive dates.

---

Expand Down
Loading
Loading