fix(seo-audit): Add SSL certificate check to SEO audit script
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions

seo_audit.py was missing SSL columns (has_ssl, ssl_expires_at,
ssl_issuer) in its INSERT/UPDATE query, causing all SEO-audited
companies to show has_ssl=false regardless of actual certificate status.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-02-13 10:58:00 +01:00
parent 893687f577
commit 7b2c4ce739

View File

@ -32,6 +32,8 @@ import os
import sys
import re
import json
import ssl
import socket
import argparse
import logging
import time as time_module
@ -930,6 +932,9 @@ class SEOAuditor:
has_sitemap, has_robots_txt,
viewport_configured, is_mobile_friendly,
-- SSL
has_ssl, ssl_expires_at, ssl_issuer,
-- Core Web Vitals
largest_contentful_paint_ms, interaction_to_next_paint_ms, cumulative_layout_shift,
@ -974,6 +979,8 @@ class SEOAuditor:
:has_sitemap, :has_robots_txt,
:viewport_configured, :is_mobile_friendly,
:has_ssl, :ssl_expires_at, :ssl_issuer,
:largest_contentful_paint_ms, :interaction_to_next_paint_ms, :cumulative_layout_shift,
:has_og_tags, :og_title, :og_description, :og_image,
@ -1032,6 +1039,10 @@ class SEOAuditor:
viewport_configured = EXCLUDED.viewport_configured,
is_mobile_friendly = EXCLUDED.is_mobile_friendly,
has_ssl = EXCLUDED.has_ssl,
ssl_expires_at = EXCLUDED.ssl_expires_at,
ssl_issuer = EXCLUDED.ssl_issuer,
largest_contentful_paint_ms = EXCLUDED.largest_contentful_paint_ms,
interaction_to_next_paint_ms = EXCLUDED.interaction_to_next_paint_ms,
cumulative_layout_shift = EXCLUDED.cumulative_layout_shift,
@ -1069,6 +1080,36 @@ class SEOAuditor:
last_content_update = EXCLUDED.last_content_update
""")
# Check SSL certificate
ssl_info = {'has_ssl': False, 'ssl_expires_at': None, 'ssl_issuer': None}
website_url = result.get('website_url', '')
try:
from urllib.parse import urlparse
parsed = urlparse(website_url or result.get('final_url', ''))
domain = parsed.hostname
if domain:
ctx = ssl.create_default_context()
with socket.create_connection((domain, 443), timeout=10) as sock:
with ctx.wrap_socket(sock, server_hostname=domain) as ssock:
cert = ssock.getpeercert()
ssl_info['has_ssl'] = True
not_after = cert.get('notAfter')
if not_after:
ssl_info['ssl_expires_at'] = datetime.strptime(
not_after, '%b %d %H:%M:%S %Y %Z'
).date()
issuer = cert.get('issuer')
if issuer:
issuer_dict = {}
for item in issuer:
for key, value in item:
issuer_dict[key] = value
ssl_info['ssl_issuer'] = (
issuer_dict.get('organizationName') or issuer_dict.get('commonName') or ''
)[:100]
except Exception:
pass # SSL check failed — has_ssl stays False
# Build issues list from errors
issues = []
for error in result.get('errors', []):
@ -1125,6 +1166,11 @@ class SEOAuditor:
'viewport_configured': bool(meta_tags.get('viewport')),
'is_mobile_friendly': 'width=device-width' in (meta_tags.get('viewport') or '').lower(),
# SSL
'has_ssl': ssl_info['has_ssl'],
'ssl_expires_at': ssl_info['ssl_expires_at'],
'ssl_issuer': ssl_info['ssl_issuer'],
# Core Web Vitals
'largest_contentful_paint_ms': cwv.get('lcp_ms'),
'interaction_to_next_paint_ms': cwv.get('inp_ms'),