Files
ImpTune/tests/test_script_generator.py
T
kawaandClaude Haiku 4.5 ed41f7f520 feat(session): per-owner printer/config storage via cookie-scoped bearer key
Printers and groups (Client) are now scoped to an Owner identified by an opaque
bearer key (secrets.token_urlsafe(32)) stored in an httponly cookie, defaulting
to temporary. First-visit modal offers backup-key download (marks permanent) or
temporary-only choice. /session/restore re-attaches a fresh browser to a saved
key. Every printer-facing route enforces ownership (404 on mismatch, not just
filtering) since printer IDs are sequential ints. Drivers stay global/shared.

On upgrade, pre-existing printer/client rows backfill to a synthetic legacy Owner;
its key is written to {DATA_DIR}/legacy_owner_key.txt for manual restore.

SECURITY: Added Origin/Referer same-origin check on POST /session/restore to
block login-CSRF/session-fixation attacks (cross-site form POST can't re-point
victim's cookie at attacker's Owner without hitting that check first).

Tests: 140 pass (2 deselected: pre-existing locale-flaky, unrelated to this change).
Verified live: modal on first visit, isolation between browsers, backup-key
download and restore flow work end-to-end.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-04 11:29:43 +02:00

200 lines
7.3 KiB
Python

"""Unit tests for script_generator.py — SCRPT-01, SCRPT-02, SCRPT-03, SCRPT-04, SCRPT-05."""
import pytest
from imptune.generators.script_generator import render_detect, render_install, render_uninstall
def _create_test_driver_and_printer(owner):
"""Helper: create a Driver + Printer for integration tests."""
from imptune.db.models import Driver, Printer
driver = Driver.create(
sha256="abc123",
original_filename="test.zip",
size_bytes=100,
driver_desc='["Test Driver"]',
inf_filename="test.inf",
)
printer = Printer.create(
name="Test Printer",
ip_address="10.0.0.1",
port_name="IP_10.0.0.1",
driver=driver,
owner=owner,
duplex_mode="LongEdge",
color_mode=True,
paper_size="A4",
collate=True,
)
return driver, printer
SAMPLE_ARGS = dict(
printer_name="HP LaserJet 4000",
ip_address="192.168.1.10",
port_name="IP_192.168.1.10",
driver_name="HP Universal Printing PCL 6",
inf_filename="hpcu270u.inf",
duplex_mode="LongEdge",
color_mode=True,
paper_size="A4",
collate=True,
)
def test_render_install_returns_string():
"""render_install returns a non-empty string."""
result = render_install(**SAMPLE_ARGS)
assert isinstance(result, str)
assert len(result) > 0
def test_render_install_contains_pnputil():
"""SCRPT-01: Output contains pnputil /add-driver and Add-PrinterDriver."""
result = render_install(**SAMPLE_ARGS)
assert "pnputil.exe /add-driver" in result
assert "Add-PrinterDriver" in result
assert "hpcu270u.inf" in result
assert "HP Universal Printing PCL 6" in result
def test_render_install_print_config():
"""SCRPT-01: Set-PrintConfiguration with translated duplex mode."""
# LongEdge -> TwoSidedLongEdge
result = render_install(**SAMPLE_ARGS)
assert "Set-PrintConfiguration" in result
assert "TwoSidedLongEdge" in result
assert "A4" in result
# ShortEdge -> TwoSidedShortEdge
result_short = render_install(**{**SAMPLE_ARGS, "duplex_mode": "ShortEdge"})
assert "TwoSidedShortEdge" in result_short
# OneSided -> OneSided (no change)
result_one = render_install(**{**SAMPLE_ARGS, "duplex_mode": "OneSided"})
assert "OneSided" in result_one
# Must NOT contain the two-sided variants when OneSided
assert "TwoSided" not in result_one
def test_render_install_wow64_guard():
"""SCRPT-05: WOW64 relaunch guard is present in the output."""
result = render_install(**SAMPLE_ARGS)
assert "PROCESSOR_ARCHITECTURE" in result
assert "SysNative" in result
# Guard must appear near the top (before pnputil)
wow64_pos = result.find("PROCESSOR_ARCHITECTURE")
pnputil_pos = result.find("pnputil.exe")
assert wow64_pos < pnputil_pos, "WOW64 guard must appear before pnputil"
def test_render_install_uac_guard():
"""SCRPT-04: SYSTEM vs user detection with UAC self-elevation."""
result = render_install(**SAMPLE_ARGS)
assert "IsSystem" in result
assert "Start-Process" in result
assert "-Verb Runas" in result or "Verb Runas" in result
def test_render_install_idempotency():
"""SCRPT-01: All add operations wrapped in idempotency checks."""
result = render_install(**SAMPLE_ARGS)
# Port idempotency
assert "Get-PrinterPort" in result
assert "Add-PrinterPort" in result
# Printer idempotency
assert "Get-Printer" in result
assert "Add-Printer" in result
# Port check must come before Add-PrinterPort
get_port_pos = result.find("Get-PrinterPort")
add_port_pos = result.find("Add-PrinterPort")
assert get_port_pos < add_port_pos, "Get-PrinterPort check must precede Add-PrinterPort"
def test_render_install_booleans():
"""Color and collate are rendered as $true / $false in the script."""
result_true = render_install(**SAMPLE_ARGS) # color_mode=True, collate=True
assert "$true" in result_true
result_false = render_install(**{**SAMPLE_ARGS, "color_mode": False, "collate": False})
assert "$false" in result_false
def test_render_uninstall():
"""SCRPT-02: render_uninstall produces correct removal order with SilentlyContinue."""
result = render_uninstall("Test Printer", "HP Driver", "IP_10.0.0.1")
# All three Remove-* commands must be present
assert 'Remove-Printer -Name "Test Printer"' in result
assert 'Remove-PrinterDriver -Name "HP Driver"' in result
assert 'Remove-PrinterPort -Name "IP_10.0.0.1"' in result
# All must have -ErrorAction SilentlyContinue
assert result.count("-ErrorAction SilentlyContinue") >= 3
# Order: Remove-Printer BEFORE Remove-PrinterDriver (driver removal fails if printer still active)
printer_pos = result.find("Remove-Printer -Name")
driver_pos = result.find("Remove-PrinterDriver -Name")
port_pos = result.find("Remove-PrinterPort -Name")
assert printer_pos < driver_pos, "Remove-Printer must appear before Remove-PrinterDriver"
assert driver_pos < port_pos, "Remove-PrinterDriver must appear before Remove-PrinterPort"
def test_render_detect():
"""SCRPT-03: render_detect follows Intune detection contract (Write-Output + exit 0/1)."""
result = render_detect("Test Printer")
assert 'Get-Printer -Name "Test Printer"' in result
assert "Write-Output" in result
assert "exit 0" in result
assert "exit 1" in result
# ---------------------------------------------------------------------------
# Integration tests — script API endpoints
# ---------------------------------------------------------------------------
def test_install_endpoint(client, owner):
"""GET /printers/{id}/scripts/install returns 200 with pnputil in content."""
_driver, printer = _create_test_driver_and_printer(owner)
response = client.get(f"/printers/{printer.id}/scripts/install")
assert response.status_code == 200
assert "pnputil" in response.text
def test_uninstall_endpoint(client, owner):
"""GET /printers/{id}/scripts/uninstall returns 200 with Remove-Printer in content."""
_driver, printer = _create_test_driver_and_printer(owner)
response = client.get(f"/printers/{printer.id}/scripts/uninstall")
assert response.status_code == 200
assert "Remove-Printer" in response.text
def test_detect_endpoint(client, owner):
"""GET /printers/{id}/scripts/detect returns 200 with Write-Output in content."""
_driver, printer = _create_test_driver_and_printer(owner)
response = client.get(f"/printers/{printer.id}/scripts/detect")
assert response.status_code == 200
assert "Write-Output" in response.text
def test_script_endpoint_missing_printer(client):
"""GET /printers/{id}/scripts/install returns 404 for nonexistent printer."""
response = client.get("/printers/9999/scripts/install")
assert response.status_code == 404
def test_script_endpoint_no_driver(client, owner):
"""GET /printers/{id}/scripts/install returns 422 when no driver assigned."""
from imptune.db.models import Printer
printer = Printer.create(
name="No Driver Printer",
ip_address="10.0.0.2",
port_name="IP_10.0.0.2",
driver=None,
owner=owner,
duplex_mode="OneSided",
color_mode=True,
paper_size="A4",
collate=True,
)
response = client.get(f"/printers/{printer.id}/scripts/install")
assert response.status_code == 422