VULN_CHECK_I913V6 =j0ddlZddlZddlZddlZddlmZmZddlmZmZm Z m Z m Z m Z m Z mZmZmZddlmZddlmZddlmZddlmZddlmZd Zed zZd ZeZejd Z Gd deZ!d!dZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+d"dZ,dZ-dZ.dZ/ej0defd Z1dS)#N)datetime timedelta) ColumnBooleanDateTimeIndexIntegerString create_engineeventfunctext)declarative_base) Inspector)Session)close_all_sessions) DatabaseErrorz/var/lve/ssa.dbz.oldcleanup_old_dataceZdZdZdZedddfZeedZ ee d Z ee d Z eed Z eed Zeed Zeed Zeed Zeed Zeed Zeed ejd Zeed ejej Zd S) RequestResultay Describes processed request stored in database file. E.g. { "timestamp": "1650008727", "url": "http://mydomain.com/index.php", "duration": 162077, "hitting_limits": false, "throttled_time": 0, "io_throttled_time": 0, "wordpress": true } Note: created_at, updated_at is saved in local TZ format scrape_resultix_scrape_result_domain_pathdomainpathT) primary_keyF)nullable)timezone)server_defaultindex)onupdaterN)__name__ __module__ __qualname____doc__ __tablename__r__table_args__rr idr rr timestampdurationris_slow_requesthitting_limitsthrottled_timeio_throttled_time wordpressrr now created_at updated_at=/opt/cloudlinux/venv/lib64/python3.11/site-packages/ssa/db.pyrr sg"$Me:HfMMON T * * *B VFU + + +F 6&5 ) ) )Dw///Ivg...HfWu555OVGe444NVGe444Nw777w///I$/// RVWWWJ$///($(**U]UYU]U_U_```JJJr4r'ctjttz }d} t |5}|t d||d}|j}||z }|dkr dddn dddn #1swxYwYnt d|t|dS)a Removes outdated records from database, saving disk space. Deletions are batched to avoid loading the entire database into the cgroup's page cache, which causes OOM on large databases. Runs VACUUM after deletion to reclaim disk space. )daysrTzrDELETE FROM scrape_result WHERE rowid IN (SELECT rowid FROM scrape_result WHERE created_at < :cutoff LIMIT :batch))cutoffbatchNzCleanup deleted %d old records) rtodayrRETENTION_TIME_DAYS session_scopeexecuterrowcountloggerinfovacuum_database)engine batch_size n_days_ago total_deletedsessionresultdeleteds r5rrSs6!!I3F$G$G$GGJM  6 " " g__`& ;; FoG W $M!||                        KK0-@@@Fs:BBBcjtjtjt}tj|tjr6|d|dt d|dSt d||dS)u Point SQLite's temp store at the database directory (on disk) for the given operation. SQLite spills large sorts / temp B-trees and VACUUM copies to the system temp directory, which can be tmpfs (RAM-backed). When it is, the spill is charged against the MemoryMax=1G cgroup and OOM-kills the agent on large databases — the same hazard for VACUUM and for index builds / ORDER BY sorts (CLPRO-2819, CLPRO-3077). PRAGMA temp_store_directory = ''z&Set SQLite temp_store_directory to: %szJDirectory %s not writable. %s will fall back to the default temp location.N) osrdirnameabspathSSA_DBaccessW_OKr>r@rAwarning)cursor operationdb_dirs r5_redirect_temp_store_to_diskrWmsW__RW__V44 5 5F y!!xBBBBCCC close Exceptionerrorstr)rCraw_connoriginal_isolation_levelrTes r5rBrB~s! $$&&H'7#' ""$VX666 2333x    4555  111 /s1vv//000000001$< $< s0BB&%D& C$0*CDC$$DD!c4|} |}t|dtd|d|td|n?#t$r2}t dt|Yd}~nd}~wwxYw|dS#|wxYw)u Create the composite (domain, path) index on existing databases. The schema is only materialised by ``create_all()`` in ``create_db_if_not_exist()``, which runs solely when the DB file does not yet exist — there are no migrations. So a model-level index reaches new installs only, while the multi-GB databases that actually OOM never get it. This explicit ``CREATE INDEX IF NOT EXISTS`` closes that gap; it is idempotent and a cheap no-op once the index exists (CLPRO-3077). Building the index on a large table sorts it, so we first redirect the temp store to disk to avoid the very tmpfs spill we are trying to fix. z CREATE INDEXz/Ensuring ix_scrape_result_domain_path exists...zVCREATE INDEX IF NOT EXISTS ix_scrape_result_domain_path ON scrape_result(domain, path)z.Index ix_scrape_result_domain_path is present.zFailed to ensure indexes: %sN) rZrTrWr@rAr>commitr\r]r^r_)rCr`rTrbs r5ensure_indexesres$$&&H ""$V^<<< EFFFoppp DEEE  === 3SVV<<<<<<<<= s0BB,+D, C(6(C#D#C((DDcft|s!tj|dSdSN) is_db_presentBasemetadata create_all)rCs r5create_db_if_not_existrls8  )   ((((())r4ctjtsdSt j|}d|D}t|dkS)NFcg|]}|Sr3r3).0tables r5 z!is_db_present..s G G Ge G G Gr4r)rMrisfilerPr from_engineget_table_nameslen)rCdatabase_inspectiontabless r5rhrhs^ 7>>& ! !u#/77 G G!4!D!D!F!F G G GF v;;?r4c0|ddS)NzPRAGMA journal_mode = WAL)r>) dbapi_con con_records r5setup_wal_moder{s 122222r4cptjtjt}tj|tjsdS |d|ddS#tj $r'}t d||Yd}~dSd}~wwxYw)uZ Keep SQLite's temp spills (sort / GROUP BY temp B-trees) on disk rather than the default temp dir, which may be tmpfs (RAM-backed) and thus charged against the MemoryMax=1G cgroup. ``temp_store_directory`` is a process-wide setting, but applying it on every connect is cheap and guarantees it is in force before the daily routine runs (CLPRO-3077). Complements the (domain, path) index: the index removes the per-domain ORDER BY sort entirely, this catches whatever spill remains (e.g. the GROUP BY on the computed hour). Best-effort — never block a connection. NrKrLz,Could not set temp_store_directory to %s: %s) rMrrNrOrPrQrRr>sqlite3Errorr@rS)ryrzrVrbs r5setup_temp_store_dirrsW__RW__V44 5 5F 9VRW % %REFEEEFFFFF =RRREvqQQQQQQQQQRs$A??B5B00B5cttdztdzfD]6}tj|rtj|d7dS)a Restrict ssa.db and its WAL/SHM sidecars to owner-only (0600). The DB holds every tenant's domains and request paths; sqlite3.connect creates the file under the agent's umask (0022 -> world-readable 0644) in the world-searchable /var/lve, leaking data across the shared-hosting trust boundary. chmod 0600 is idempotent, so this is a safe no-op for an already-tightened file; each path is guarded on existence. -wal-shmiN)rPrMrexistschmod)rs r5_secure_db_filesrsU&&6/:"" 7>>$   " HT5 ! ! !""r4cdt|rdfd}td|d}tj|dttj|dt t |t|S)Nzfile:z?mode=roc0tjdS)NT)uri)r}connect)connection_stringsr5creatorz _setup_database..creators0d;;;;r4 sqlite:////F)rechor)rPr r listenr{rrlr)readonlyrrCrs @r5_setup_databasers(((;0:::<<<<< F  LN333 L$89996""" Mr4Fc t|Srg)r)rs r5setup_databasers 8 $ $$r4ctjtr-t tjtt t}|tdt } t|5}t|5}| t t||dddn #1swxYwYdddn #1swxYwYn#t$rYnwxYwt tdztdzfD]5}tj|rtj|6dS)z Restore database by establish connections to old and new databases, merge data to new one if possible and delete old one. rNrr)rMrrrPrreplace OLD_SSA_DBrdisposer r=queryrfirst!merge_unharmed_data_from_databaserremove)rC new_engine old_engine session_old session_newrs r5restore_databasers  w~~f' 6:&&&!!J NN9Z99::J : & & H+}Z7P7P HT_   m , , 2 2 4 4 4 -k; G G G H H H H H H H H H H H H H H H H H H H H H H H H H H H H H H      Vf_fvo> 7>>$    IdOOOsZ DD +=C4( D 4C8 8D ;C8 <D ? D DDDD D$#D$cd}d} |t||} |}|sdS|D]}||nv#t $rit|D]V} |||z}|sn&||G#t $rYSwxYwYnwxYw| ||z })z_ Scrape all unharmed records from malformed database and merge them into new database. r TN) rroffsetlimitallmergerrangerrd) rrrrDrrecords_to_saverecord pos_in_batchrecord_to_saves r5rrsNFJ!!-0077??EEjQQ #iikkO" ) * *!!&)))) *    %j 1 1   %*\\&<2G%H%H%N%N%P%PN)%%n5555$D  *%sHA:A::C-,CC-CC- C'$C-&C''C-,C-ctjtr=tjtrtjt t |5}|td}| }|dddkcdddS#1swxYwYdS#t$rYdSwxYw)z Try integrity check of database file to see if it is malformed. If database unable to execute it, will also count as malformed. zPRAGMA integrity_checkrokNT) rMrrrrPrr=r>rfetchallr)rCdbrHerrorss r5is_malformed_databaser:s  w~~j!!bgnnV&<&< * 6 " " (bZZ%= > >??F__&&F!9Q<4' ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( tts7#C2AC: CC  CC C C"!C"returnc#Kt|} |V|n#|xYw |dS#|wxYw)zF Provide a transactional scope around a series of operations. )bindN)rrdrollbackr\)rCrGs r5r=r=Js 6"""G      s-AAAA4)r6)F)2rM contextlibr}loggingrr sqlalchemyrrrrr r r r r rsqlalchemy.ext.declarativersqlalchemy.engine.reflectionrsqlalchemy.ormrsqlalchemy.orm.sessionrsqlalchemy.excrrPrr<ri getLoggerr@rrrWrBrerlrhr{rrrrrrrcontextmanagerr=r3r4r5rsg ((((((((jjjjjjjjjjjjjjjjjjjjjjjj777777222222""""""555555((((((  f_   - . .0a0a0a0a0aD0a0a0af4xxx"6:))) 333RRR* " " "(%%%%86      W      r4