forked from cleveragents/cleveragents-core
8c81f13758
The TLS handshake failure on git.dev.cleveragents.com was caused by the hostname being absent from the certificate's Subject Alternative Names (SANs), or by SNI virtual-host misconfiguration on the server side. This commit delivers the repository-side remediation: - scripts/check-tls-cert.py: New TLS certificate health-check script. Connects to a hostname, verifies the certificate's SANs include the target hostname, checks expiry, and reports errors/warnings. Accepts an injectable SSLContext for unit testing without real network access. Supports wildcard SAN matching and configurable expiry warning threshold. - docs/development/ops-runbook.md: New ops runbook documenting the full certificate renewal procedure (Let's Encrypt/certbot and manual CA), SNI misconfiguration diagnosis steps, expiry monitoring with cron, and recommended alert thresholds (30/14/7/0 days). - features/tls_certificate_check.feature: 14 Behave scenarios tagged @tdd_issue @tdd_issue_1543 covering: missing SAN detection, valid SAN acceptance, expired certificate detection, expiry warning threshold, TLS handshake errors, connection timeouts, connection refused, wildcard SAN matching, and _hostname_matches_san unit tests. - features/steps/tls_certificate_check_steps.py: Step definitions for the above feature, using unittest.mock to inject SSL contexts and socket connections so no real network calls are made. - mkdocs.yml: Added Ops Runbook to the Development section navigation. The actual server-side certificate renewal (adding git.dev.cleveragents.com as a SAN and reloading the web server) must be performed by the server administrator following the procedure in docs/development/ops-runbook.md. Closes #1543 ISSUES CLOSED: #1543
111 lines
5.6 KiB
Gherkin
111 lines
5.6 KiB
Gherkin
Feature: TLS certificate health-check script
|
|
The ``scripts/check-tls-cert.py`` script inspects TLS certificates for
|
|
CleverAgents infrastructure hostnames and reports errors, warnings, and
|
|
certificate metadata. These scenarios exercise the script's core logic
|
|
using injected SSL contexts so no real network connections are made.
|
|
|
|
# ── Regression tests for issue #1543 ──────────────────────────────────
|
|
# The TLS handshake failure on git.dev.cleveragents.com was caused by the
|
|
# hostname being absent from the certificate's Subject Alternative Names
|
|
# (SANs). The scenarios below verify that the check script correctly
|
|
# detects this condition and reports it as an error.
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: Script detects missing SAN for git.dev.cleveragents.com
|
|
Given a TLS certificate for "git.cleverthis.com" with SANs "git.cleverthis.com,git.cleveragents.com"
|
|
And the certificate expires in 90 days
|
|
When the TLS check runs for hostname "git.dev.cleveragents.com"
|
|
Then the check result should be a failure
|
|
And the check error should mention "not found in certificate SANs"
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: Script passes when hostname is present in SANs
|
|
Given a TLS certificate for "git.cleverthis.com" with SANs "git.cleverthis.com,git.dev.cleveragents.com"
|
|
And the certificate expires in 90 days
|
|
When the TLS check runs for hostname "git.dev.cleveragents.com"
|
|
Then the check result should be a success
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: Script detects expired certificate
|
|
Given a TLS certificate for "git.cleverthis.com" with SANs "git.cleverthis.com,git.dev.cleveragents.com"
|
|
And the certificate expired 5 days ago
|
|
When the TLS check runs for hostname "git.dev.cleveragents.com"
|
|
Then the check result should be a failure
|
|
And the check error should mention "expired"
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: Script warns when certificate expires within threshold
|
|
Given a TLS certificate for "git.cleverthis.com" with SANs "git.cleverthis.com,git.dev.cleveragents.com"
|
|
And the certificate expires in 15 days
|
|
When the TLS check runs for hostname "git.dev.cleveragents.com" with warn-days 30
|
|
Then the check result should be a success
|
|
And the check warning should mention "expires in"
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: Script does not warn when certificate expires beyond threshold
|
|
Given a TLS certificate for "git.cleverthis.com" with SANs "git.cleverthis.com,git.dev.cleveragents.com"
|
|
And the certificate expires in 60 days
|
|
When the TLS check runs for hostname "git.dev.cleveragents.com" with warn-days 30
|
|
Then the check result should be a success
|
|
And the check has no warnings
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: Script reports TLS handshake failure as an error
|
|
Given the TLS connection raises an SSLError "CERTIFICATE_VERIFY_FAILED"
|
|
When the TLS check runs for hostname "git.dev.cleveragents.com"
|
|
Then the check result should be a failure
|
|
And the check error should mention "TLS"
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: Script reports connection timeout as an error
|
|
Given the TLS connection times out
|
|
When the TLS check runs for hostname "git.dev.cleveragents.com"
|
|
Then the check result should be a failure
|
|
And the check error should mention "timed out"
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: Script reports connection refused as an error
|
|
Given the TLS connection is refused
|
|
When the TLS check runs for hostname "git.dev.cleveragents.com"
|
|
Then the check result should be a failure
|
|
And the check error should mention "Connection failed"
|
|
|
|
# ── Wildcard SAN matching ──────────────────────────────────────────────
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: Script accepts wildcard SAN matching the hostname
|
|
Given a TLS certificate for "git.cleverthis.com" with SANs "*.cleverthis.com"
|
|
And the certificate expires in 90 days
|
|
When the TLS check runs for hostname "git.cleverthis.com"
|
|
Then the check result should be a success
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: Script rejects wildcard SAN that does not match the hostname
|
|
Given a TLS certificate for "git.cleverthis.com" with SANs "*.cleveragents.com"
|
|
And the certificate expires in 90 days
|
|
When the TLS check runs for hostname "git.cleverthis.com"
|
|
Then the check result should be a failure
|
|
And the check error should mention "not found in certificate SANs"
|
|
|
|
# ── Helper function unit tests ─────────────────────────────────────────
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: _hostname_matches_san returns True for exact match
|
|
When I check if hostname "git.dev.cleveragents.com" matches SANs "git.dev.cleveragents.com,git.cleveragents.com"
|
|
Then the SAN match result should be True
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: _hostname_matches_san returns False when hostname is absent
|
|
When I check if hostname "git.dev.cleveragents.com" matches SANs "git.cleveragents.com,git.cleverthis.com"
|
|
Then the SAN match result should be False
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: _hostname_matches_san handles wildcard SANs correctly
|
|
When I check if hostname "git.cleverthis.com" matches SANs "*.cleverthis.com"
|
|
Then the SAN match result should be True
|
|
|
|
@tdd_issue @tdd_issue_1543
|
|
Scenario: _hostname_matches_san rejects multi-level wildcard
|
|
When I check if hostname "a.b.cleverthis.com" matches SANs "*.cleverthis.com"
|
|
Then the SAN match result should be False
|