From c5b7b9f5b8e4c114eed9af9d8634965ac57778be Mon Sep 17 00:00:00 2001 From: Paul Huliganga Date: Thu, 23 Apr 2026 09:51:20 -0400 Subject: [PATCH] fix: resolve latent bugs found in code review - Fix ValueError crash in migrate_template.py and migrate_paul_template.py: compose_template() returns a 3-tuple since Phase 23 but both CLI scripts were still unpacking 2 values - Fix ImportError in bulk-send/bulk_send.py: replace non-existent auth_helper import with docusign_auth.get_access_token via sys.path - Activate log sanitizer at web app startup so tokens never appear in logs - Log a warning at startup when SESSION_SECRET_KEY is the default dev value - Add reportlab to requirements.txt (used by generate_pdfs.py, was missing) - Move asyncio import from bottom of templates.py to top where it belongs - Correct stale coordinate comment in generate_pdfs.py (both platforms use top-left origin; the comment incorrectly described bottom-left inversion) Co-Authored-By: Claude Sonnet 4.6 --- bulk-send/bulk_send.py | 5 ++++- requirements.txt | 3 +++ src/generate_pdfs.py | 6 +++--- src/migrate_paul_template.py | 2 +- src/migrate_template.py | 2 +- web/app.py | 15 +++++++++++++++ web/routers/templates.py | 5 +---- 7 files changed, 28 insertions(+), 10 deletions(-) diff --git a/bulk-send/bulk_send.py b/bulk-send/bulk_send.py index 15b101d..1b20e17 100644 --- a/bulk-send/bulk_send.py +++ b/bulk-send/bulk_send.py @@ -13,12 +13,15 @@ DocuSign API reference: """ import os +import sys import csv import json import argparse import requests from dotenv import load_dotenv -from auth_helper import get_access_token # reuses existing JWT auth + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) +from docusign_auth import get_access_token load_dotenv() diff --git a/requirements.txt b/requirements.txt index 22aa7f4..18dedc8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,9 @@ uvicorn[standard] itsdangerous httpx +# PDF generation (sample template tooling) +reportlab + # Testing responses respx diff --git a/src/generate_pdfs.py b/src/generate_pdfs.py index 85823ce..edc8e4c 100644 --- a/src/generate_pdfs.py +++ b/src/generate_pdfs.py @@ -6,9 +6,9 @@ Generates realistic sample PDFs for adobe-to-docusign migration testing. Each PDF mirrors the form fields described in the matching *-formfields.json so that tab positions map to visible labels on the document. -Adobe rect coordinates are top-left origin; DocuSign yPosition is bottom-left. -Formula: docusign_y = PAGE_HEIGHT - adobe_top - adobe_height -To place a *label* just above a field: label_y = PAGE_HEIGHT - adobe_top + 2 +Both Adobe Sign and DocuSign use top-left origin with y increasing downward — no +coordinate inversion is needed. DocuSign xPosition = adobe left, yPosition = adobe top. +To place a *label* just above a field in this PDF: label_y = page_height - adobe_top + 2 """ import base64 diff --git a/src/migrate_paul_template.py b/src/migrate_paul_template.py index 3fc7f21..8a2f284 100644 --- a/src/migrate_paul_template.py +++ b/src/migrate_paul_template.py @@ -115,7 +115,7 @@ def run_migration(template_dir: Path) -> Path: output_path = MIGRATION_OUTPUT_DIR / template_dir.name / "docusign-template.json" print(f"\nRunning migration: {template_dir.name}") - template_dict, warnings = compose_template(str(template_dir), str(output_path)) + template_dict, warnings, field_issues = compose_template(str(template_dir), str(output_path)) print(f" Written: {output_path}") if warnings: diff --git a/src/migrate_template.py b/src/migrate_template.py index cd57305..a3116a9 100644 --- a/src/migrate_template.py +++ b/src/migrate_template.py @@ -121,7 +121,7 @@ def download_template(template) -> Path: def convert_template(template_dir: Path) -> Path: output_path = OUTPUT_DIR / template_dir.name / "docusign-template.json" print(f"\nConverting to DocuSign format...") - _, warnings = compose_template(str(template_dir), str(output_path)) + _, warnings, _ = compose_template(str(template_dir), str(output_path)) print(f" Written: {output_path}") for w in warnings: print(f" WARNING: {w}") diff --git a/web/app.py b/web/app.py index 4e3f42c..c389694 100644 --- a/web/app.py +++ b/web/app.py @@ -12,11 +12,26 @@ From the project root. from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse, HTMLResponse +import logging import os from web.config import settings from web.routers import auth, templates, migrate, verify, audit, admin +import sys +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) +from src.utils.log_sanitizer import install_sanitizing_filter + +install_sanitizing_filter() + +logger = logging.getLogger(__name__) + +_DEFAULT_SECRET = "dev-secret-change-in-production" +if settings.session_secret_key == _DEFAULT_SECRET: + logger.warning( + "SESSION_SECRET_KEY is using the default dev value — set a random secret in .env before exposing this app" + ) + app = FastAPI( title="Adobe Sign → DocuSign Migrator", version=settings.version, diff --git a/web/routers/templates.py b/web/routers/templates.py index 6b6ca63..ed5e2fe 100644 --- a/web/routers/templates.py +++ b/web/routers/templates.py @@ -5,6 +5,7 @@ Template listing endpoints for Adobe Sign and DocuSign. Computes per-template migration status for the side-by-side UI. """ +import asyncio from datetime import datetime, timezone from pathlib import Path import tempfile @@ -243,7 +244,3 @@ def _dedupe(items: list[str]) -> list[str]: seen.add(item) result.append(item) return result - - -# asyncio needed for gather — import at top of module -import asyncio