Title: How can I add my credentials into .gitignore but still execute my python?
Tags: python,json,git,lambda,config

Question: I am confused on how to add my credentials to .gitignore when they are in my config file. I have database credentials stored in my config file and they are used to execute my code below:
import os 
import json
import platform
import logging
import pymysql as pm
import boto3

class ClassName:
    env=None
    config=None

    def __init__(self, env_filename):
        self.env=env_filename
        self.config=self.get_config()

    def get_config(self):
        with open(self.env) as file_in:
            return json.load(file_in)
        
    def is_Windows():
        if "win" in (platform.system().lower()):
            return True
        else:
            return False

    def DB_connection(self):
        logger = logging.getLogger()
        logger.setLevel(logging.INFO)
        connection = None
        try:
            config=ClassName.get_config(self)
            host=config["exceptions"]["database-secrets"]["host"]
            port=config["exceptions"]["database-secrets"]["port"]
            database=config["exceptions"]["database-secrets"]["db"]

            # retrieve DB password from secrets manager by invoking exceptions lambda function
            dbUserName = "user"
            lambdaFunctionName = "exceptions"
            client = boto3.client('lambda')
            response = client.invoke(FunctionName=lambdaFunctionName)
            result = json.loads(response['Payload'].read().decode())
            dbPassword = result["pass"]

            connection = pm.connect(user=dbUserName,password=dbPassword,host=host,port=port,database=database)
    
            logger.info("Successfully connected to database")

        except Exception as e:
            logger.error("Unable to connect to database: %s", str(e))
        
        return connection
    

    def run_all(self):
        def func1(self):
            func1_INSERT_QUERY = "CALL sp_func1_Insert_Daily_Records();"
            func1_EXCEPTIONS_QUERY = "CALL sp_func1_Exceptions();"
            vfcaa = self.config["verafin-exceptions"]["functions"]["func1"]
            if vfcaa:
                with self.DB_connection() as cnxn:
                    with cnxn.cursor() as cur:
                        try:
                            cur.execute(func1_INSERT_QUERY)
                            print("func1 insertion query ran successfully, {} records updated.".format(cur.rowcount), '\n')

                            cur.execute(func1_EXCEPTIONS_QUERY)
                            print("func1 exceptions query ran successfully, {} exceptions updated.".format(cur.rowcount), '\n')
                            data=cur.fetchall()                     
                            for row in data:
                                for col in row:
                                    print (col, end=' ')
                                print('\n')

                        except pm.Error as e:
                            print(f"Error: {e}")

                        except Exception as e:
                            logging.exception(e)

                        else:
                            cnxn.commit()
        func1(self)

        def func2(self):
            func2_INSERT_QUERY = "CALL sp_func2_Insert_Daily_Records();"
            func2_EXCEPTIONS_QUERY = "CALL sp_func2_Exceptions();"
            vfj = self.config["verafin-exceptions"]["functions"]["func2"]
            if vfj:
                with self.DB_connection() as cnxn:
                    with cnxn.cursor() as cur:
                        try:
                            cur.execute(func2_INSERT_QUERY)
                            print("func2 insertion query ran successfully, {} records updated.".format(cur.rowcount), '\n')

                            cur.execute(func2_EXCEPTIONS_QUERY)
                            print("func2 exceptions query ran successfully, {} exceptions updated.".format(cur.rowcount), '\n')
                            data=cur.fetchall()                     
                            for row in data:
                                for col in row:
                                    print (col, end=' ')
                                print('\n')

                        except pm.Error as e:
                            print(f"Error: {e}")

                        except Exception as e:
                            logging.exception(e)

                        else:
                            cnxn.commit()
        func2(self)

        def func3(self):
            func3_INSERT_QUERY = "CALL sp_func3_Insert_Daily_Records();"
            func3_EXCEPTIONS_QUERY = "CALL sp_func3_Exceptions();"
            vfl = self.config["verafin-exceptions"]["functions"]["func3"]
            if vfl:
                with self.DB_connection() as cnxn:
                    with cnxn.cursor() as cur:
                        try:
                            cur.execute(func3_INSERT_QUERY)
                            print("func3 insertion query ran successfully, {} records updated.".format(cur.rowcount), '\n')

                            cur.execute(func3_EXCEPTIONS_QUERY)
                            print("func3 exceptions query ran successfully, {} exceptions updated.".format(cur.rowcount), '\n')
                            data=cur.fetchall()                   
                            for row in data:
                                for col in row:
                                    print (col, end=' ')
                                print('\n')

                        except pm.Error as e:
                            print(f"Error: {e}")

                        except Exception as e:
                            logging.exception(e)

                        else:
                            cnxn.commit()
        func3(self)

def main():
    cwd=os.getcwd()
    if "win" in (platform.system().lower()):
        vfc=(cwd+"\config"+".json")
    else:
        vfc=(cwd+"/config"+".json")
    ve=ClassName(vfc)
    ve.run_all()
if __name__ == "__main__":
    main()

My config has info stored here in json format:
{
    "exceptions":{
        "database-secrets":{
            "host": "host",
            "db": "db",
            "port": port
        },
        "functions":{
            "func1": true,
            "func2": true,
            "func3": true
        }
    }
}

I have to add them into .gitignore because the credentials will differ depending on the levels.

Answer: You can add your config file to .gitignore and then once you deploy your app in the server, you can manually add a new config file in the server to get it working.
This way your credentials are not exposed in your git repo.
This is a pretty standard procedure which many people use, but nowadays its better managed by third party services such as Azure KeyVault etc. You could take a look into that.