@@ -4178,6 +4178,106 @@ def test_setconfig(node_factory, bitcoind):
41784178 assert lines == ["# Created and update by setconfig, but you can edit this manually when node is stopped." , "min-capacity-sat=400000" ]
41794179
41804180
4181+ def test_setconfig_access (node_factory , bitcoind ):
4182+ """Test that we correctly fail (not crash) if config file/dir not writable"""
4183+
4184+ # Disable bookkeeper, with its separate db which gets upset under CI.
4185+ l1 = node_factory .get_node (options = {'disable-plugin' : 'bookkeeper' })
4186+
4187+ netconfigfile = os .path .join (l1 .daemon .opts .get ("lightning-dir" ), TEST_NETWORK , 'config' )
4188+
4189+ # It's OK if the config file doesn't exist.
4190+ l1 .rpc .check ("setconfig" , config = "min-capacity-sat" , val = 1000000 )
4191+
4192+ # But not if we can't create it.
4193+ os .chmod (os .path .dirname (netconfigfile ), 0o550 )
4194+ with pytest .raises (RpcError , match = f'Cannot write to config file { netconfigfile } ' ):
4195+ l1 .rpc .check ("setconfig" , config = "min-capacity-sat" , val = 1000000 )
4196+
4197+ with pytest .raises (RpcError , match = f'Cannot write to config file { netconfigfile } ' ):
4198+ l1 .rpc .setconfig (config = "min-capacity-sat" , val = 1000000 )
4199+
4200+ # Empty config file (we need to be able to write dir)
4201+ os .chmod (os .path .dirname (netconfigfile ), 0o750 )
4202+ with open (netconfigfile , 'w' ) as file :
4203+ pass
4204+ l1 .restart ()
4205+
4206+ # check will fail
4207+ os .chmod (os .path .dirname (netconfigfile ), 0o550 )
4208+ with pytest .raises (RpcError , match = f'Cannot write to config file { netconfigfile } ' ):
4209+ l1 .rpc .check ("setconfig" , config = "min-capacity-sat" , val = 1000000 )
4210+
4211+ # real write will definitely fail
4212+ with pytest .raises (RpcError , match = f'Cannot write to config file { netconfigfile } ' ):
4213+ l1 .rpc .setconfig (config = "min-capacity-sat" , val = 1000000 )
4214+
4215+ # Transient? Don't care that we can't change it.
4216+ ret = l1 .rpc .setconfig (config = 'min-capacity-sat' , val = 400001 , transient = True )
4217+ assert ret == {'config' :
4218+ {'config' : 'min-capacity-sat' ,
4219+ 'source' : 'setconfig transient' ,
4220+ 'value_int' : 400001 ,
4221+ 'dynamic' : True }}
4222+
4223+ # db also needs to write directory!
4224+ os .chmod (os .path .dirname (netconfigfile ), 0o750 )
4225+
4226+ # Now put a setting in the main config file
4227+ l1 .stop ()
4228+ mainconfigfile = os .path .join (l1 .daemon .opts .get ("lightning-dir" ), 'config' )
4229+ with open (mainconfigfile , 'w' ) as file :
4230+ file .write ("min-capacity-sat=100" )
4231+ l1 .start ()
4232+
4233+ # We don't actually need to write file, just directoty.
4234+ os .chmod (mainconfigfile , 0o400 )
4235+
4236+ l1 .rpc .check ("setconfig" , config = "min-capacity-sat" , val = 9999 )
4237+ l1 .rpc .setconfig (config = "min-capacity-sat" , val = 9999 )
4238+
4239+ # setconfig file exists, and its permissions matter!
4240+ setconfigfile = netconfigfile + ".setconfig"
4241+ os .chmod (setconfigfile , 0o400 )
4242+ with pytest .raises (RpcError , match = f'Cannot write to config file { setconfigfile } ' ):
4243+ l1 .rpc .check ("setconfig" , config = "min-capacity-sat" , val = 1000000 )
4244+
4245+ with pytest .raises (RpcError , match = f'Cannot write to config file { setconfigfile } ' ):
4246+ l1 .rpc .setconfig (config = "min-capacity-sat" , val = 1000000 )
4247+
4248+ # Change location of setconfig file in another sub directory.
4249+ l1 .stop ()
4250+ includedir = os .path .join (os .path .dirname (netconfigfile ), "include" )
4251+ os .mkdir (includedir )
4252+ os .unlink (setconfigfile )
4253+ setconfigfile = os .path .join (includedir , "special.setconfig" )
4254+ with open (netconfigfile , 'w' ) as file :
4255+ file .write (f"include { setconfigfile } " )
4256+ with open (setconfigfile , 'w' ) as file :
4257+ pass
4258+ l1 .start ()
4259+
4260+ # Needs to be writable, to append.
4261+ os .chmod (setconfigfile , 0o400 )
4262+ with pytest .raises (RpcError , match = f'Cannot write to config file { setconfigfile } ' ):
4263+ l1 .rpc .check ("setconfig" , config = "min-capacity-sat" , val = 1000000 )
4264+
4265+ with pytest .raises (RpcError , match = f'Cannot write to config file { setconfigfile } ' ):
4266+ l1 .rpc .setconfig (config = "min-capacity-sat" , val = 1000000 )
4267+
4268+ # But directory doesn't!
4269+ os .chmod (includedir , 0o500 )
4270+ os .chmod (setconfigfile , 0o700 )
4271+ assert l1 .rpc .setconfig (config = "min-capacity-sat" , val = 1000000 ) == {'config' :
4272+ {'config' : 'min-capacity-sat' ,
4273+ 'source' : f'{ setconfigfile } :1' ,
4274+ 'value_int' : 1000000 ,
4275+ 'dynamic' : True }}
4276+
4277+ # Don't break pytest cleanup!
4278+ os .chmod (includedir , 0o700 )
4279+
4280+
41814281@unittest .skipIf (os .getenv ('TEST_DB_PROVIDER' , 'sqlite3' ) != 'sqlite3' , "deletes database, which is assumed sqlite3" )
41824282def test_recover_command (node_factory , bitcoind ):
41834283 l1 , l2 = node_factory .get_nodes (2 )
0 commit comments