generated from jric11/baseProject
ChatGPT's update to harden software and run db updates.
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
if(PHP_SAPI!=='cli')exit;
|
||||
if(!preg_match('/\Ahcr_http_test_[a-f0-9]{12}\z/',getenv('HCR_DB_NAME')?:''))throw new RuntimeException('Disposable database required.');
|
||||
require __DIR__.'/../classes/Base.php';
|
||||
$db=(new Base())->connect();$ids=json_decode(getenv('HCR_TENANT_IDS'),true,512,JSON_THROW_ON_ERROR);$checks=0;
|
||||
function retryCheck(bool $ok,string $label):void{global $checks;if(!$ok)throw new RuntimeException($label);$checks++;echo 'PASS: '.$label."\n";}
|
||||
$insert=static function(PDO $db,string $subject)use($ids):void{$s=$db->prepare('INSERT INTO club_tickets(club_serial,user_serial,subject) VALUES(?,?,?)');$s->execute([$ids['clubA'],$ids['membera'],$subject]);};
|
||||
$attempts=0;$value=DatabaseTransaction::run($db,function(PDO $db)use(&$attempts,$insert){$attempts++;$insert($db,'Retried transaction');if($attempts<3)$db->exec("SIGNAL SQLSTATE '40001' SET MYSQL_ERRNO=1213,MESSAGE_TEXT='Controlled deadlock'");return 'committed';});
|
||||
retryCheck($attempts===3&&$value==='committed','Deadlock retries return the successful whole-transaction result');
|
||||
retryCheck((int)$db->query("SELECT COUNT(*) FROM club_tickets WHERE subject='Retried transaction'")->fetchColumn()===1,'Retry rollbacks prevent duplicate ticket writes');
|
||||
$attempts=0;try{DatabaseTransaction::run($db,function(PDO $db)use(&$attempts,$insert){$attempts++;$insert($db,'Exhausted transaction');$db->exec("SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO=1205,MESSAGE_TEXT='Controlled timeout'");});throw new RuntimeException('Expected timeout');}catch(PDOException $e){retryCheck($attempts===3&&(int)$e->errorInfo[1]===1205,'Lock timeout retries stop after three attempts');}
|
||||
retryCheck(!$db->inTransaction()&&!(int)$db->query("SELECT COUNT(*) FROM club_tickets WHERE subject='Exhausted transaction'")->fetchColumn(),'Exhausted retries leave no open transaction or partial write');
|
||||
$attempts=0;try{DatabaseTransaction::run($db,function(PDO $db)use(&$attempts,$insert){$attempts++;$insert($db,'Rejected transaction');throw new AppException('Denied',403);});}catch(AppException $e){retryCheck($attempts===1&&$e->status===403,'Business and permission errors are never retried');}
|
||||
retryCheck(!(int)$db->query("SELECT COUNT(*) FROM club_tickets WHERE subject='Rejected transaction'")->fetchColumn(),'Permission failure rolls back its writes');
|
||||
// Simulate a grant changing after the first attempt rolls back, before retry.
|
||||
class RevocationPDO extends PDO {
|
||||
public $afterRollback;
|
||||
public function rollBack():bool{$ok=parent::rollBack();if($this->afterRollback){$call=$this->afterRollback;$this->afterRollback=null;$call();}return $ok;}
|
||||
}
|
||||
$settings=(new Base())->getSettings();$retryDb=new RevocationPDO('mysql:host='.$settings->DatabaseServer.';port='.$settings->DatabasePort.';dbname='.$settings->DatabaseName.';charset=utf8mb4',(string)$settings->DatabaseUser,(string)$settings->DatabasePassword,[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC]);
|
||||
$_SESSION=[Base::USER_SERIAL=>$ids['admina2']];$retryDb->afterRollback=function()use($db,$ids){$db->exec("UPDATE club_memberships SET membership_role='member' WHERE membership_serial=".$ids['clubA_admina2']);};$attempts=0;
|
||||
try{DatabaseTransaction::run($retryDb,function(PDO $db)use(&$attempts,$ids,$insert){$attempts++;(new TenantAccess())->requireManager($ids['clubA'],$db);$insert($db,'Revoked transaction');$db->exec("SIGNAL SQLSTATE '40001' SET MYSQL_ERRNO=1213,MESSAGE_TEXT='Controlled deadlock'");});throw new RuntimeException('Revoked write was allowed');}catch(AppException $e){retryCheck($attempts===2&&$e->status===403,'Authorization is checked again after a concurrent revocation');}
|
||||
retryCheck(!(int)$db->query("SELECT COUNT(*) FROM club_tickets WHERE subject='Revoked transaction'")->fetchColumn(),'Revoked authority cannot commit a retried write');
|
||||
echo "$checks transaction retry checks passed.\n";
|
||||
Reference in New Issue
Block a user