git-secret-protector 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: git-secret-protector
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: A tool for managing secrets in Git with AWS Parameter Store integration.
5
5
  Author: Duc Duong
6
6
  Author-email: duc.duong@c0x12c.com
@@ -30,7 +30,6 @@ Description-Content-Type: text/markdown
30
30
  ### Requirements
31
31
 
32
32
  - pipx ([Download](https://pipx.pypa.io/stable/installation/))
33
- - Poetry ([Download](https://python-poetry.org/docs/#installation))
34
33
 
35
34
  You can install the `git-secret-protector` module via pipx:
36
35
 
@@ -42,25 +41,35 @@ pipx install git-secret-protector
42
41
 
43
42
  ### 1. Initial Setup
44
43
 
45
- Before using the tool, ensure you have the necessary AWS permissions to manage AWS MKS & SSM. Then, initialize your repository for secret protection by installing Git clean and smudge filter and setting up the module.
44
+ #### Set up AES key
45
+
46
+ Before using the tool, ensure you have the necessary AWS permissions to manage AWS MKS & SSM.
46
47
 
47
48
  ```sh
48
- git-secret-protector install
49
+ git-secret-protector init <filter_name>
49
50
  ```
50
51
 
51
- ### 2. Pull AES Key
52
+ **NOTE: Perform this setup once per repository during initial configuration.**
53
+
54
+ ### 2. Configure Git Filters
52
55
 
53
- Before encrypting or decrypting files, you need to pull the relevant AES keys from AWS Parameter Store for a specific filter:
56
+ onfigure the Git clean and smudge filters for the specified filter name
54
57
 
55
58
  ```sh
56
- git-secret-protector pull-aes-key <filter_name>
59
+ git-secret-protector init <filter_name>
57
60
  ```
58
61
 
59
- This command will pull the latest AES data key from AWS Parameter Store for the specified filter and cache it locally.
62
+ ### 3. Pull AES Key and IV
63
+
64
+ Before encrypting or decrypting files, it's necessary to retrieve the relevant AES keys from the AWS Parameter Store for specific filters:
65
+
66
+ ```sh
67
+ git-secret-protector pull-aes-key <filter_name>
68
+ ```
60
69
 
61
- This command will decrypt the files in your working directory for the specified filter, making them available for editing.
70
+ This command fetches the latest AES data key and IV from AWS Parameter Store for the designated filter and caches them locally for subsequent operations. This step ensures that you have the correct keys for encryption or decryption tasks related to the specified filter.
62
71
 
63
- ### 3. Key Rotation
72
+ ### 4. Key Rotation
64
73
 
65
74
  #### Command to Rotate Keys
66
75
 
@@ -81,7 +90,7 @@ git rm --cached -r .
81
90
  git reset --hard
82
91
  ```
83
92
 
84
- ### 4. View Encryption Status
93
+ ### 5. View Encryption Status
85
94
 
86
95
  Command to obtain a comprehensive overview of the encryption status of files within the repository:
87
96
 
@@ -93,7 +102,6 @@ git-secret-protector status
93
102
 
94
103
  All configurations are managed through a `config.ini` file located in the `.git-secret-protector` directory. You can customize the following settings:
95
104
 
96
- - **AWS Configuration**: Set your AWS region, profile, and other credentials.
97
105
  - **Logging**: Configure the log file path and rotation settings.
98
106
  - **Module Name**: Specify a custom module name for organizing keys in AWS Parameter Store.
99
107
 
@@ -102,8 +110,8 @@ All configurations are managed through a `config.ini` file located in the `.git-
102
110
  Define which files to encrypt in your `.gitattributes` file:
103
111
 
104
112
  ```
105
- secrets/*.tfstate filter=git-crypt-app diff=git-crypt-app
106
- config/**/credentials/* filter=git-crypt-shared diff=git-crypt-shared
113
+ secrets/*.tfstate filter=sample-app diff=sample-app
114
+ config/**/credentials/* filter=sample-shared diff=sample-shared
107
115
  ```
108
116
 
109
117
  ### Logging
@@ -15,7 +15,6 @@
15
15
  ### Requirements
16
16
 
17
17
  - pipx ([Download](https://pipx.pypa.io/stable/installation/))
18
- - Poetry ([Download](https://python-poetry.org/docs/#installation))
19
18
 
20
19
  You can install the `git-secret-protector` module via pipx:
21
20
 
@@ -27,25 +26,35 @@ pipx install git-secret-protector
27
26
 
28
27
  ### 1. Initial Setup
29
28
 
30
- Before using the tool, ensure you have the necessary AWS permissions to manage AWS MKS & SSM. Then, initialize your repository for secret protection by installing Git clean and smudge filter and setting up the module.
29
+ #### Set up AES key
30
+
31
+ Before using the tool, ensure you have the necessary AWS permissions to manage AWS MKS & SSM.
31
32
 
32
33
  ```sh
33
- git-secret-protector install
34
+ git-secret-protector init <filter_name>
34
35
  ```
35
36
 
36
- ### 2. Pull AES Key
37
+ **NOTE: Perform this setup once per repository during initial configuration.**
38
+
39
+ ### 2. Configure Git Filters
37
40
 
38
- Before encrypting or decrypting files, you need to pull the relevant AES keys from AWS Parameter Store for a specific filter:
41
+ onfigure the Git clean and smudge filters for the specified filter name
39
42
 
40
43
  ```sh
41
- git-secret-protector pull-aes-key <filter_name>
44
+ git-secret-protector init <filter_name>
42
45
  ```
43
46
 
44
- This command will pull the latest AES data key from AWS Parameter Store for the specified filter and cache it locally.
47
+ ### 3. Pull AES Key and IV
48
+
49
+ Before encrypting or decrypting files, it's necessary to retrieve the relevant AES keys from the AWS Parameter Store for specific filters:
50
+
51
+ ```sh
52
+ git-secret-protector pull-aes-key <filter_name>
53
+ ```
45
54
 
46
- This command will decrypt the files in your working directory for the specified filter, making them available for editing.
55
+ This command fetches the latest AES data key and IV from AWS Parameter Store for the designated filter and caches them locally for subsequent operations. This step ensures that you have the correct keys for encryption or decryption tasks related to the specified filter.
47
56
 
48
- ### 3. Key Rotation
57
+ ### 4. Key Rotation
49
58
 
50
59
  #### Command to Rotate Keys
51
60
 
@@ -66,7 +75,7 @@ git rm --cached -r .
66
75
  git reset --hard
67
76
  ```
68
77
 
69
- ### 4. View Encryption Status
78
+ ### 5. View Encryption Status
70
79
 
71
80
  Command to obtain a comprehensive overview of the encryption status of files within the repository:
72
81
 
@@ -78,7 +87,6 @@ git-secret-protector status
78
87
 
79
88
  All configurations are managed through a `config.ini` file located in the `.git-secret-protector` directory. You can customize the following settings:
80
89
 
81
- - **AWS Configuration**: Set your AWS region, profile, and other credentials.
82
90
  - **Logging**: Configure the log file path and rotation settings.
83
91
  - **Module Name**: Specify a custom module name for organizing keys in AWS Parameter Store.
84
92
 
@@ -87,8 +95,8 @@ All configurations are managed through a `config.ini` file located in the `.git-
87
95
  Define which files to encrypt in your `.gitattributes` file:
88
96
 
89
97
  ```
90
- secrets/*.tfstate filter=git-crypt-app diff=git-crypt-app
91
- config/**/credentials/* filter=git-crypt-shared diff=git-crypt-shared
98
+ secrets/*.tfstate filter=sample-app diff=sample-app
99
+ config/**/credentials/* filter=sample-shared diff=sample-shared
92
100
  ```
93
101
 
94
102
  ### Logging
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "git-secret-protector"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  description = "A tool for managing secrets in Git with AWS Parameter Store integration."
5
5
  authors = ["Duc Duong <duc.duong@c0x12c.com>"]
6
6
  readme = "README.md"
@@ -113,8 +113,7 @@ class AesKeyManager:
113
113
  try:
114
114
  self.ssm_client.get_parameter(Name=parameter_name, WithDecryption=True)
115
115
  return True
116
- except ClientError as e:
117
- logging.error("Failed to check if parameter '%s': {%s}", parameter_name, str(e))
116
+ except ClientError:
118
117
  return False
119
118
 
120
119
  def _ssm_parameter_name(self, filter_name):
@@ -1,11 +1,19 @@
1
1
  import fnmatch
2
2
  import glob
3
+ import logging
3
4
  import os
4
5
  import re
5
6
 
7
+ from git_secret_protector.settings import get_settings
8
+
9
+ logger = logging.getLogger(__name__)
10
+
6
11
 
7
12
  class GitAttributesParser:
8
- def __init__(self, git_attributes_file='.gitattributes'):
13
+ def __init__(self):
14
+ settings = get_settings()
15
+ git_attributes_file = os.path.join(settings.base_dir, '.gitattributes')
16
+
9
17
  self.git_attributes_file = git_attributes_file
10
18
  self.patterns = self._parse_patterns()
11
19
 
@@ -1,21 +1,61 @@
1
1
  import argparse
2
+ import configparser
2
3
  import logging
3
4
  import subprocess
4
5
  import sys
6
+ from pathlib import Path
5
7
 
6
8
  from git_secret_protector.aes_key_manager import AesKeyManager
7
9
  from git_secret_protector.encryption_manager import EncryptionManager
8
10
  from git_secret_protector.git_attributes_parser import GitAttributesParser
9
11
  from git_secret_protector.key_rotator import KeyRotator
10
12
  from git_secret_protector.logging import configure_logging
13
+ from git_secret_protector.settings import get_settings
11
14
 
12
15
  logger = logging.getLogger(__name__)
13
16
 
17
+ MODULE_FOLDER = '.git_secret_protector'
18
+
19
+
20
+ def init_module_folder():
21
+ module_path = Path(get_settings().module_dir)
22
+
23
+ if not module_path.exists():
24
+ module_path.mkdir(parents=True, exist_ok=True)
25
+ (module_path / 'cache').mkdir(exist_ok=True)
26
+ (module_path / 'logs').mkdir(exist_ok=True)
27
+
28
+ # Check if config.ini exists, if not, create it with default settings
29
+ config_file = module_path / 'config.ini'
30
+ if not config_file.exists():
31
+ config = configparser.ConfigParser()
32
+ config['DEFAULT'] = {
33
+ 'module_name': 'git-secret-protector',
34
+ 'log_level': 'WARN',
35
+ 'log_max_size': '10485760' # 10MB
36
+ }
37
+
38
+ with open(config_file, 'w') as configfile:
39
+ config.write(configfile)
40
+
41
+
42
+ def setup_aes_key(args):
43
+ filter_name = args.filter_name
44
+ logger.info("Set up AES key for filter: %s", filter_name)
45
+
46
+ init_module_folder()
47
+
48
+ key_manager = AesKeyManager()
49
+ key_manager.setup_aes_key_and_iv(args.filter_name)
50
+ logger.info(f"Filters for '{filter_name}' have been set up successfully.")
51
+
14
52
 
15
53
  def init_filter(args):
16
54
  filter_name = args.filter_name
17
55
  logger.info("Initializing filter: %s", filter_name)
18
56
 
57
+ init_module_folder()
58
+
19
59
  # Check for existing Git filters
20
60
  check_clean = subprocess.getoutput(f'git config --get filter.{filter_name}.clean')
21
61
  check_smudge = subprocess.getoutput(f'git config --get filter.{filter_name}.smudge')
@@ -32,10 +72,6 @@ def init_filter(args):
32
72
  subprocess.run(['git', 'config', f'filter.{filter_name}.required', 'true'], check=True)
33
73
  logger.debug("Git clean & smudge filters for '%s' have been set up successfully.", filter_name)
34
74
 
35
- key_manager = AesKeyManager()
36
- key_manager.setup_aes_key_and_iv(args.filter_name)
37
- logger.info(f"Filters for '{filter_name}' have been set up successfully.")
38
-
39
75
 
40
76
  def pull_aes_key(args):
41
77
  key_manager = AesKeyManager()
@@ -106,6 +142,33 @@ def encrypt_stdin(args):
106
142
  sys.stdout.buffer.flush()
107
143
 
108
144
 
145
+ def decrypt_files_by_filter(args):
146
+ filter_name = args.filter_name
147
+ logger.info("Decrypting files for filter: %s", filter_name)
148
+
149
+ try:
150
+ git_attributes_parser = GitAttributesParser()
151
+ files = git_attributes_parser.get_files_for_filter(filter_name)
152
+
153
+ if not files:
154
+ logger.info("No files to decrypt for filter: %s", filter_name)
155
+ return
156
+
157
+ key_manager = AesKeyManager()
158
+ aes_key, iv = key_manager.retrieve_key_and_iv(filter_name)
159
+ encryption_manager = EncryptionManager(aes_key, iv, git_attributes_parser)
160
+
161
+ for file in files:
162
+ logger.debug("Decrypting file: %s", file)
163
+ encryption_manager.decrypt_file(file)
164
+ logger.debug("Successfully decrypted: %s", file)
165
+
166
+ logger.info("All files decrypted for filter: %s", filter_name)
167
+ except Exception as e:
168
+ logger.error("Failed to decrypt files for filter %s: %s", filter_name, e)
169
+ raise
170
+
171
+
109
172
  def status_command(args):
110
173
  logger.info("Gathering status of all filters and their files...")
111
174
  git_attributes_parser = GitAttributesParser()
@@ -132,9 +195,14 @@ def main():
132
195
  subparsers = parser.add_subparsers(help="Available commands")
133
196
 
134
197
  # Command to init filter
135
- parser_setup_aes_key = subparsers.add_parser('init', help="Init a filter with AES key and update git config")
136
- parser_setup_aes_key.add_argument('filter_name', type=str, help="The filter name")
137
- parser_setup_aes_key.set_defaults(func=init_filter)
198
+ parser_init = subparsers.add_parser('init', help="Init filter actions in git config")
199
+ parser_init.add_argument('filter_name', type=str, help="The filter name")
200
+ parser_init.set_defaults(func=init_filter)
201
+
202
+ # Command to set up AES key
203
+ parser_setup_aes_key = subparsers.add_parser('setup-aes-key', help="Set up AES key for a filter")
204
+ parser_setup_aes_key.add_argument('filter_name', type=str, help="The filter name for the AES key")
205
+ parser_setup_aes_key.set_defaults(func=setup_aes_key)
138
206
 
139
207
  # Command to pull AES key
140
208
  parser_pull_aes_key = subparsers.add_parser('pull-aes-key', help="Pull AES key for a filter")
@@ -156,6 +224,11 @@ def main():
156
224
  parser_encrypt_stdin.add_argument('file_name', type=str, help="Filename for encryption")
157
225
  parser_encrypt_stdin.set_defaults(func=encrypt_stdin)
158
226
 
227
+ # Command to decrypt files for a specific filter
228
+ parser_decrypt_files = subparsers.add_parser('decrypt-files', help="Decrypt files for a specific filter")
229
+ parser_decrypt_files.add_argument('filter_name', type=str, help="The filter name whose files to decrypt")
230
+ parser_decrypt_files.set_defaults(func=decrypt_files_by_filter)
231
+
159
232
  # Status command
160
233
  parser_status = subparsers.add_parser('status', help="List all filters and file statuses")
161
234
  parser_status.set_defaults(func=status_command)
@@ -2,28 +2,45 @@ import configparser
2
2
  import os
3
3
  from dataclasses import dataclass, field
4
4
 
5
- BASE_DIR = '.git_secret_protector'
6
-
7
5
 
8
6
  @dataclass
9
7
  class Settings:
10
- _instance: 'Settings' = field(default=None, init=False, repr=False, compare=False)
8
+ BASE_DIR_LOOKUP_FOLDER = ".git"
11
9
 
12
- config_file: str = os.path.join(BASE_DIR, 'config.ini')
13
- cache_dir: str = os.path.join(BASE_DIR, 'cache')
14
- log_dir: str = os.path.join(BASE_DIR, 'logs')
10
+ _instance: 'Settings' = field(default=None, init=False, repr=False, compare=False)
11
+ module_folder: str = '.git_secret_protector'
12
+ base_dir: str = field(init=False)
13
+ module_dir: str = field(init=False)
14
+ config_file: str = field(init=False)
15
+ cache_dir: str = field(init=False)
16
+ log_dir: str = field(init=False)
15
17
  module_name: str = 'git-secret-protector'
16
- log_file: str = field(init=False, default='')
18
+ log_file: str = field(init=False)
17
19
  log_level: str = 'INFO'
18
20
  log_max_size: int = 10485760 # 10MB
19
21
  log_backup_count: int = 3
20
- config: configparser.ConfigParser = field(init=False, default=None)
22
+ config: configparser.ConfigParser = field(init=False)
21
23
 
22
24
  def __post_init__(self):
23
- self.config = configparser.ConfigParser()
25
+ self.base_dir = self.find_base_dir()
26
+ self.module_dir = os.path.join(self.base_dir, self.module_folder)
27
+ self.config_file = os.path.join(self.module_dir, 'config.ini')
28
+ self.cache_dir = os.path.join(self.module_dir, 'cache')
29
+ self.log_dir = os.path.join(self.module_dir, 'logs')
24
30
  self.log_file = os.path.join(self.log_dir, 'git_secret_protector.log')
31
+ self.config = configparser.ConfigParser()
25
32
  self._load_config()
26
33
 
34
+ def find_base_dir(self):
35
+ current_dir = os.getcwd()
36
+ while current_dir != os.path.dirname(current_dir): # Traverse up to the root directory
37
+ possible_dir = os.path.join(current_dir, Settings.BASE_DIR_LOOKUP_FOLDER)
38
+ if os.path.exists(possible_dir):
39
+ return current_dir
40
+ current_dir = os.path.dirname(current_dir)
41
+ raise FileNotFoundError(
42
+ "The git-secret-protector module folder was not found in any ascendant directories. Please ensure the module is set up correctly.")
43
+
27
44
  def _load_config(self):
28
45
  if os.path.exists(self.config_file):
29
46
  self.config.read(self.config_file)