1
1
#!/usr/bin/env python3
2
2
3
- # Copyright 2023 Cisco Systems, Inc.
3
+ # Copyright 2024 Cisco Systems, Inc.
4
4
#
5
5
# Licensed under the Apache License, Version 2.0 (the "License");
6
6
# you may not use this file except in compliance with the License.
17
17
import fnmatch
18
18
import glob
19
19
import json
20
+ import os
20
21
import pathlib
21
22
import shutil
22
23
import tempfile
26
27
import jinja2
27
28
import yaml
28
29
30
+ import filters
31
+ from tools import encryption_decrypt
32
+
29
33
30
34
def directory_copy (srcpath , dstpath , ignore = []):
31
35
"""Copy the contents of the dir in 'srcpath' to the dir in 'dstpath'.
@@ -62,19 +66,12 @@ def directory_remove(path, keep=[]):
62
66
if not path .is_dir ():
63
67
return
64
68
65
- temp = pathlib .Path (tempfile .TemporaryDirectory (dir = pathlib .Path ().cwd ()).name )
66
- for item in keep :
67
- itempath = path .joinpath (item )
68
- if itempath .exists ():
69
- shutil .move (itempath , temp .joinpath (item ))
70
-
71
- shutil .rmtree (path )
72
-
73
- for item in keep :
74
- itempath = temp .joinpath (item )
75
- if itempath .exists ():
76
- shutil .move (itempath , path .joinpath (item ))
77
- directory_remove (temp )
69
+ for item in path .iterdir ():
70
+ if item .name not in keep :
71
+ if item .is_dir ():
72
+ shutil .rmtree (item )
73
+ else :
74
+ item .unlink ()
78
75
79
76
80
77
def json_read (patterns ):
@@ -151,6 +148,31 @@ def hcl2_read(patterns):
151
148
continue
152
149
with open (path , "r" ) as f :
153
150
data = deepmerge .always_merger .merge (data , hcl2 .load (f ))
151
+ return hcl2_decrypt (data )
152
+
153
+
154
+ def hcl2_decrypt (data ):
155
+ """Decrypts all strings in 'data'.
156
+
157
+ Keyword arguments:
158
+ data[any]: any HCL2-sourced data structure
159
+ """
160
+ if isinstance (data , str ) and data .startswith ("ENC[" ) and data .endswith ("]" ):
161
+ key_path = os .getenv ("STACKS_PRIVATE_KEY_PATH" )
162
+ if not key_path :
163
+ raise Exception ("could not decrypt data: STACKS_PRIVATE_KEY_PATH is not set" )
164
+ if not pathlib .Path (key_path ).exists ():
165
+ raise Exception (f"could not decrypt data: STACKS_PRIVATE_KEY_PATH ({ key_path } ) does not exist" )
166
+ return encryption_decrypt .main (data , key_path )
167
+
168
+ elif isinstance (data , list ):
169
+ for i in range (len (data )):
170
+ data [i ] = hcl2_decrypt (data [i ])
171
+
172
+ elif isinstance (data , dict ):
173
+ for k , v in data .items ():
174
+ data [k ] = hcl2_decrypt (v )
175
+
154
176
return data
155
177
156
178
@@ -167,8 +189,20 @@ def jinja2_render(patterns, data):
167
189
path = pathlib .Path (path )
168
190
if not path .is_file ():
169
191
continue
170
- with open (path , "r" ) as fin :
171
- template = jinja2 .Template (fin .read ())
172
- rendered = template .render (data )
173
- with open (path , "w" ) as fout :
174
- fout .write (rendered )
192
+ try :
193
+ with open (path , "r" ) as fin :
194
+ template = jinja2 .Template (fin .read ())
195
+
196
+ rendered = template .render (data | {
197
+ func .__name__ : func
198
+ for func in filters .__all__
199
+ })
200
+
201
+ with open (path , "w" ) as fout :
202
+ fout .write (rendered )
203
+ except jinja2 .exceptions .UndefinedError as e :
204
+ print (f"Failure to render { path } : { e } " , file = sys .stderr )
205
+ sys .exit (1 )
206
+ except jinja2 .exceptions .TemplateSyntaxError as e :
207
+ print (f"Failure to render { path } at line { e .lineno } , in statement { e .source } : { e } " , file = sys .stderr )
208
+ sys .exit (1 )
0 commit comments