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 +4 -4
- data/Appraisals +9 -0
- data/CHANGELOG.md +30 -1
- data/LICENSE +21 -0
- data/README.md +37 -8
- data/gemfiles/thor_1.0.gemfile +18 -0
- data/gemfiles/thor_1.3.gemfile +18 -0
- data/keysloth.gemspec +5 -5
- data/keysloth.png +0 -0
- data/lib/keysloth/cli.rb +58 -53
- data/lib/keysloth/file_manager.rb +34 -12
- data/lib/keysloth/git_manager.rb +31 -5
- data/lib/keysloth/version.rb +1 -1
- data/lib/keysloth.rb +17 -4
- data/promts/main/rules.md +16 -0
- data/promts/outdated/feature_wildcard_extensions.md +62 -0
- data/promts/outdated/fix_backups.md +49 -0
- data/promts/outdated/fix_config_file.md +47 -0
- data/promts/outdated/fix_ssh.md +77 -0
- data/promts/outdated/thor-updates.md +38 -0
- data/promts/task_lists_for_human/release_task_list.md +60 -0
- data/{task → promts/task_lists_for_human}/test_plan.md +8 -89
- metadata +33 -16
- data/task/cr.md +0 -59
- /data/{task → promts/main}/task.md +0 -0
- /data/{task/ragged_removing.md → promts/outdated/feature_ragged_removing.md} +0 -0
- /data/{task → promts/outdated}/plan.md +0 -0
|
@@ -25,8 +25,6 @@ module KeySloth
|
|
|
25
25
|
# @author KeySloth Team
|
|
26
26
|
# @since 0.1.0
|
|
27
27
|
class FileManager
|
|
28
|
-
# Поддерживаемые расширения файлов секретов
|
|
29
|
-
SECRET_FILE_EXTENSIONS = %w[.cer .p12 .mobileprovisioning .json].freeze
|
|
30
28
|
|
|
31
29
|
# Максимальное количество backup'ов
|
|
32
30
|
DEFAULT_BACKUP_COUNT = 3
|
|
@@ -75,7 +73,7 @@ module KeySloth
|
|
|
75
73
|
@logger.debug("Читаем файл: #{file_path}")
|
|
76
74
|
|
|
77
75
|
begin
|
|
78
|
-
content = File.
|
|
76
|
+
content = File.binread(file_path)
|
|
79
77
|
@logger.debug("Файл прочитан успешно (размер: #{content.length} байт)")
|
|
80
78
|
content
|
|
81
79
|
rescue StandardError => e
|
|
@@ -97,7 +95,7 @@ module KeySloth
|
|
|
97
95
|
directory = File.dirname(file_path)
|
|
98
96
|
ensure_directory(directory) unless directory_exists?(directory)
|
|
99
97
|
|
|
100
|
-
File.
|
|
98
|
+
File.binwrite(file_path, content)
|
|
101
99
|
@logger.debug("Файл записан успешно (размер: #{content.length} байт)")
|
|
102
100
|
rescue StandardError => e
|
|
103
101
|
@logger.error('Ошибка записи файла', e)
|
|
@@ -105,7 +103,13 @@ module KeySloth
|
|
|
105
103
|
end
|
|
106
104
|
end
|
|
107
105
|
|
|
108
|
-
# Собирает все файлы секретов из директории
|
|
106
|
+
# Собирает все файлы секретов из директории (wildcard)
|
|
107
|
+
#
|
|
108
|
+
# Рекурсивно собирает любые обычные файлы, исключая:
|
|
109
|
+
# - .enc файлы (они являются артефактами репозитория)
|
|
110
|
+
# - содержимое .git директорий
|
|
111
|
+
# - общеизвестные мусорные файлы (.DS_Store, Thumbs.db)
|
|
112
|
+
# - локальный README.md внутри каталога секретов
|
|
109
113
|
#
|
|
110
114
|
# @param directory_path [String] Путь к директории с секретами
|
|
111
115
|
# @return [Array<String>] Массив путей к файлам секретов
|
|
@@ -116,11 +120,24 @@ module KeySloth
|
|
|
116
120
|
begin
|
|
117
121
|
validate_directory_access!(directory_path)
|
|
118
122
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
all_candidates = Dir.glob(File.join(directory_path, '**', '*'), File::FNM_DOTMATCH)
|
|
124
|
+
|
|
125
|
+
files = all_candidates.select do |path|
|
|
126
|
+
next false unless File.file?(path)
|
|
127
|
+
|
|
128
|
+
relative = get_relative_path(path, directory_path)
|
|
129
|
+
|
|
130
|
+
# Исключаем .git содержимое
|
|
131
|
+
next false if relative.split(File::SEPARATOR).include?('.git')
|
|
132
|
+
|
|
133
|
+
# Исключаем артефакты шифрования
|
|
134
|
+
next false if File.extname(path).downcase == '.enc'
|
|
135
|
+
|
|
136
|
+
# Исключаем общеизвестный мусор и локальный README.md
|
|
137
|
+
base = File.basename(path)
|
|
138
|
+
next false if base == '.DS_Store' || base == 'Thumbs.db' || base == 'README.md'
|
|
139
|
+
|
|
140
|
+
true
|
|
124
141
|
end
|
|
125
142
|
|
|
126
143
|
@logger.info("Найдено #{files.size} файлов секретов")
|
|
@@ -147,6 +164,8 @@ module KeySloth
|
|
|
147
164
|
# @raise [FileSystemError] при ошибках создания backup'а
|
|
148
165
|
def create_backup(directory_path)
|
|
149
166
|
return nil unless directory_exists?(directory_path)
|
|
167
|
+
# Отключение бэкапов: при нулевом или отрицательном лимите
|
|
168
|
+
return nil if @backup_count.to_i <= 0
|
|
150
169
|
|
|
151
170
|
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
|
152
171
|
backup_name = "#{File.basename(directory_path)}_backup_#{timestamp}"
|
|
@@ -217,7 +236,7 @@ module KeySloth
|
|
|
217
236
|
|
|
218
237
|
# Базовая проверка на читаемость
|
|
219
238
|
begin
|
|
220
|
-
content = File.
|
|
239
|
+
content = File.binread(file_path, 100) # Читаем первые 100 байт для проверки
|
|
221
240
|
|
|
222
241
|
# Дополнительная проверка по типу файла
|
|
223
242
|
file_extension = File.extname(file_path).downcase
|
|
@@ -254,7 +273,7 @@ module KeySloth
|
|
|
254
273
|
return result unless result[:non_empty]
|
|
255
274
|
|
|
256
275
|
# Проверяем читаемость
|
|
257
|
-
content = File.
|
|
276
|
+
content = File.binread(file_path, 200) # Читаем больше для детальной проверки
|
|
258
277
|
result[:readable] = true
|
|
259
278
|
|
|
260
279
|
# Проверяем соответствие типу файла
|
|
@@ -322,6 +341,9 @@ module KeySloth
|
|
|
322
341
|
# @param parent_dir [String] Родительская директория
|
|
323
342
|
# @param base_name [String] Базовое имя директории
|
|
324
343
|
def cleanup_old_backups(parent_dir, base_name)
|
|
344
|
+
# При отключённых бэкапах не удаляем существующие
|
|
345
|
+
return if @backup_count.to_i <= 0
|
|
346
|
+
|
|
325
347
|
backups = list_backups(File.join(parent_dir, base_name))
|
|
326
348
|
|
|
327
349
|
return if backups.size <= @backup_count
|
data/lib/keysloth/git_manager.rb
CHANGED
|
@@ -108,7 +108,7 @@ module KeySloth
|
|
|
108
108
|
FileUtils.mkdir_p(File.dirname(file_path))
|
|
109
109
|
|
|
110
110
|
# Записываем файл
|
|
111
|
-
File.
|
|
111
|
+
File.binwrite(file_path, file_data[:content])
|
|
112
112
|
@logger.debug("Записан файл: #{file_data[:path]}")
|
|
113
113
|
end
|
|
114
114
|
rescue StandardError => e
|
|
@@ -271,7 +271,7 @@ module KeySloth
|
|
|
271
271
|
|
|
272
272
|
files << {
|
|
273
273
|
name: relative_path,
|
|
274
|
-
content: File.
|
|
274
|
+
content: File.binread(full_path)
|
|
275
275
|
}
|
|
276
276
|
end
|
|
277
277
|
|
|
@@ -332,9 +332,9 @@ module KeySloth
|
|
|
332
332
|
private_key_path = File.join(@ssh_tmp_dir, 'id_rsa')
|
|
333
333
|
public_key_path = File.join(@ssh_tmp_dir, 'id_rsa.pub')
|
|
334
334
|
|
|
335
|
-
File.
|
|
335
|
+
File.binwrite(private_key_path, ENV['SSH_PRIVATE_KEY'])
|
|
336
336
|
File.chmod(0o600, private_key_path)
|
|
337
|
-
File.
|
|
337
|
+
File.binwrite(public_key_path, ENV['SSH_PUBLIC_KEY']) if ENV['SSH_PUBLIC_KEY']
|
|
338
338
|
|
|
339
339
|
# В CI отключаем проверку хостов (опционально)
|
|
340
340
|
return %(ssh -i #{private_key_path} -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null)
|
|
@@ -381,7 +381,33 @@ module KeySloth
|
|
|
381
381
|
return [stdout, stderr] if allow_failure
|
|
382
382
|
|
|
383
383
|
base_msg = (stderr.strip.empty? ? stdout.strip : stderr.strip)
|
|
384
|
-
|
|
384
|
+
|
|
385
|
+
# Расширенные подсказки для типовых SSH/Git ошибок
|
|
386
|
+
extra_advice = nil
|
|
387
|
+
lower = base_msg.downcase
|
|
388
|
+
if lower.include?('permission denied (publickey)')
|
|
389
|
+
extra_advice = [
|
|
390
|
+
'Совет: SSH-ключ не найден или не принят.',
|
|
391
|
+
'1) Проверьте ключи в агенте: ssh-add -l (или загрузите: ssh-add ~/.ssh/id_ed25519)',
|
|
392
|
+
'2) Укажите ключ явно: export KEYSLOTH_SSH_KEY_PATH=~/.ssh/id_ed25519 (или используйте SSH_PRIVATE_KEY в CI)',
|
|
393
|
+
'3) Проверьте права на ключ: chmod 600 ~/.ssh/<key>'
|
|
394
|
+
].join("\n")
|
|
395
|
+
elsif lower.include?('host key verification failed')
|
|
396
|
+
extra_advice = [
|
|
397
|
+
'Совет: Не пройдена проверка ключа хоста.',
|
|
398
|
+
'1) Добавьте хост в known_hosts: ssh-keyscan <host> >> ~/.ssh/known_hosts',
|
|
399
|
+
'2) Избегайте отключения StrictHostKeyChecking вне CI'
|
|
400
|
+
].join("\n")
|
|
401
|
+
elsif lower.include?('repository not found') || lower.include?('could not read from remote repository')
|
|
402
|
+
extra_advice = [
|
|
403
|
+
'Совет: Проверьте корректность URL и доступ к репозиторию.',
|
|
404
|
+
'1) Убедитесь, что у вас есть права доступа (приглашение/ключ).',
|
|
405
|
+
'2) Проверьте точность SSH URL: git@host:owner/repo.git'
|
|
406
|
+
].join("\n")
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
generic_advice = 'Совет: проверьте доступ к репозиторию, корректность ветки и SSH-настройки.'
|
|
410
|
+
advice = extra_advice || generic_advice
|
|
385
411
|
raise RepositoryError, [base_msg, advice].reject(&:empty?).join("\n")
|
|
386
412
|
end
|
|
387
413
|
|
data/lib/keysloth/version.rb
CHANGED
data/lib/keysloth.rb
CHANGED
|
@@ -75,7 +75,7 @@ module KeySloth
|
|
|
75
75
|
# @raise [KeySloth::RepositoryError] при ошибках работы с репозиторием
|
|
76
76
|
# @raise [KeySloth::CryptoError] при ошибках расшифровки
|
|
77
77
|
# @raise [KeySloth::FileSystemError] при ошибках файловой системы
|
|
78
|
-
def pull(repo_url:, password:, local_path
|
|
78
|
+
def pull(repo_url:, password:, local_path: nil, branch: nil, config_file: nil)
|
|
79
79
|
start_time = Time.now
|
|
80
80
|
logger = Logger.new
|
|
81
81
|
config = Config.load(config_file)
|
|
@@ -98,7 +98,14 @@ module KeySloth
|
|
|
98
98
|
logger.info("Начинаем получение секретов из репозитория: #{repo_url}")
|
|
99
99
|
|
|
100
100
|
git_manager = GitManager.new(merged_config[:repo_url], logger)
|
|
101
|
-
|
|
101
|
+
# Прокидываем backup_count из конфигурации; невалидные значения заменяем дефолтом
|
|
102
|
+
configured_backup_count = merged_config[:backup_count]
|
|
103
|
+
backup_count = if configured_backup_count.is_a?(Integer) && configured_backup_count >= 0
|
|
104
|
+
configured_backup_count
|
|
105
|
+
else
|
|
106
|
+
KeySloth::FileManager::DEFAULT_BACKUP_COUNT
|
|
107
|
+
end
|
|
108
|
+
file_manager = FileManager.new(logger, backup_count)
|
|
102
109
|
crypto = Crypto.new(password, logger)
|
|
103
110
|
|
|
104
111
|
# Создаем backup перед операцией
|
|
@@ -184,7 +191,7 @@ module KeySloth
|
|
|
184
191
|
# @raise [KeySloth::RepositoryError] при ошибках работы с репозиторием
|
|
185
192
|
# @raise [KeySloth::CryptoError] при ошибках шифрования
|
|
186
193
|
# @raise [KeySloth::FileSystemError] при ошибках файловой системы
|
|
187
|
-
def push(repo_url:, password:, local_path
|
|
194
|
+
def push(repo_url:, password:, local_path: nil, branch: nil,
|
|
188
195
|
config_file: nil, commit_message: nil)
|
|
189
196
|
start_time = Time.now
|
|
190
197
|
logger = Logger.new
|
|
@@ -209,7 +216,13 @@ module KeySloth
|
|
|
209
216
|
logger.info("Начинаем отправку секретов в репозиторий: #{repo_url}")
|
|
210
217
|
|
|
211
218
|
git_manager = GitManager.new(merged_config[:repo_url], logger)
|
|
212
|
-
|
|
219
|
+
configured_backup_count = merged_config[:backup_count]
|
|
220
|
+
backup_count = if configured_backup_count.is_a?(Integer) && configured_backup_count >= 0
|
|
221
|
+
configured_backup_count
|
|
222
|
+
else
|
|
223
|
+
KeySloth::FileManager::DEFAULT_BACKUP_COUNT
|
|
224
|
+
end
|
|
225
|
+
file_manager = FileManager.new(logger, backup_count)
|
|
213
226
|
crypto = Crypto.new(password, logger)
|
|
214
227
|
|
|
215
228
|
# Проверяем существование локальной директории
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Правила выполнения задачи
|
|
2
|
+
|
|
3
|
+
- Все новые фичи должны быть покрыты тестами
|
|
4
|
+
- По итогам выполнения задачи
|
|
5
|
+
- необходимо обязательно убедиться в успешном прохождении всех тестов, в случае ошибки - исправить код библиотеки или теста и запустить тесты заново, пока все они не будут заканчиваться успешно
|
|
6
|
+
- необходимо обязательно внести правки в файл CHANGELOG.md для версии, указанной в файле lib/keysloth/version.rb
|
|
7
|
+
- при необходимости - внести изменения в техническую документацию проекта
|
|
8
|
+
|
|
9
|
+
# Правила правки бага
|
|
10
|
+
|
|
11
|
+
- Каждый баг перед исправлением должен быть покрыт тестом, который должен фейлится до начала исправления бага
|
|
12
|
+
- Только после этого следует начинать правки бага
|
|
13
|
+
- После правок бага - необходимо убедиться, что весь набор тестов проекта проходит успешно, в случае ошибки - исправить код библиотеки или теста и запустить тесты заново, пока все они не будут заканчиваться успешно
|
|
14
|
+
- По итогам выполнения задачи
|
|
15
|
+
- необходимо обязательно внести правки в файл CHANGELOG.md для версии, указанной в файле lib/keysloth/version.rb
|
|
16
|
+
- при необходимости - внести изменения в техническую документацию проекта
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Wildcard extensions: поддержка любых типов файлов
|
|
2
|
+
|
|
3
|
+
## Цель
|
|
4
|
+
Убрать ограничение на список поддерживаемых расширений. Инструмент должен шифровать/дешифровывать любые типы файлов в указанной директории, сохраняя текущую модель хранения `.enc` в репозитории.
|
|
5
|
+
|
|
6
|
+
## Объём работ
|
|
7
|
+
- Сбор входных файлов: из whitelist расширений → на «все файлы», с разумными исключениями.
|
|
8
|
+
- Безопасная работа с бинарными файлами.
|
|
9
|
+
- Обновление CLI и документации.
|
|
10
|
+
- Актуализация тестов и тест-плана.
|
|
11
|
+
|
|
12
|
+
## План задач
|
|
13
|
+
1) Обновить сбор файлов в `FileManager#collect_secret_files`
|
|
14
|
+
- Рекурсивно собирать все обычные файлы (`File.file?`) в заданной директории.
|
|
15
|
+
- Исключить из выбора: `**/*.enc`, `**/.git/**`.
|
|
16
|
+
- Дополнительно исключить общеизвестные мусорные файлы по умолчанию: `.DS_Store`, `Thumbs.db`, локальный `README.md` в каталоге секретов.
|
|
17
|
+
- Подготовить точку расширения для будущей настройки include/exclude через конфиг (без реализации, если не требуется сейчас).
|
|
18
|
+
|
|
19
|
+
2) Обеспечить бинарно-безопасный I/O
|
|
20
|
+
- Перейти на `File.binread`/`File.binwrite` в `FileManager` и местах использования (чтение/запись секретов).
|
|
21
|
+
- Проверить, что `Crypto` корректно работает с бинарными строками (подтвердить тестами).
|
|
22
|
+
|
|
23
|
+
3) Проверки целостности файлов
|
|
24
|
+
- Сохранить специализированные проверки для известных типов (`.cer`, `.p12`, `.mobileprovisioning`, `.json`).
|
|
25
|
+
- Для всех прочих типов — базовая проверка (не пустой, читаемый), не блокирующая обработку.
|
|
26
|
+
|
|
27
|
+
4) Тесты
|
|
28
|
+
- Расширить `spec/keysloth/file_manager_spec.rb`:
|
|
29
|
+
- кейс: собираются разные типы файлов (например, `.txt`, `.png`, `.bin`).
|
|
30
|
+
- кейс: игнорируются `.enc` и `.git` содержимое, а также `README.md`.
|
|
31
|
+
- кейс: корректный сбор в вложенных директориях.
|
|
32
|
+
- Адаптировать тесты, завязанные на whitelist.
|
|
33
|
+
|
|
34
|
+
5) Обновить CLI help и генерацию README секретов
|
|
35
|
+
- Удалить жёсткий список «поддерживаемых типов» из long_desc в `lib/keysloth/cli.rb`.
|
|
36
|
+
- В шаблоне README для директории секретов указать: «поддерживаются любые типы файлов».
|
|
37
|
+
- Убедиться, что создаваемый локально `README.md` НЕ попадает под шифрование/отправку.
|
|
38
|
+
|
|
39
|
+
6) Обновить основную документацию
|
|
40
|
+
- В `README.md` заменить раздел «Поддерживаемые типы файлов» на «любой тип файла (примеры: .cer, .p12, .json, изображения, бинарные и т.д.)».
|
|
41
|
+
- Добавить примечание про исключения (`*.enc`, `.git/**`, `.DS_Store`, `Thumbs.db`, `README.md`).
|
|
42
|
+
|
|
43
|
+
7) Тест-план
|
|
44
|
+
- Обновить `task/test_plan.md`: добавить сценарии для произвольных расширений и бинарных файлов, проверку побайтной идентичности после `push`→`pull`.
|
|
45
|
+
|
|
46
|
+
8) Релизная подготовка
|
|
47
|
+
- Обновить `CHANGELOG.md`.
|
|
48
|
+
- Поднять версию gem (patch/minor).
|
|
49
|
+
|
|
50
|
+
## Критерии приёмки
|
|
51
|
+
- `push` шифрует все файлы из указанной директории (и подпапок), кроме исключений по умолчанию, и публикует их как `<relative_path>.enc`.
|
|
52
|
+
- `pull` корректно расшифровывает любые `.enc` и восстанавливает исходные имена и содержимое.
|
|
53
|
+
- Бинарные файлы (например, `.png`, `.p12`) после цикла `push`→`pull` побайтно идентичны исходникам (проверка через хэш).
|
|
54
|
+
- Тесты проходят локально и в CI.
|
|
55
|
+
|
|
56
|
+
## Риски и меры
|
|
57
|
+
- Большие файлы: текущая реализация читает файлы целиком в память - так и оставляем;
|
|
58
|
+
- Случайные/мусорные файлы: добавлены исключения; при необходимости сделать настраиваемыми через конфиг - но это уже потом.
|
|
59
|
+
|
|
60
|
+
## Замечания по обратной совместимости
|
|
61
|
+
- Прежние проекты продолжат работать; расширение функциональности не требует миграций.
|
|
62
|
+
- Пользователи могут удалить упоминания конкретных расширений из своих внутренних инструкций.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
## Исправление использования backup_count
|
|
2
|
+
|
|
3
|
+
Контекст:
|
|
4
|
+
- Значение `backup_count` из `.keyslothrc` не используется при создании бэкапов: `FileManager` всегда создаётся без параметра, из‑за чего применяется дефолт `3`.
|
|
5
|
+
- Требование: `backup_count == 0` — валидное значение, которое должно полностью отключать создание и ротацию бэкапов (без удаления уже существующих).
|
|
6
|
+
|
|
7
|
+
Цели:
|
|
8
|
+
- Прокидывать `backup_count` из конфигурации в `FileManager`.
|
|
9
|
+
- При `backup_count == 0` не создавать новые бэкапы и не выполнять очистку (не удалять существующие).
|
|
10
|
+
|
|
11
|
+
План работ
|
|
12
|
+
|
|
13
|
+
1) Тесты (сначала красные)
|
|
14
|
+
- KeySloth.pull/KeySloth.push используют `backup_count` из конфигурации:
|
|
15
|
+
- В `spec/keysloth_spec.rb` добавить тест для `.pull` и `.push`, где `Config.load` возвращает конфиг с `backup_count: N` (произвольное число, например `7`).
|
|
16
|
+
- Ожидание: `KeySloth::FileManager.new` вызывается как `FileManager.new(logger, 7)`.
|
|
17
|
+
|
|
18
|
+
- Ротация с кастомным лимитом:
|
|
19
|
+
- В `spec/keysloth/file_manager_spec.rb` добавить тест: `file_manager = FileManager.new(logger, 2)`; создать директорию с секретами и трижды вызвать `create_backup` (небольшая задержка для уникальных timestamp'ов). Ожидание: `list_backups` вернёт 2 каталога.
|
|
20
|
+
|
|
21
|
+
- Отключение бэкапов (`backup_count == 0`):
|
|
22
|
+
- Тест: `file_manager = FileManager.new(logger, 0)`; вызвать `create_backup` для существующей директории. Ожидания: метод вернёт `nil`, новые каталоги бэкапов не появятся, `list_backups` пуст.
|
|
23
|
+
|
|
24
|
+
2) Прогон тестов (ожидаемо красные)
|
|
25
|
+
```bash
|
|
26
|
+
bundle exec rake spec
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
3) Исправления в коде
|
|
30
|
+
- `lib/keysloth.rb`:
|
|
31
|
+
- В `.pull` и `.push` заменить инициализацию `file_manager = FileManager.new(logger)` на `FileManager.new(logger, merged_config[:backup_count])`.
|
|
32
|
+
- Защититься от невалидных значений: если `backup_count` отсутствует/не Integer/отрицателен — использовать дефолт.
|
|
33
|
+
|
|
34
|
+
- `lib/keysloth/file_manager.rb`:
|
|
35
|
+
- В `create_backup`: если `@backup_count <= 0`, сразу возвращать `nil` (ничего не создавать и не чистить).
|
|
36
|
+
- В `cleanup_old_backups`: если `@backup_count <= 0`, сразу выходить (не удалять существующие бэкапы).
|
|
37
|
+
|
|
38
|
+
4) Прогон тестов (ожидаемо зелёные)
|
|
39
|
+
```bash
|
|
40
|
+
bundle exec rake spec
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Замечания и критерии приёмки
|
|
44
|
+
- Без `.keyslothrc` или без поля `backup_count` поведение не меняется: хранится 3 бэкапа.
|
|
45
|
+
- При `backup_count: 7` хранится 7 бэкапов (покрыто тестом на вызов конструктора и ротацию в `FileManager`).
|
|
46
|
+
- При `backup_count: 0` бэкапы не создаются и ротация не выполняется (существующие каталоги не удаляются).
|
|
47
|
+
- Никакие другие сценарии не ломаются, все существующие тесты остаются зелёными.
|
|
48
|
+
|
|
49
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Исправление: игнорируется branch/local_path из .keyslothrc при вызове CLI
|
|
2
|
+
|
|
3
|
+
## Признаки
|
|
4
|
+
- При наличии `.keyslothrc` значения `branch` и `local_path` из файла конфигурации не применяются при `pull`/`push`.
|
|
5
|
+
- CLI прокидывает дефолты (`branch: 'main'`, `path: './secrets'`) в корневые методы, тем самым перекрывая конфиг.
|
|
6
|
+
- Автопоиск конфига есть (текущий каталог и `~/.keyslothrc`).
|
|
7
|
+
|
|
8
|
+
## Требования (см. promts/main/rules.md)
|
|
9
|
+
- Добавить тест(ы), воспроизводящие баг (красные до фикса).
|
|
10
|
+
- Исправить код так, чтобы параметры из `.keyslothrc` учитывались, а CLI‑дефолты не перекрывали их.
|
|
11
|
+
- Убедиться, что все тесты проходят.
|
|
12
|
+
- Обновить `CHANGELOG.md` под текущую версию из `lib/keysloth/version.rb`.
|
|
13
|
+
- Обновить документацию: README — пояснить автопоиск `.keyslothrc`.
|
|
14
|
+
|
|
15
|
+
## План работ
|
|
16
|
+
1) Тесты (красные):
|
|
17
|
+
- В `spec/keysloth_spec.rb` добавить кейсы для `.pull` и `.push`:
|
|
18
|
+
- Мок `KeySloth::Config.load` возвращает конфиг с `branch: 'develop'`, `local_path: './conf_secrets'`.
|
|
19
|
+
- Вызов `.pull(repo_url: 'x', password: 'y', branch: nil, local_path: nil, config_file: '.keyslothrc')` должен после мерджа отдать `branch='develop'`, `local_path='./conf_secrets'` в `GitManager/FileManager`.
|
|
20
|
+
- Аналогично для `.push`.
|
|
21
|
+
- Альтернативно (на уровне CLI): тесты в `spec/keysloth/cli_spec.rb`, что при отсутствии указанных пользователем `--branch/--path` CLI не прокидывает дефолты, позволяя конфигу примениться.
|
|
22
|
+
|
|
23
|
+
2) Исправление мерджа параметров:
|
|
24
|
+
- В `lib/keysloth/cli.rb`:
|
|
25
|
+
- Убрать дефолты у опций `:branch` и `:path` для команд `pull`/`push`/других, где нужно применять конфиг. Оставить только `desc` и `type`.
|
|
26
|
+
- В вызове `KeySloth.pull/push` передавать `branch: options[:branch], local_path: options[:path]` как есть (могут быть `nil`).
|
|
27
|
+
- В `lib/keysloth.rb` (методы `.pull` и `.push`):
|
|
28
|
+
- При формировании `merged_config = config.merge({...}.compact)` — НЕ задавать свои дефолты в сигнатуре метода (оставить `branch: nil` и `local_path: nil`), чтобы при `nil` бралось из `config`.
|
|
29
|
+
- Сохранять текущую логику приоритета: явные аргументы пользователя перекрывают конфиг, а `nil` не перетирает.
|
|
30
|
+
|
|
31
|
+
3) Прогон тестов:
|
|
32
|
+
- `bundle exec rake spec` — все тесты должны стать зелёными.
|
|
33
|
+
- При необходимости — исправить тесты/код, не нарушая приоритетов параметров.
|
|
34
|
+
|
|
35
|
+
4) Документация и ченджлог:
|
|
36
|
+
- В `README.md` дополнить раздел «Конфигурационный файл»:
|
|
37
|
+
- Явно указать автопоиск: текущая директория и `~/.keyslothrc`.
|
|
38
|
+
- Уточнить приоритеты: CLI > конфиг > значения по умолчанию.
|
|
39
|
+
- Явно указать дефолты при отсутствии флагов и полей в конфиге: `branch: 'main'`, `local_path: './secrets'`, `backup_count: 3` (у `repo_url` дефолта нет).
|
|
40
|
+
- В `CHANGELOG.md` для версии `0.2.0` (или актуальной) добавить запись:
|
|
41
|
+
- Исправлено: игнорирование `branch` и `local_path` из `.keyslothrc` при использовании CLI.
|
|
42
|
+
|
|
43
|
+
## Критерии приёмки
|
|
44
|
+
- Без явных `--branch/--path` и с `.keyslothrc` значения из конфига применяются в `pull`/`push`.
|
|
45
|
+
- С явными флагами CLI значения из конфига перекрываются флагами.
|
|
46
|
+
- При отсутствии файла конфига — используются дефолты (из `Config::DEFAULT_CONFIG`).
|
|
47
|
+
- Тесты и линт проходят.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
## SSH fixes: улучшение UX и сообщений об ошибках
|
|
2
|
+
|
|
3
|
+
### Цели
|
|
4
|
+
- Улучшить сообщения об ошибках SSH/аутентификации с практичными подсказками.
|
|
5
|
+
- Обновить README: явно указать поддержку `id_ed25519`, примеры использования ENV и `KEYSLOTH_SSH_KEY_PATH`.
|
|
6
|
+
- По возможности покрыть тестами типовые SSH‑ошибки.
|
|
7
|
+
|
|
8
|
+
### Вне scope
|
|
9
|
+
- Не добавляем CLI‑флаг `--ssh-key`.
|
|
10
|
+
- Не обновляем test plan.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
### План работ
|
|
15
|
+
|
|
16
|
+
#### 1) Документация (`README.md`)
|
|
17
|
+
- Обновить раздел «Настройка SSH ключей»:
|
|
18
|
+
- Ясно указать, что системный SSH и ssh-agent автоматически поддерживают как `id_rsa`, так и `id_ed25519`.
|
|
19
|
+
- Обновить раздел «CI/CD настройка»:
|
|
20
|
+
- Уточнить, что `SSH_PRIVATE_KEY` может содержать любой тип ключа (ed25519/rsa).
|
|
21
|
+
- Добавить упоминание `KEYSLOTH_SSH_KEY_PATH` для явного указания пути к ключу.
|
|
22
|
+
- Раздел «Использование системного SSH (GIT_SSH_COMMAND)»:
|
|
23
|
+
- Описать авто‑формирование `GIT_SSH_COMMAND` при наличии ENV (`SSH_PRIVATE_KEY`/`SSH_PUBLIC_KEY` или `KEYSLOTH_SSH_KEY_PATH`).
|
|
24
|
+
- Отдельно отметить рекомендации про StrictHostKeyChecking только для CI.
|
|
25
|
+
- Раздел «Troubleshooting → Ошибки аутентификации Git»:
|
|
26
|
+
- Добавить подсказки для Ed25519: проверка агента `ssh-add -l`, загрузка ключа `ssh-add ~/.ssh/id_ed25519`.
|
|
27
|
+
- Добавить подсказку про `KEYSLOTH_SSH_KEY_PATH` и ENV `SSH_PRIVATE_KEY` как быстрые способы указать ключ.
|
|
28
|
+
|
|
29
|
+
Готово, когда: README явно содержит `ed25519`, `KEYSLOTH_SSH_KEY_PATH` и универсальность `SSH_PRIVATE_KEY`.
|
|
30
|
+
|
|
31
|
+
#### 2) Улучшение ошибок SSH (код: `lib/keysloth/git_manager.rb`)
|
|
32
|
+
- В `run_git` добавить распознавание типовых SSH‑ошибок и расширенные советы:
|
|
33
|
+
- При `Permission denied (publickey)`:
|
|
34
|
+
- Советы: проверить ключи в агенте `ssh-add -l` (или загрузить: `ssh-add ~/.ssh/id_ed25519`),
|
|
35
|
+
указать ключ явно `KEYSLOTH_SSH_KEY_PATH=~/.ssh/id_ed25519` или использовать `SSH_PRIVATE_KEY` в CI,
|
|
36
|
+
проверить права на ключ `chmod 600 ~/.ssh/<key>`.
|
|
37
|
+
- При `Host key verification failed`:
|
|
38
|
+
- Советы: добавить хост в known_hosts `ssh-keyscan <host> >> ~/.ssh/known_hosts`,
|
|
39
|
+
избегать отключения проверки хостов вне CI.
|
|
40
|
+
- При `Repository not found`/`Could not read from remote repository`:
|
|
41
|
+
- Советы: проверить URL репозитория и доступ (приглашение/права).
|
|
42
|
+
- Сохранить текущее общее сообщение‑совет как fallback, если паттерн не распознан.
|
|
43
|
+
- Убедиться, что в сообщениях не выводятся секреты/ключи.
|
|
44
|
+
|
|
45
|
+
Готово, когда: `RepositoryError` содержит релевантные советы для распознанных паттернов.
|
|
46
|
+
|
|
47
|
+
#### 3) Тесты (по возможности) — `spec/keysloth/git_manager_spec.rb`
|
|
48
|
+
- Добавить группу: «SSH ошибки и подсказки».
|
|
49
|
+
- Кейс: stderr содержит `Permission denied (publickey)` → ошибка содержит подсказки про `ssh-add -l`, `KEYSLOTH_SSH_KEY_PATH`, `SSH_PRIVATE_KEY`.
|
|
50
|
+
- Кейс: stderr содержит `Host key verification failed` → ошибка содержит подсказку про `ssh-keyscan … >> ~/.ssh/known_hosts`.
|
|
51
|
+
- Кейс: stderr содержит `Repository not found` → ошибка содержит подсказку про проверку URL/прав доступа.
|
|
52
|
+
- Кейс: произвольный stderr → остаётся общий совет.
|
|
53
|
+
- Техподход:
|
|
54
|
+
- Мокнуть `Open3.capture3` на неуспех с требуемым stderr.
|
|
55
|
+
- Вызвать любой публичный путь, который триггерит `run_git` (например, `clone_repository`/`ensure_branch_up_to_date`) или обратиться через `send` к приватному методу, не ломая интерфейс.
|
|
56
|
+
|
|
57
|
+
Готово, когда: новые спеки зелёные и не ломают существующие.
|
|
58
|
+
|
|
59
|
+
#### 4) CHANGELOG
|
|
60
|
+
- Добавить строку: «Улучшены сообщения об ошибках SSH (подсказки для publickey/host key/доступа), README обновлён под Ed25519 и KEYSLOTH_SSH_KEY_PATH».
|
|
61
|
+
|
|
62
|
+
#### 5) Быстрая ручная проверка
|
|
63
|
+
- `KEYSLOTH_SSH_KEY_PATH` с реальным ed25519 ключом → `pull`/`push` проходят.
|
|
64
|
+
- Без ENV, c системным ssh-agent и `id_ed25519` → работает «из коробки».
|
|
65
|
+
- Смоделировать ошибку `Permission denied (publickey)` и убедиться, что подсказки видны и полезны.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### Критерии приёмки
|
|
70
|
+
- README обновлён (ed25519, KEYSLOTH_SSH_KEY_PATH, ENV‑примеры).
|
|
71
|
+
- Сообщения об ошибках SSH расширены и сохраняют безопасность.
|
|
72
|
+
- Добавлены/прогнаны спеки на типовые сценарии (если возможно).
|
|
73
|
+
- CHANGELOG обновлён.
|
|
74
|
+
|
|
75
|
+
### Риски и откат
|
|
76
|
+
- Риск «шумных» сообщений для редких ошибок — ограничиваемся известными паттернами.
|
|
77
|
+
- Откат: вернуть прежнюю версию `run_git`, удалить новые спеки и строку в CHANGELOG; документацию откатить соответствующим PR.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Обновление диапазона версии thor
|
|
2
|
+
|
|
3
|
+
Цель: обеспечить совместимость с thor в диапазоне '>= 1.0.1', '< 1.4.0' (консервативно), сохранив работоспособность и покрытие тестами.
|
|
4
|
+
|
|
5
|
+
## Таск-лист (выполнить по порядку)
|
|
6
|
+
|
|
7
|
+
1) Подготовка и анализ
|
|
8
|
+
- Проверить текущие точки интеграции с Thor в `lib/keysloth/cli.rb` (описания опций, help, ошибки)
|
|
9
|
+
- Сверить breaking changes Thor 1.0.x → 1.3.x (release notes)
|
|
10
|
+
|
|
11
|
+
2) Обновить зависимость
|
|
12
|
+
- В `keysloth.gemspec` заменить зависимость на: `spec.add_dependency 'thor', '>= 1.0.1', '< 1.4.0'`
|
|
13
|
+
- Обновить локальные зависимости: `bundle update thor` (для проверки на последнем доступном < 1.4.0)
|
|
14
|
+
|
|
15
|
+
3) Матрица совместимости (локально и/или CI)
|
|
16
|
+
- Добавить Appraisal (dev): `spec.add_development_dependency 'appraisal', '~> 2.5'`
|
|
17
|
+
- Создать `Appraisals` с наборами:
|
|
18
|
+
- thor-1.0: `gem 'thor', '1.0.1'`
|
|
19
|
+
- thor-1.3: `gem 'thor', '~> 1.3.2'`
|
|
20
|
+
- Установить и прогнать: `bundle exec appraisal install`
|
|
21
|
+
- Запустить тесты: `bundle exec appraisal thor-1.0 rspec` и `bundle exec appraisal thor-1.3 rspec`
|
|
22
|
+
|
|
23
|
+
4) Тесты (согласно правилам выполнения фичи)
|
|
24
|
+
- Убедиться, что весь набор тестов проходит на обоих наборах (1.0.1 и ~>1.3.2)
|
|
25
|
+
- При падениях — адаптировать код CLI или тесты под совместимый API Thor, не меняя публичное поведение
|
|
26
|
+
|
|
27
|
+
5) Качество кода
|
|
28
|
+
- Прогнать линтер: `bundle exec rake rubocop`
|
|
29
|
+
- Прогнать полную проверку: `bundle exec rake check`
|
|
30
|
+
|
|
31
|
+
6) Документация
|
|
32
|
+
- Обновить `CHANGELOG.md` для текущей версии из `lib/keysloth/version.rb` (раздел Changed):
|
|
33
|
+
- «Диапазон совместимости Thor обновлён до '>= 1.0.1', '< 1.4.0'»
|
|
34
|
+
|
|
35
|
+
## Критерии приёмки
|
|
36
|
+
- Тесты проходят на `thor 1.0.1` и на `thor ~> 1.3.2`
|
|
37
|
+
- Никаких регрессий CLI (опции, help, коды завершения)
|
|
38
|
+
- Обновлены: `gemspec` (диапазон), `CHANGELOG.md`
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
### Чек‑лист релиза
|
|
2
|
+
|
|
3
|
+
Краткий, практичный список шагов для публикации и релиза `KeySloth`.
|
|
4
|
+
|
|
5
|
+
#### 1) Подготовка версии
|
|
6
|
+
- [ ] Обновить версию в `lib/keysloth/version.rb` (SemVer)
|
|
7
|
+
- [ ] Обновить `CHANGELOG.md` (секция для новой версии)
|
|
8
|
+
- [ ] Проверить `keysloth.gemspec`: `summary`, `description`, `authors`, `email`, `license`, `required_ruby_version`, `homepage`
|
|
9
|
+
- [ ] Добавить/актуализировать `metadata`
|
|
10
|
+
|
|
11
|
+
#### 2) Публикация на RubyGems.org
|
|
12
|
+
- [ ] Создать аккаунт/включить 2FA (MFA) на RubyGems
|
|
13
|
+
- [ ] Сгенерировать API‑ключ и экспортировать его в окружение
|
|
14
|
+
```bash
|
|
15
|
+
export GEM_HOST_API_KEY=rg_********************************
|
|
16
|
+
```
|
|
17
|
+
- [ ] Собрать и проверить пакет
|
|
18
|
+
```bash
|
|
19
|
+
gem build keysloth.gemspec
|
|
20
|
+
gem check keysloth-<VERSION>.gem
|
|
21
|
+
```
|
|
22
|
+
- [ ] Отправить пакет
|
|
23
|
+
```bash
|
|
24
|
+
gem push keysloth-<VERSION>.gem
|
|
25
|
+
```
|
|
26
|
+
- [ ] Проверить страницу gem’a: `https://rubygems.org/gems/keysloth`
|
|
27
|
+
- [ ] (Опционально) Отозвать версию (rollback)
|
|
28
|
+
```bash
|
|
29
|
+
gem yank keysloth -v <VERSION>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
#### 3) Git‑тег и GitHub Release
|
|
33
|
+
- [ ] Создать и запушить тег
|
|
34
|
+
- [ ] Создать релиз (через GitHub UI)
|
|
35
|
+
|
|
36
|
+
#### 4) Валидация после релиза
|
|
37
|
+
- [ ] Проверить, что страница на RubyGems отображает новую версию
|
|
38
|
+
- [ ] Проверить установку:
|
|
39
|
+
```bash
|
|
40
|
+
gem install keysloth -v <VERSION>
|
|
41
|
+
keysloth version
|
|
42
|
+
keysloth help
|
|
43
|
+
```
|
|
44
|
+
- [ ] Прогнать быстрый сценарий использования (минимальный pull в тестовый каталог)
|
|
45
|
+
|
|
46
|
+
#### 5) Rollback (при необходимости)
|
|
47
|
+
- [ ] Отозвать версию gem’a:
|
|
48
|
+
```bash
|
|
49
|
+
gem yank keysloth -v <VERSION>
|
|
50
|
+
```
|
|
51
|
+
- [ ] Удалить GitHub Release и тег (или выпустить hotfix)
|
|
52
|
+
|
|
53
|
+
#### 6) Мини‑чек‑лист
|
|
54
|
+
- [ ] Обновить версию и changelog
|
|
55
|
+
- [ ] Собрать и запушить gem в RubyGems
|
|
56
|
+
- [ ] Создать git‑тег и GitHub Release
|
|
57
|
+
- [ ] Обновить/опубликовать документацию
|
|
58
|
+
- [ ] Обновить/добавить примеры CI/CD
|
|
59
|
+
|
|
60
|
+
|