diff --git a/docs/query_proxy.md b/docs/query_proxy.md index c413721c74..0f56fedaf2 100644 --- a/docs/query_proxy.md +++ b/docs/query_proxy.md @@ -179,6 +179,26 @@ If this flag is specified, then `allowedCalls` must not be specified. } ``` +### Validating Permissions File Changes + +The query server automatically detects changes to the permissions file and attempts to reload them. If there are errors in the updated +file, the server rejects the update and continues running on the old version. However, if the file is not fixed, those errors will prevent +the server from coming up on the next restart. You can avoid this problem by verifying any file updates before attempting to reload. + +To do this, you can copy the permissions file to some other file, make your changes to the copy, and then do the following: + +```sh +$ guardiand query-server --verifyPermissions --permFile new.permissions.file.json --allowAnything +``` + +where `new.permissions.file.json` is the path to the updated file. Additionally, if your permission file includes the `allowAnything` +flag for any of the users, you must specify that flag on the command line when doing the verify. + +If the updated file is good, the program will exit immediately with no output and an exit code of zero. If the file contains +errors, the first error will be printed, and the exit code will be one. + +Once you are satisfied with your updates, you can copy the updated file to the official location. + ## Telemetry The proxy server provides two types of telemetry data, logs and metrics. diff --git a/node/cmd/ccq/query_server.go b/node/cmd/ccq/query_server.go index 1ae79b2cd1..c8907a587f 100644 --- a/node/cmd/ccq/query_server.go +++ b/node/cmd/ccq/query_server.go @@ -48,6 +48,7 @@ var ( monitorPeers *bool gossipAdvertiseAddress *string allowAnything *bool + verifyPermissions *bool ) const DEV_NETWORK_ID = "/wormhole/dev" @@ -71,6 +72,7 @@ func init() { monitorPeers = QueryServerCmd.Flags().Bool("monitorPeers", false, "Should monitor bootstrap peers and attempt to reconnect") gossipAdvertiseAddress = QueryServerCmd.Flags().String("gossipAdvertiseAddress", "", "External IP to advertize on P2P (use if behind a NAT or running in k8s)") allowAnything = QueryServerCmd.Flags().Bool("allowAnything", false, `Should allow API keys with the "allowAnything" flag (only allowed in testnet and devnet)`) + verifyPermissions = QueryServerCmd.Flags().Bool("verifyPermissions", false, `parse and verify the permissions file and then exit with 0 if success, 1 if failure`) // The default health check monitoring is every five seconds, with a five second timeout, and you have to miss two, for 20 seconds total. shutdownDelay1 = QueryServerCmd.Flags().Uint("shutdownDelay1", 25, "Seconds to delay after disabling health check on shutdown") @@ -86,6 +88,15 @@ var QueryServerCmd = &cobra.Command{ } func runQueryServer(cmd *cobra.Command, args []string) { + if *verifyPermissions { + _, err := parseConfigFile(*permFile, *allowAnything) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + os.Exit(0) + } + common.SetRestrictiveUmask() // Setup logging