keysloth 0.1.1 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49887eb92bcda0765f1598cff713b8820be1bf341259d22797c0b7cbce8a0ed6
4
- data.tar.gz: eaa959d6e6bd4495635dd09c53f5c6e66911f517b10639651e691d7d67cfefd4
3
+ metadata.gz: 83e6473845f54b9be85c0e72e3c07cd8f9230ae11c2e8c1fe13284eebcc70c68
4
+ data.tar.gz: b6aac32a358a3fd948fa24234211197fac62173d9b8e4e5120c6db6731082488
5
5
  SHA512:
6
- metadata.gz: 4be3619d2eb8e824132985421b8ea5b7853921dae1e42962543ee313bb6e59bdb8e9091b454781e441a112fe7e35f4aba769e0293ae55bb084de0c4c1cb5f107
7
- data.tar.gz: 933bf6a35dce1daebd282f90627fad87f13660089b6972044ba68b939d05572b50bf0fa39b357a8bd01417f31e64dae58c339c801dc987b7dd0312fec622ccea
6
+ metadata.gz: cdeaadbacf945fab4594cd19c1692c1ee35333f99bd71a678def06411a91252eda8292a2ceac8495fa0bd1b7b3e55013fceac558ec241f4db8110e6980610faa
7
+ data.tar.gz: 7855a1388754df2d9db3732470aabbc3ac933ed0b01b917f1110f34769e1ac1cf8475fd0e51c1dbe98483c15e932206b622609f719a9ec1b681a9f94e7ce4bc5
data/Appraisals ADDED
@@ -0,0 +1,9 @@
1
+ appraise 'thor-1.0' do
2
+ gem 'thor', '1.0.1'
3
+ end
4
+
5
+ appraise 'thor-1.3' do
6
+ gem 'thor', '~> 1.3.2'
7
+ end
8
+
9
+
data/CHANGELOG.md CHANGED
@@ -5,7 +5,36 @@
5
5
  Формат основан на [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  и этот проект придерживается [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
8
+ ## [Released]
9
+
10
+ ## [0.2.0] - 2025-09-04
11
+
12
+ ### Added
13
+ - Поддержка произвольных типов файлов для шифрования/дешифрования (wildcard extensions)
14
+
15
+ ### Changed
16
+ - Сбор входных файлов: рекурсивно все обычные файлы, исключая `*.enc`, `.git/**`, `.DS_Store`, `Thumbs.db`, локальный `README.md`
17
+ - Перевод всех I/O операций на бинарные методы `File.binread`/`File.binwrite`
18
+ - Обновлены проверки целостности: работают с бинарными данными
19
+ - Обновлены CLI help и README для отражения поддержки любых типов
20
+ - Улучшены сообщения об ошибках SSH: подсказки для `Permission denied (publickey)`, `Host key verification failed`, `Repository not found`
21
+ - Улучшена читаемость логов CLI: добавлены явные маркеры начала/конца выполнения команд, эмодзи ✅ для успешных действий и ⛔ для ошибок
22
+ - Расширен диапазон совместимости с Thor: теперь `'>= 1.0.1', '< 1.4.0'`
23
+
24
+ ### Fixed
25
+ - Исправлено: параметр `backup_count` из `.keyslothrc` ранее игнорировался (всегда хранилось 3 бэкапа). Теперь значение конфигурации применяется, а `backup_count: 0` корректно отключает создание и ротацию бэкапов.
26
+ - Исправлено: значения `branch` и `local_path` из `.keyslothrc` игнорировались при использовании CLI из-за дефолтов в опциях. Дефолты в CLI убраны; приоритет теперь корректный: CLI > конфиг > дефолты. Документация обновлена (автопоиск и дефолты).
27
+ - Исправлено: `keysloth status` падал при форматировании времени backup'ов на некоторых окружениях (`Time.strptime` недоступен). Добавлено `require 'time'` и безопасный парсинг с `rescue`.
28
+ - Исправлено: команды `status`, `validate`, `restore` игнорировали `local_path` из `.keyslothrc`. Теперь при отсутствии `--path` путь берётся из конфигурации (или дефолта), а при наличии флага — имеет приоритет.
29
+
30
+ ### Tests
31
+ - Обновлены и расширены тесты `file_manager_spec` и `git_manager_spec` под wildcard и бинарный I/O
32
+ - Добавлены тесты на подсказки SSH-ошибок в `git_manager_spec`
33
+
34
+ ### Docs
35
+ - README: заменён раздел «Поддерживаемые типы» на «Типы файлов (любые)» и добавлены исключения
36
+ - Обновлён test_plan с учётом новых сценариев
37
+ - README: добавлены примеры с `ed25519` и переменной `KEYSLOTH_SSH_KEY_PATH`
9
38
 
10
39
  ## [0.1.1] - 2025-09-02
11
40
 
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Surf
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # KeySloth
2
2
 
3
+ ![SwiftObfuscator](keysloth.png)
4
+
3
5
  Ruby gem для безопасного управления зашифрованными секретами в Git репозиториях.
4
6
 
5
7
  ## Описание
@@ -15,12 +17,15 @@ KeySloth решает проблему безопасного хранения
15
17
  - 📦 **Backup'ы**: Автоматическое создание резервных копий
16
18
  - 🎯 **CI/CD готовность**: Поддержка переменных окружения для автоматизации
17
19
 
18
- ### Поддерживаемые типы файлов
20
+ ### Типы файлов
21
+
22
+ Поддерживаются любые типы файлов (сертификаты, конфиги, изображения, бинарные и т.д.).
19
23
 
20
- - `.cer` - сертификаты
21
- - `.p12` - PKCS#12 сертификаты
22
- - `.mobileprovisioning` - профили подготовки iOS
23
- - `.json` - конфигурационные файлы
24
+ По умолчанию игнорируются при сборе и шифровании:
25
+ - `*.enc` (зашифрованные артефакты в репозитории)
26
+ - содержимое `.git/`
27
+ - `.DS_Store`, `Thumbs.db`
28
+ - локальный `README.md` в директории секретов
24
29
 
25
30
  ## Зависимости
26
31
 
@@ -107,6 +112,7 @@ keysloth push --repo git@github.com:company/secrets.git \
107
112
 
108
113
  ```bash
109
114
  keysloth status --path ./secrets
115
+ # без --path возьмёт путь из .keyslothrc (или дефолт)
110
116
  ```
111
117
 
112
118
  #### restore - Восстановление из backup'а
@@ -115,6 +121,7 @@ keysloth status --path ./secrets
115
121
 
116
122
  ```bash
117
123
  keysloth restore secrets_backup_20231215_143022 --path ./secrets
124
+ # без --path возьмёт путь из .keyslothrc (или дефолт)
118
125
  ```
119
126
 
120
127
  ### Конфигурационный файл
@@ -131,6 +138,16 @@ backup_count: 3
131
138
 
132
139
  Параметры командной строки имеют приоритет над конфигурационным файлом.
133
140
 
141
+ Дополнительно: файл конфигурации ищется автоматически, если путь не указан флагом `--config`:
142
+ - сначала в текущей директории (`./.keyslothrc`)
143
+ - затем в домашней директории (`~/.keyslothrc`)
144
+
145
+ Дефолтные значения при отсутствии флагов CLI и отсутствующих полях в конфиге:
146
+ - `branch`: `main`
147
+ - `local_path`: `./secrets`
148
+ - `backup_count`: `3`
149
+ - `repo_url`: отсутствует (должен быть указан явно через CLI или в конфиге)
150
+
134
151
  ### Логирование
135
152
 
136
153
  KeySloth поддерживает три уровня логирования:
@@ -165,10 +182,14 @@ KeySloth обеспечивает многоуровневую защиту:
165
182
 
166
183
  ```bash
167
184
  # Генерируем SSH ключ если нет
168
- ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
185
+ ssh-keygen -t rsa -b 4096 -C "your_email@example.com" # RSA
186
+ # или современный вариант:
187
+ ssh-keygen -t ed25519 -C "your_email@example.com" # Ed25519
169
188
 
170
189
  # Добавляем публичный ключ в GitHub/GitLab
171
190
  cat ~/.ssh/id_rsa.pub
191
+ # или
192
+ cat ~/.ssh/id_ed25519.pub
172
193
  ```
173
194
 
174
195
  #### CI/CD настройка
@@ -177,8 +198,8 @@ cat ~/.ssh/id_rsa.pub
177
198
 
178
199
  ```bash
179
200
  # Экспортируем SSH ключ в переменную окружения
180
- export SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)"
181
- export SSH_PUBLIC_KEY="$(cat ~/.ssh/id_rsa.pub)"
201
+ export SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)" # может быть RSA или Ed25519
202
+ export SSH_PUBLIC_KEY="$(cat ~/.ssh/id_rsa.pub)" # опционально
182
203
 
183
204
  # Используем в CI/CD
184
205
  keysloth pull -r git@github.com:company/secrets.git -p $SECRET_PASSWORD
@@ -194,6 +215,12 @@ export GIT_SSH_COMMAND='ssh -i /tmp/keysloth_ssh/id_rsa -o IdentitiesOnly=yes -o
194
215
 
195
216
  Для локальной разработки отключать проверку хостов не рекомендуется.
196
217
 
218
+ Также можно явно указать путь к ключу через переменную окружения `KEYSLOTH_SSH_KEY_PATH` (поддерживаются как RSA, так и Ed25519):
219
+
220
+ ```bash
221
+ export KEYSLOTH_SSH_KEY_PATH="~/.ssh/id_ed25519"
222
+ ```
223
+
197
224
  #### Требования к автору коммита
198
225
 
199
226
  Перед отправкой изменений должны быть настроены глобальные параметры Git:
@@ -342,6 +369,8 @@ ssh-add -l
342
369
 
343
370
  # Добавьте SSH ключ если необходимо
344
371
  ssh-add ~/.ssh/id_rsa
372
+ # или
373
+ ssh-add ~/.ssh/id_ed25519
345
374
 
346
375
  # Проверьте соединение с GitHub/GitLab
347
376
  ssh -T git@github.com
@@ -0,0 +1,18 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "thor", "1.0.1"
6
+
7
+ group :development, :test do
8
+ gem "pry", "~> 0.14"
9
+ gem "rake", "~> 13.0"
10
+ gem "appraisal", "~> 2.5"
11
+ end
12
+
13
+ group :test do
14
+ gem "timecop", "~> 0.9"
15
+ gem "webmock", "~> 3.18"
16
+ end
17
+
18
+ gemspec path: "../"
@@ -0,0 +1,18 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "thor", "~> 1.3.2"
6
+
7
+ group :development, :test do
8
+ gem "pry", "~> 0.14"
9
+ gem "rake", "~> 13.0"
10
+ gem "appraisal", "~> 2.5"
11
+ end
12
+
13
+ group :test do
14
+ gem "timecop", "~> 0.9"
15
+ gem "webmock", "~> 3.18"
16
+ end
17
+
18
+ gemspec path: "../"
data/keysloth.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
6
6
  spec.name = 'keysloth'
7
7
  spec.version = KeySloth::VERSION
8
8
  spec.authors = ['KeySloth Team']
9
- spec.email = ['team@keysloth.org']
9
+ spec.email = ['chausov@surf.dev']
10
10
 
11
11
  spec.summary = 'Ruby gem для управления зашифрованными секретами в Git репозиториях'
12
12
  spec.description = <<~DESC
@@ -15,14 +15,14 @@ Gem::Specification.new do |spec|
15
15
  Обеспечивает простое получение, изменение и отправку секретов с использованием#{' '}
16
16
  AES-256-GCM шифрования.
17
17
  DESC
18
- spec.homepage = 'https://github.com/keysloth/keysloth'
18
+ spec.homepage = 'https://github.com/chausovSurfStudio/keysloth'
19
19
  spec.license = 'MIT'
20
20
  spec.required_ruby_version = '>= 2.7.0'
21
21
 
22
22
  spec.metadata['allowed_push_host'] = 'https://rubygems.org'
23
23
  spec.metadata['homepage_uri'] = spec.homepage
24
- spec.metadata['source_code_uri'] = 'https://github.com/keysloth/keysloth'
25
- spec.metadata['changelog_uri'] = 'https://github.com/keysloth/keysloth/blob/main/CHANGELOG.md'
24
+ spec.metadata['source_code_uri'] = 'https://github.com/chausovSurfStudio/keysloth'
25
+ spec.metadata['changelog_uri'] = 'https://github.com/chausovSurfStudio/keysloth/blob/main/CHANGELOG.md'
26
26
  spec.metadata['rubygems_mfa_required'] = 'true'
27
27
 
28
28
  # Определяем, какие файлы включить в gem
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
37
37
  spec.require_paths = ['lib']
38
38
 
39
39
  # Основные зависимости
40
- spec.add_dependency 'thor', '~> 1.2' # CLI интерфейс
40
+ spec.add_dependency 'thor', '>= 1.0.1', '< 1.4.0' # CLI интерфейс
41
41
  # Используем системные git команды вместо rugged для упрощения установки
42
42
  # Используем встроенный openssl, доступный в Ruby по умолчанию
43
43
 
data/keysloth.png ADDED
Binary file
data/lib/keysloth/cli.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'thor'
4
+ require 'time'
4
5
 
5
6
  module KeySloth
6
7
  # Интерфейс командной строки для KeySloth
@@ -34,27 +35,21 @@ module KeySloth
34
35
  из указанной ветки, расшифровывает их с использованием предоставленного пароля
35
36
  и сохраняет в локальную директорию.
36
37
 
37
- Поддерживаемые типы файлов секретов:
38
- - .cer (сертификаты)
39
- - .p12 (PKCS#12 сертификаты)
40
- - .mobileprovisioning (профили подготовки iOS)
41
- - .json (конфигурационные файлы)
42
-
43
38
  Перед выполнением операции автоматически создается резервная копия
44
39
  существующей локальной директории с секретами.
45
40
  DESC
46
41
  option :repo, type: :string, aliases: '-r',
47
42
  desc: 'URL Git репозитория (SSH: git@github.com:user/repo.git)'
48
- option :branch, type: :string, default: 'main', aliases: '-b',
43
+ option :branch, type: :string, aliases: '-b',
49
44
  desc: 'Ветка репозитория для получения секретов'
50
45
  option :password, type: :string, required: true, aliases: '-p',
51
46
  desc: 'Пароль для расшифровки секретов'
52
- option :path, type: :string, default: './secrets', aliases: '-d',
47
+ option :path, type: :string, aliases: '-d',
53
48
  desc: 'Локальный путь для сохранения расшифрованных секретов'
54
49
  def pull
55
50
  setup_logger
56
51
 
57
- logger.info('=== Начинаем операцию получения секретов ===')
52
+ logger.info("\n=== Начинаем операцию получения секретов ===")
58
53
 
59
54
  begin
60
55
  KeySloth.pull(
@@ -65,9 +60,9 @@ module KeySloth
65
60
  config_file: options[:config]
66
61
  )
67
62
 
68
- logger.info('=== Операция получения секретов завершена успешно ===')
63
+ logger.info("✅ Операция получения секретов завершена успешно\n")
69
64
  rescue KeySloth::KeySlothError => e
70
- logger.error("Ошибка выполнения операции: #{e.message}")
65
+ logger.error("Ошибка выполнения операции: #{e.message}")
71
66
  exit 1
72
67
  end
73
68
  end
@@ -82,26 +77,21 @@ module KeySloth
82
77
  При обнаружении конфликтов операция прекращается с детальным сообщением
83
78
  об ошибке.
84
79
 
85
- Поддерживаемые типы файлов секретов:
86
- - .cer (сертификаты)
87
- - .p12 (PKCS#12 сертификаты)#{' '}
88
- - .mobileprovisioning (профили подготовки iOS)
89
- - .json (конфигурационные файлы)
90
80
  DESC
91
81
  option :repo, type: :string, aliases: '-r',
92
82
  desc: 'URL Git репозитория (SSH: git@github.com:user/repo.git)'
93
- option :branch, type: :string, default: 'main', aliases: '-b',
83
+ option :branch, type: :string, aliases: '-b',
94
84
  desc: 'Ветка репозитория для отправки секретов'
95
85
  option :password, type: :string, required: true, aliases: '-p',
96
86
  desc: 'Пароль для шифрования секретов'
97
- option :path, type: :string, default: './secrets', aliases: '-d',
87
+ option :path, type: :string, aliases: '-d',
98
88
  desc: 'Локальный путь с секретами для шифрования'
99
89
  option :message, type: :string, aliases: '-m',
100
90
  desc: 'Сообщение коммита (опционально)'
101
91
  def push
102
92
  setup_logger
103
93
 
104
- logger.info('=== Начинаем операцию отправки секретов ===')
94
+ logger.info("\n=== Начинаем операцию отправки секретов ===")
105
95
 
106
96
  begin
107
97
  KeySloth.push(
@@ -113,9 +103,9 @@ module KeySloth
113
103
  commit_message: options[:message]
114
104
  )
115
105
 
116
- logger.info('=== Операция отправки секретов завершена успешно ===')
106
+ logger.info("✅ Операция отправки секретов завершена успешно\n")
117
107
  rescue KeySloth::KeySlothError => e
118
- logger.error("Ошибка выполнения операции: #{e.message}")
108
+ logger.error("Ошибка выполнения операции: #{e.message}")
119
109
  exit 1
120
110
  end
121
111
  end
@@ -128,7 +118,7 @@ module KeySloth
128
118
  - Информацию о доступных резервных копиях
129
119
  - Проверку целостности файлов
130
120
  DESC
131
- option :path, type: :string, default: './secrets', aliases: '-d',
121
+ option :path, type: :string, aliases: '-d',
132
122
  desc: 'Локальный путь с секретами для проверки'
133
123
  def status
134
124
  setup_logger
@@ -137,14 +127,17 @@ module KeySloth
137
127
 
138
128
  begin
139
129
  file_manager = FileManager.new(logger)
130
+ # Выбор пути: CLI -> конфиг -> дефолт
131
+ config = Config.load(options[:config])
132
+ resolved_path = options[:path] || config[:local_path] || Config::DEFAULT_CONFIG[:local_path]
140
133
 
141
- unless file_manager.directory_exists?(options[:path])
142
- logger.warn("Директория секретов не существует: #{options[:path]}")
134
+ unless file_manager.directory_exists?(resolved_path)
135
+ logger.warn("Директория секретов не существует: #{resolved_path}")
143
136
  return
144
137
  end
145
138
 
146
139
  # Собираем файлы секретов
147
- secret_files = file_manager.collect_secret_files(options[:path])
140
+ secret_files = file_manager.collect_secret_files(resolved_path)
148
141
 
149
142
  if secret_files.empty?
150
143
  logger.info('Файлы секретов не найдены')
@@ -155,21 +148,27 @@ module KeySloth
155
148
 
156
149
  secret_files.each do |file_path|
157
150
  size = File.size(file_path)
158
- relative_path = file_manager.get_relative_path(file_path, options[:path])
151
+ relative_path = file_manager.get_relative_path(file_path, resolved_path)
159
152
  integrity = file_manager.verify_file_integrity(file_path) ? '✓' : '✗'
160
153
 
161
154
  logger.info(" #{integrity} #{relative_path} (#{size} байт)")
162
155
  end
163
156
 
164
157
  # Показываем информацию о backup'ах
165
- backups = file_manager.list_backups(options[:path])
158
+ backups = file_manager.list_backups(resolved_path)
166
159
  if backups.any?
167
160
  logger.info("\nДоступные резервные копии:")
168
161
  backups.each do |backup_path|
169
162
  backup_time = File.basename(backup_path).match(/_(\d{8}_\d{6})$/)&.captures&.first
170
- if backup_time
171
- formatted_time = Time.strptime(backup_time,
172
- '%Y%m%d_%H%M%S').strftime('%Y-%m-%d %H:%M:%S')
163
+ formatted_time = begin
164
+ if backup_time
165
+ Time.strptime(backup_time, '%Y%m%d_%H%M%S').strftime('%Y-%m-%d %H:%M:%S')
166
+ end
167
+ rescue StandardError
168
+ nil
169
+ end
170
+
171
+ if formatted_time
173
172
  logger.info(" #{File.basename(backup_path)} (#{formatted_time})")
174
173
  else
175
174
  logger.info(" #{File.basename(backup_path)}")
@@ -179,7 +178,7 @@ module KeySloth
179
178
  logger.info("\nРезервные копии не найдены")
180
179
  end
181
180
  rescue KeySloth::KeySlothError => e
182
- logger.error("Ошибка проверки состояния: #{e.message}")
181
+ logger.error("Ошибка проверки состояния: #{e.message}")
183
182
  exit 1
184
183
  end
185
184
  end
@@ -190,20 +189,22 @@ module KeySloth
190
189
  резервной копии. Используйте команду 'status' для просмотра
191
190
  доступных резервных копий.
192
191
  DESC
193
- option :path, type: :string, default: './secrets', aliases: '-d',
192
+ option :path, type: :string, aliases: '-d',
194
193
  desc: 'Локальный путь для восстановления секретов'
195
194
  def restore(backup_path)
196
195
  setup_logger
197
196
 
198
- logger.info('=== Восстанавливаем секреты из резервной копии ===')
197
+ logger.info("\n=== Восстанавливаем секреты из резервной копии ===")
199
198
 
200
199
  begin
201
200
  file_manager = FileManager.new(logger)
202
- file_manager.restore_from_backup(backup_path, options[:path])
201
+ config = Config.load(options[:config])
202
+ resolved_path = options[:path] || config[:local_path] || Config::DEFAULT_CONFIG[:local_path]
203
+ file_manager.restore_from_backup(backup_path, resolved_path)
203
204
 
204
- logger.info('=== Восстановление завершено успешно ===')
205
+ logger.info("✅ Восстановление завершено успешно\n")
205
206
  rescue KeySloth::KeySlothError => e
206
- logger.error("Ошибка восстановления: #{e.message}")
207
+ logger.error("Ошибка восстановления: #{e.message}")
207
208
  exit 1
208
209
  end
209
210
  end
@@ -217,23 +218,25 @@ module KeySloth
217
218
  - Валидирует структуру файлов секретов
218
219
  - Выводит детальный отчет о состоянии каждого файла
219
220
  DESC
220
- option :path, type: :string, default: './secrets', aliases: '-d',
221
+ option :path, type: :string, aliases: '-d',
221
222
  desc: 'Локальный путь с секретами для проверки'
222
223
  def validate
223
224
  setup_logger
224
225
 
225
- logger.info('=== Проверяем целостность файлов секретов ===')
226
+ logger.info("\n=== Проверяем целостность файлов секретов ===")
226
227
 
227
228
  begin
228
229
  file_manager = FileManager.new(logger)
230
+ config = Config.load(options[:config])
231
+ resolved_path = options[:path] || config[:local_path] || Config::DEFAULT_CONFIG[:local_path]
229
232
 
230
- unless file_manager.directory_exists?(options[:path])
231
- logger.error("Директория секретов не существует: #{options[:path]}")
233
+ unless file_manager.directory_exists?(resolved_path)
234
+ logger.error("Директория секретов не существует: #{resolved_path}")
232
235
  exit 1
233
236
  end
234
237
 
235
238
  # Собираем файлы секретов
236
- secret_files = file_manager.collect_secret_files(options[:path])
239
+ secret_files = file_manager.collect_secret_files(resolved_path)
237
240
 
238
241
  if secret_files.empty?
239
242
  logger.warn('Файлы секретов не найдены')
@@ -246,7 +249,7 @@ module KeySloth
246
249
  invalid_files = 0
247
250
 
248
251
  secret_files.each do |file_path|
249
- relative_path = file_manager.get_relative_path(file_path, options[:path])
252
+ relative_path = file_manager.get_relative_path(file_path, resolved_path)
250
253
 
251
254
  if file_manager.verify_file_integrity(file_path)
252
255
  logger.info(" ✓ #{relative_path} - файл корректен")
@@ -263,13 +266,14 @@ module KeySloth
263
266
  logger.info("Поврежденных файлов: #{invalid_files}")
264
267
 
265
268
  if invalid_files.positive?
266
- logger.error("Обнаружены поврежденные файлы! Рекомендуется восстановление из backup'а.")
269
+ logger.error("Обнаружены поврежденные файлы! Рекомендуется восстановление из backup'а.")
267
270
  exit 1
268
271
  else
269
272
  logger.info('Все файлы секретов прошли проверку целостности.')
273
+ logger.info("✅ Проверка целостности завершена успешно\n")
270
274
  end
271
275
  rescue KeySloth::KeySlothError => e
272
- logger.error("Ошибка проверки целостности: #{e.message}")
276
+ logger.error("Ошибка проверки целостности: #{e.message}")
273
277
  exit 1
274
278
  end
275
279
  end
@@ -295,7 +299,7 @@ module KeySloth
295
299
  def init
296
300
  setup_logger
297
301
 
298
- logger.info('=== Инициализируем KeySloth проект ===')
302
+ logger.info("\n=== Инициализируем KeySloth проект ===")
299
303
 
300
304
  begin
301
305
  file_manager = FileManager.new(logger)
@@ -366,11 +370,12 @@ module KeySloth
366
370
  keysloth status
367
371
  ```
368
372
 
369
- ## Поддерживаемые типы файлов
370
- - `.cer` - сертификаты
371
- - `.p12` - PKCS#12 сертификаты
372
- - `.mobileprovisioning` - профили подготовки iOS
373
- - `.json` - конфигурационные файлы
373
+ ## Типы файлов
374
+ Поддерживаются любые типы файлов. По умолчанию игнорируются:
375
+ - `*.enc` (артефакты шифрования)
376
+ - содержимое `.git/`
377
+ - `.DS_Store`, `Thumbs.db`
378
+ - локальный `README.md` в этой директории
374
379
 
375
380
  **ВНИМАНИЕ:** Никогда не коммитьте эту директорию в Git!
376
381
  MARKDOWN
@@ -378,16 +383,16 @@ module KeySloth
378
383
  File.write(readme_path, readme_content)
379
384
  logger.info("Создан файл справки: #{readme_path}")
380
385
 
381
- logger.info("\n=== Инициализация завершена успешно ===")
386
+ logger.info("\n Инициализация завершена успешно\n")
382
387
  logger.info('Следующие шаги:')
383
388
  logger.info("1. Поместите ваши файлы секретов в #{secrets_path}/")
384
389
  logger.info("2. Используйте 'keysloth push' для первой отправки секретов")
385
390
  logger.info('3. Поделитесь паролем шифрования с командой')
386
391
  rescue KeySloth::KeySlothError => e
387
- logger.error("Ошибка инициализации: #{e.message}")
392
+ logger.error("Ошибка инициализации: #{e.message}")
388
393
  exit 1
389
394
  rescue StandardError => e
390
- logger.error("Неожиданная ошибка: #{e.message}")
395
+ logger.error("Неожиданная ошибка: #{e.message}")
391
396
  exit 1
392
397
  end
393
398
  end