-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.py
More file actions
60 lines (49 loc) · 2.17 KB
/
Copy pathmain.py
File metadata and controls
60 lines (49 loc) · 2.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import sys
import getpass
from models import initialize_db, add_items, update_item_price_config_sync
from pydantic import ValidationError
from core.config_schema import AppConfig
from core.service import BotService
from logger import setup_logger, writeLog
def collect_cvv():
"""Collect CVV via hidden input at runtime. Never echoes or stores to disk (SEC-02)."""
try:
cvv = getpass.getpass("Enter CVV (input hidden): ").strip()
except getpass.GetPassWarning:
print("WARNING: CVV echo suppression unavailable in this terminal", file=sys.stderr)
raise SystemExit("Cannot collect CVV securely. Run in an interactive terminal.")
if not cvv:
raise SystemExit("CVV is required for auto-buy. Exiting.")
return cvv
def main():
writeLog("Starting main function", "INFO")
# Validate config at startup; exit cleanly on schema error (CORE-05)
try:
cfg = AppConfig()
except ValidationError as e:
print(f"Configuration error -- fix config.yml:\n{e}")
raise SystemExit(1)
# Initialize the database and add items from config
initialize_db()
items = [
(item.name, item.link, item.auto_buy, item.quantity, False)
for item in cfg.available.items
]
add_items(items)
# Seed per-item price monitoring config into items table (PRICE-01, PRICE-05, Pitfall 7).
# Idempotent: NULL overwrites NULL when no price targets are configured.
for item in cfg.available.items:
update_item_price_config_sync(item.link, item.target_price, item.price_drop_pct)
# SEC-01/02: collect BestBuy CVV from getpass BEFORE the service run (D-03 / Pitfall 6).
# Only prompt if not in test_mode AND at least one BestBuy item has auto_buy enabled.
# In test_mode the purchase step is skipped, so blocking on a getpass prompt would
# break CI and violate the test_mode contract (WR-02).
needs_bb_autobuy = (
not cfg.debug.test_mode
and any("bestbuy.com" in item.link and item.auto_buy for item in cfg.available.items)
)
cvv = collect_cvv() if needs_bb_autobuy else None
BotService(cfg).run(cvv)
if __name__ == "__main__":
logger = setup_logger()
main()