assertMatchesRegularExpression('/^[a-f0-9]{12}$/D',$run); $identity=DB::selectOne("SELECT current_database() AS name,current_user AS role,inet_server_port() AS port,current_setting('cluster_name') AS cluster"); $this->assertMatchesRegularExpression('/^stock_read_compras_([a-f0-9]{12})$/D',$identity->name); $tag=substr($identity->name,-12); $this->assertSame('stock_read_qa_'.$tag,$identity->role);$this->assertSame(55439,(int)$identity->port);$this->assertSame('sgf_modular_regression_'.$run,$identity->cluster); // Fresh, dedicated QA database only. Never migrate/reset any existing host. $this->assertFalse(DB::getSchemaBuilder()->hasTable('users')); DB::transaction(function () { DB::statement('CREATE TABLE tenants(id bigint PRIMARY KEY,name text,currency text)'); DB::statement("INSERT INTO tenants VALUES(77,'Synthetic native company','MZN'),(88,'Foreign company','MZN')"); DB::statement('CREATE TABLE users(id bigserial PRIMARY KEY,tenant_id bigint,department_id bigint,name text,email text,password text,purchasing_role text,email_verified_at timestamp,remember_token text,created_at timestamp,updated_at timestamp)'); DB::statement('CREATE TABLE organization_access(tenant_id bigint,active boolean)'); DB::statement('CREATE TABLE organization_profiles(id bigint PRIMARY KEY,tenant_id bigint,name text,permissions jsonb,work_contexts jsonb)'); DB::statement('CREATE TABLE organization_memberships(id bigint PRIMARY KEY,tenant_id bigint,user_id bigint,profile_id bigint,expires_at timestamp,maintenance boolean)'); }); $actor=User::forceCreate(['tenant_id'=>77,'purchasing_role'=>'warehouse','name'=>'Synthetic warehouse','email'=>'stock@example.test','password'=>bin2hex(random_bytes(16))]); $denied=User::forceCreate(['tenant_id'=>77,'purchasing_role'=>'requester','name'=>'Synthetic requester','email'=>'request@example.test','password'=>bin2hex(random_bytes(16))]); $schema='sgf_stock_read_'.bin2hex(random_bytes(6)); DB::transaction(function () use ($schema) { DB::statement("CREATE SCHEMA $schema"); DB::statement("CREATE TABLE $schema.stock_items(id bigint PRIMARY KEY,tenant_id bigint,code text,name text,unit text)"); DB::statement("CREATE TABLE $schema.warehouses(id bigint PRIMARY KEY,tenant_id bigint,code text,name text)"); DB::statement("CREATE TABLE $schema.stock_movements(id bigserial PRIMARY KEY,tenant_id bigint,stock_item_id bigint,warehouse_id bigint,quantity_milli bigint,movement_type text,snapshot jsonb,moved_at timestamp)"); DB::statement("INSERT INTO $schema.warehouses VALUES(11,77,'WH-A','Synthetic A'),(12,77,'WH-B','Synthetic B'),(13,77,'HIDDEN','Restricted warehouse'),(21,88,'FOREIGN','Foreign warehouse')"); DB::statement("INSERT INTO $schema.stock_items SELECT i,77,'QA-'||lpad(i::text,6,'0'),'Synthetic item '||i,'un' FROM generate_series(1,100) i"); DB::statement("INSERT INTO $schema.stock_items VALUES(101,77,'ZERO','Without movements','un'),(9999999,88,'SECRET','Foreign item','un')"); DB::statement("INSERT INTO $schema.stock_movements(tenant_id,stock_item_id,warehouse_id,quantity_milli,movement_type,snapshot,moved_at) SELECT 77,i,11,10000,'receipt',jsonb_build_object('reference','QA-R-'||i,'private_document','DO_NOT_RETURN'),'2026-11-01'::timestamp FROM generate_series(1,100) i"); DB::statement("INSERT INTO $schema.stock_movements(tenant_id,stock_item_id,warehouse_id,quantity_milli,movement_type,snapshot,moved_at) SELECT 77,i,11,-2000,'issue',jsonb_build_object('reference','QA-I-'||i),'2026-11-02'::timestamp FROM generate_series(1,100) i"); DB::statement("INSERT INTO $schema.stock_movements(tenant_id,stock_item_id,warehouse_id,quantity_milli,movement_type,snapshot,moved_at) VALUES(77,1,13,99000,'hidden','{}',now()),(88,9999999,21,88000,'foreign','{}',now())"); DB::statement("CREATE FUNCTION $schema.immutable() RETURNS trigger LANGUAGE plpgsql AS 'BEGIN RAISE EXCEPTION ''Inventory ledger is append-only''; END'"); DB::statement("CREATE TRIGGER immutable BEFORE UPDATE OR DELETE ON $schema.stock_movements FOR EACH ROW EXECUTE FUNCTION $schema.immutable()"); }); $binding=['schema'=>$schema,'source_tenant_id'=>77,'warehouse_ids'=>[11,12],'append_only'=>true]; $key='77:'.$actor->id;config(['stock_read.synthetic_sources.'.$key=>$binding]); $this->getJson('/api/stock-read')->assertUnauthorized(); $this->actingAs($denied)->getJson('/api/stock-read')->assertForbidden(); $this->actingAs($actor); $queries=[];foreach(['items','warehouses','balances','movements'] as $view)foreach([25,100] as $size)$queries[]='view='.$view.'&per_page='.$size; $queries=[...$queries,'view=balances&per_page=25&page=2','view=items&per_page=25&page=5','view=balances&warehouse_id=12','view=items&search=QA-000001']; $cases=[]; foreach($queries as $query){ $r=$this->getJson('/api/stock-read?'.$query)->assertOk(); $this->assertStringNotContainsString('DO_NOT_RETURN',$r->getContent());$this->assertStringNotContainsString('Foreign',$r->getContent());$this->assertStringNotContainsString('Restricted warehouse',$r->getContent()); $cases[$query]=['sha256'=>hash('sha256',json_encode([$r->json('rows'),$r->json('pagination')],JSON_THROW_ON_ERROR)),'total'=>$r->json('pagination.total')]; } $snapshot=$this->getJson('/api/stock-read')->assertOk()->assertJsonPath('rows.0.physical_milli','8000')->json('snapshot'); $this->getJson('/api/stock-read?warehouse_id=13')->assertForbidden();$this->getJson('/api/stock-read?warehouse_id=21')->assertForbidden(); $this->getJson('/api/stock-read?tenant_id=88')->assertUnprocessable();$this->getJson('/api/stock-read?per_page=101')->assertUnprocessable(); $this->getJson('/api/stock-read?snapshot=invalid')->assertConflict(); DB::table($schema.'.stock_movements')->insert(['tenant_id'=>77,'stock_item_id'=>1,'warehouse_id'=>11,'quantity_milli'=>-1000,'movement_type'=>'issue','snapshot'=>'{}','moved_at'=>now()]); $this->getJson('/api/stock-read?snapshot='.urlencode($snapshot))->assertConflict(); $this->getJson('/api/stock-read')->assertOk()->assertJsonPath('rows.0.physical_milli','7000'); // Exercise configured native permissions too, without inventing a new right. DB::table('organization_access')->insert(['tenant_id'=>77,'active'=>true]); DB::table('organization_profiles')->insert(['id'=>1,'tenant_id'=>77,'name'=>'Synthetic warehouse profile','permissions'=>'["warehouse"]','work_contexts'=>'[]']); DB::table('organization_memberships')->insert(['id'=>1,'tenant_id'=>77,'user_id'=>$actor->id,'profile_id'=>1,'maintenance'=>false]); $this->getJson('/api/stock-read')->assertOk(); DB::table('organization_profiles')->where('id',1)->update(['permissions'=>'["requester"]']); $this->getJson('/api/stock-read')->assertForbidden(); DB::table('organization_profiles')->where('id',1)->update(['permissions'=>'["warehouse"]']); $this->getJson('/api/stock-read')->assertOk(); config(['stock_read.synthetic_sources.'.$key=>null]);$this->getJson('/api/stock-read')->assertStatus(503)->assertJsonPath('status','unavailable'); config(['stock_read.synthetic_sources.'.$key=>array_replace($binding,['source_tenant_id'=>88])]);$this->getJson('/api/stock-read')->assertStatus(503); config(['stock_read.synthetic_sources.'.$key=>$binding]);$this->getJson('/api/stock-read')->assertOk(); $output=getenv('STOCK_READ_COMPOSITION_OUTPUT');$root=realpath((string)getenv('STOCK_READ_COMPOSITION_ROOT')); if(!$output||!$root||realpath(dirname($output))!==$root)throw new \RuntimeException('Unexpected private proof directory'); file_put_contents($output,json_encode(['identity'=>$identity,'cases'=>$cases,'native_snapshot'=>$snapshot,'native_roles_and_profiles_revalidated'=>true, 'warehouse_isolation'=>true,'stale_snapshot_refused'=>true,'unknown_source_refused'=>true,'package_manifest_sha256'=>config('stock_read.package_manifest_sha256')],JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR)); } }