1919import subprocess
2020import time
2121from abc import ABC , abstractmethod
22+ from enum import Enum
2223from typing import Optional , Dict , Any
2324
2425from planet_auth .auth_exception import AuthException
@@ -96,9 +97,15 @@ def _default_storage_provider():
9697class _SOPSAwareFilesystemObjectStorageProvider (ObjectStorageProvider ):
9798 """
9899 Storage provider geared around backing a single object in a single file
99- with paths take from the root of the local file system.
100+ with paths taken from the root of the local file system.
100101 """
101102
103+ _STORAGE_TYPE_KEY = "___SOPSAwareFilesystemObjectStorageProvider__storage_type"
104+
105+ class _StorageType (Enum ):
106+ PLAINTEXT = "plaintext"
107+ SOPS = "sops"
108+
102109 def __init__ (self , root : Optional [pathlib .Path ] = None ):
103110 if root :
104111 self ._storage_root = root
@@ -116,13 +123,18 @@ def _obj_filepath(self, obj_key):
116123 return obj_path
117124
118125 @staticmethod
119- def _is_sops_path (file_path ) :
126+ def _is_sops_path (file_path : pathlib . Path ) -> bool :
120127 # TODO: Could be ".json.sops", or ".sops.json", depending on file
121128 # level or field level encryption, respectively. We currently
122129 # only look for and support field level encryption in json
123130 # files with a ".sops.json" suffix.
124131 return bool (file_path .suffixes == [".sops" , ".json" ])
125132
133+ @staticmethod
134+ def _filter_write_object (data : dict ) -> dict :
135+ final_data = {k : v for k , v in data .items () if not (isinstance (k , str ) and k .startswith ("__" ))}
136+ return final_data
137+
126138 @staticmethod
127139 def _read_json (file_path : pathlib .Path ):
128140 auth_logger .debug (msg = "Loading JSON data from file {}" .format (file_path ))
@@ -137,7 +149,7 @@ def _read_json_sops(file_path: pathlib.Path):
137149
138150 @staticmethod
139151 def _write_json (file_path : pathlib .Path , data : dict ):
140- auth_logger .debug (msg = "Writing JSON data to file {}" .format (file_path ))
152+ auth_logger .debug (msg = "Writing JSON data to cleartext file {}" .format (file_path ))
141153 with open (file_path , mode = "w" , encoding = "UTF-8" ) as file_w :
142154 os .chmod (file_path , stat .S_IREAD | stat .S_IWRITE )
143155 _no_none_data = {key : value for key , value in data .items () if value is not None }
@@ -155,26 +167,54 @@ def _write_json_sops(file_path: pathlib.Path, data: dict):
155167 # ['sops', '-e', '--input-type', 'json', '--output-type',
156168 # 'json', '--output', file_path, '/dev/stdin'],
157169 # stdin=data_f)
158- auth_logger .debug (msg = "Writing JSON data to SOPS encrypted file {}" .format (file_path ))
159170 _SOPSAwareFilesystemObjectStorageProvider ._write_json (file_path , data )
171+ auth_logger .debug (msg = "Writing JSON data to SOPS encrypted file {}" .format (file_path ))
160172 subprocess .check_call (["sops" , "-e" , "--input-type" , "json" , "--output-type" , "json" , "-i" , file_path ])
161173
162174 @staticmethod
163175 def _load_file (file_path : pathlib .Path ) -> dict :
164176 if _SOPSAwareFilesystemObjectStorageProvider ._is_sops_path (file_path ):
165177 new_data = _SOPSAwareFilesystemObjectStorageProvider ._read_json_sops (file_path )
178+ new_data [_SOPSAwareFilesystemObjectStorageProvider ._STORAGE_TYPE_KEY ] = (
179+ _SOPSAwareFilesystemObjectStorageProvider ._StorageType .SOPS .value
180+ )
166181 else :
167182 new_data = _SOPSAwareFilesystemObjectStorageProvider ._read_json (file_path )
183+ new_data [_SOPSAwareFilesystemObjectStorageProvider ._STORAGE_TYPE_KEY ] = (
184+ _SOPSAwareFilesystemObjectStorageProvider ._StorageType .PLAINTEXT .value
185+ )
168186
169187 return new_data
170188
189+ @staticmethod
190+ def _do_sops (file_path : pathlib .Path , data : dict ) -> bool :
191+ if _SOPSAwareFilesystemObjectStorageProvider ._is_sops_path (file_path ):
192+ return True
193+ if (
194+ data
195+ and data .get (_SOPSAwareFilesystemObjectStorageProvider ._STORAGE_TYPE_KEY )
196+ == _SOPSAwareFilesystemObjectStorageProvider ._StorageType .SOPS .value
197+ ):
198+ auth_logger .warning (msg = f"Data sourced from SOPS being written cleartext to the file { file_path } ." )
199+ # Upgrading to SOPS would be great, but also problematic.
200+ # The problem is that if we are writing to SOPS we should use a
201+ # SOPS file name so that we know we should read it as a SOPS file
202+ # later. We can't change the name here because the caller would
203+ # not know what we did, and may not be able to find the object
204+ # later.
205+
206+ return False
207+
171208 @staticmethod
172209 def _save_file (file_path : pathlib .Path , data : dict ):
173210 file_path .parent .mkdir (parents = True , exist_ok = True )
174- if _SOPSAwareFilesystemObjectStorageProvider ._is_sops_path (file_path ):
175- _SOPSAwareFilesystemObjectStorageProvider ._write_json_sops (file_path , data )
211+ do_sops = _SOPSAwareFilesystemObjectStorageProvider ._do_sops (file_path , data )
212+ write_data = _SOPSAwareFilesystemObjectStorageProvider ._filter_write_object (data )
213+
214+ if do_sops :
215+ _SOPSAwareFilesystemObjectStorageProvider ._write_json_sops (file_path , write_data )
176216 else :
177- _SOPSAwareFilesystemObjectStorageProvider ._write_json (file_path , data )
217+ _SOPSAwareFilesystemObjectStorageProvider ._write_json (file_path , write_data )
178218
179219 def load_obj (self , key : ObjectStorageProvider_KeyType ) -> dict :
180220 obj_filepath = self ._obj_filepath (key )
0 commit comments