mirror of
https://github.com/ivuorinen/f2b.git
synced 2026-03-07 23:58:21 +00:00
fix: repair Renovate config, convert Makefile to go run, update GitHub Actions (#120)
* fix: repair Renovate config and convert Makefile to go run (#117) - Remove non-existent `github>renovatebot/presets:golang` preset that broke Renovate PR creation - Replace deprecated `fileMatch` with `managerFilePatterns` in customManagers - Rewrite regex to match new Makefile pattern (renovate comment above version variable assignment) - Fix `matchFileNames` glob pattern (`*.mk` -> `**/*.mk`) - Convert all tool invocations from `go install` + global binary to `go run tool@version` for reproducible builds - Convert npm global tools to `npx --yes` invocations - Remove `dev-deps` and `check-deps` targets (tools auto-download) - Add mdformat pre-commit hook with GFM support and config - Add `fmt-md` Makefile target for manual markdown formatting - Update local golangci-lint pre-commit hook to use `go run` - Apply golangci-lint v2.10.1 auto-fixes (fmt.Fprintf optimization) - Add nolint:gosec annotations for legitimate exec.Command usage - Exclude .serena/ from mdformat and megalinter - Add markdown indent_size=unset in .editorconfig for CommonMark compat * chore(deps): update GitHub Actions to latest versions - anthropics/claude-code-action: v1.0.34 -> v1.0.64 - actions/setup-go: v6.2.0 -> v6.3.0 - actions/upload-artifact: v6.0.0 -> v7.0.0 - goreleaser/goreleaser-action: v6.4.0 -> v7.0.0 - docker/login-action: v3.6.0 -> v3.7.0 - ivuorinen/actions: v2026.01.21 -> v2026.02.24 * fix: address code review feedback - Fix issue template YAML frontmatter (replace underscore separators with proper --- delimiters); exclude templates from mdformat - Replace string(rune(n)) with strconv.Itoa(n) in test files to produce deterministic numeric directory names instead of Unicode characters - Remove stale `make dev-deps` reference in README, replace with `make dev-setup` - Extract ban/unban format strings into shared.MetricsFmtBanOperations and shared.MetricsFmtUnbanOperations constants - Replace hardcoded coverage percentages in README with evergreen phrasing * fix: address round 2 code review feedback for PR #120 - Fix corrupted path traversal example in docs/security.md - Fix Renovate .mk regex to match nested paths (.*\.mk$) - Update checkmake pre-commit hook to v0.3.2 to match Makefile - Add sync.WaitGroup to unsynchronized goroutines in security tests - Fix fmt-md target to use pre-commit run mdformat - Pin markdownlint-cli2 to v0.21.0 in lint-md target - Standardize //nolint:gosec to // #nosec annotations for gosec CLI * fix(ci): install PyYAML dependency for PR lint workflow The pr-lint workflow uses ivuorinen/actions/pr-lint which internally calls validate-inputs running a Python script that imports yaml. Python was set up but PyYAML was never installed, causing ModuleNotFoundError at runtime. * fix: address round 3 code review feedback for PR #120 - Wrap Windows-style path traversal example in backtick code span so backslashes render literally in docs/security.md - Add Renovate-managed MARKDOWNLINT_CLI2_VERSION variable in Makefile to match the pattern used by all other tool versions
This commit is contained in:
@@ -13,5 +13,8 @@ indent_width = 2
|
|||||||
[{Makefile,go.mod,go.sum}]
|
[{Makefile,go.mod,go.sum}]
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
indent_size = unset
|
||||||
|
|
||||||
[.github/renovate.json]
|
[.github/renovate.json]
|
||||||
max_line_length = off
|
max_line_length = off
|
||||||
|
|||||||
7
.github/ISSUE_TEMPLATE/bug_report.md
vendored
7
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -4,7 +4,6 @@ about: Create a report to help us improve
|
|||||||
title: ''
|
title: ''
|
||||||
labels: bug
|
labels: bug
|
||||||
assignees: ivuorinen
|
assignees: ivuorinen
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
@@ -14,9 +13,9 @@ A clear and concise description of what the bug is.
|
|||||||
Steps to reproduce the behavior:
|
Steps to reproduce the behavior:
|
||||||
|
|
||||||
1. Run command: `f2b [command]`
|
1. Run command: `f2b [command]`
|
||||||
2. With arguments: `[arguments]`
|
1. With arguments: `[arguments]`
|
||||||
3. Expected behavior: `[what should happen]`
|
1. Expected behavior: `[what should happen]`
|
||||||
4. Actual result: `[what actually happened]`
|
1. Actual result: `[what actually happened]`
|
||||||
|
|
||||||
**Expected behavior**
|
**Expected behavior**
|
||||||
A clear and concise description of what you expected to happen.
|
A clear and concise description of what you expected to happen.
|
||||||
|
|||||||
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -4,7 +4,6 @@ about: Suggest an idea for this project
|
|||||||
title: ''
|
title: ''
|
||||||
labels: enhancement
|
labels: enhancement
|
||||||
assignees: ivuorinen
|
assignees: ivuorinen
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
|||||||
8
.github/renovate.json
vendored
8
.github/renovate.json
vendored
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": ["github>ivuorinen/renovate-config", "github>renovatebot/presets:golang", "schedule:weekly"],
|
"extends": ["github>ivuorinen/renovate-config", "schedule:weekly"],
|
||||||
"customManagers": [
|
"customManagers": [
|
||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"fileMatch": ["^Makefile$", "\\.mk$"],
|
"managerFilePatterns": ["^Makefile$", ".*\\.mk$"],
|
||||||
"matchStrings": [
|
"matchStrings": [
|
||||||
"@go install (?<depName>\\S+)@(?<currentValue>v?\\d+\\.\\d+\\.\\d+)[\\s\\S]*?renovate:\\s*datasource=(?<datasource>\\S+)\\s+depName=\\S+"
|
"#\\s*renovate:\\s*datasource=(?<datasource>\\S+)\\s+depName=(?<depName>\\S+)\\n[A-Z_]+\\s*:?=\\s*(?<currentValue>v?\\d+\\.\\d+\\.\\d+\\S*)"
|
||||||
],
|
],
|
||||||
"versioningTemplate": "semver"
|
"versioningTemplate": "semver"
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
"packageRules": [
|
"packageRules": [
|
||||||
{
|
{
|
||||||
"matchManagers": ["custom.regex"],
|
"matchManagers": ["custom.regex"],
|
||||||
"matchFileNames": ["Makefile", "*.mk"],
|
"matchFileNames": ["Makefile", "**/*.mk"],
|
||||||
"groupName": "development tools",
|
"groupName": "development tools",
|
||||||
"schedule": ["before 6am on monday"]
|
"schedule": ["before 6am on monday"]
|
||||||
}
|
}
|
||||||
|
|||||||
2
.github/workflows/claude.yml
vendored
2
.github/workflows/claude.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Run Claude Code
|
- name: Run Claude Code
|
||||||
id: claude
|
id: claude
|
||||||
uses: anthropics/claude-code-action@f64219702d7454cf29fe32a74104be6ed43dc637 # v1.0.34
|
uses: anthropics/claude-code-action@ba7fa4bcf054319261202aef93d71a89112a8d00 # v1.0.64
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
|||||||
node-version: 24.x
|
node-version: 24.x
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
|
|||||||
9
.github/workflows/pr-lint.yml
vendored
9
.github/workflows/pr-lint.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
|||||||
node-version: 24.x
|
node-version: 24.x
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
@@ -46,6 +46,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: "3.x"
|
python-version: "3.x"
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: pip install pyyaml
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
|
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
|
||||||
with:
|
with:
|
||||||
@@ -58,7 +61,7 @@ jobs:
|
|||||||
go test -race -covermode=atomic -coverprofile=coverage.out ./...
|
go test -race -covermode=atomic -coverprofile=coverage.out ./...
|
||||||
|
|
||||||
- name: Upload coverage report
|
- name: Upload coverage report
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: coverage-report
|
name: coverage-report
|
||||||
path: coverage.out
|
path: coverage.out
|
||||||
@@ -66,4 +69,4 @@ jobs:
|
|||||||
- name: Run PR Lint
|
- name: Run PR Lint
|
||||||
# Custom PR linting action that performs additional PR-specific checks
|
# Custom PR linting action that performs additional PR-specific checks
|
||||||
# https://github.com/ivuorinen/actions
|
# https://github.com/ivuorinen/actions
|
||||||
uses: ivuorinen/actions/pr-lint@f98ae7cd7d0feb1f9d6b01de0addbb11414cfc73 # v2026.01.21
|
uses: ivuorinen/actions/pr-lint@8faacf8a1cae049c1471708dcb408a167e91afaf # v2026.02.24
|
||||||
|
|||||||
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -23,26 +23,26 @@ jobs:
|
|||||||
fetch-depth: 0 # Required for changelog generation
|
fetch-depth: 0 # Required for changelog generation
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
- name: Install GoReleaser
|
- name: Install GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
|
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
|
||||||
with:
|
with:
|
||||||
install-only: true
|
install-only: true
|
||||||
version: "~> v2"
|
version: "~> v2"
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
|
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
|
||||||
with:
|
with:
|
||||||
version: "~> v2"
|
version: "~> v2"
|
||||||
args: release --clean
|
args: release --clean
|
||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
# HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
|
# HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Upload Release Assets
|
- name: Upload Release Assets
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: release-artifacts
|
name: release-artifacts
|
||||||
path: dist/
|
path: dist/
|
||||||
|
|||||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -23,4 +23,4 @@ jobs:
|
|||||||
issues: write
|
issues: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: ivuorinen/actions/stale@f98ae7cd7d0feb1f9d6b01de0addbb11414cfc73 # v2026.01.21
|
- uses: ivuorinen/actions/stale@8faacf8a1cae049c1471708dcb408a167e91afaf # v2026.02.24
|
||||||
|
|||||||
2
.github/workflows/sync-labels.yml
vendored
2
.github/workflows/sync-labels.yml
vendored
@@ -23,4 +23,4 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
issues: write
|
issues: write
|
||||||
steps:
|
steps:
|
||||||
- uses: ivuorinen/actions/sync-labels@f98ae7cd7d0feb1f9d6b01de0addbb11414cfc73 # v2026.01.21
|
- uses: ivuorinen/actions/sync-labels@8faacf8a1cae049c1471708dcb408a167e91afaf # v2026.02.24
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,3 +14,4 @@ dist/*
|
|||||||
!dist/.gitkeep
|
!dist/.gitkeep
|
||||||
# Anonymous test data from real fail2ban logs
|
# Anonymous test data from real fail2ban logs
|
||||||
!fail2ban/testdata/*
|
!fail2ban/testdata/*
|
||||||
|
/.claude/settings.local.json
|
||||||
|
|||||||
2
.mdformat.toml
Normal file
2
.mdformat.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
wrap = "keep"
|
||||||
|
end_of_line = "lf"
|
||||||
@@ -14,6 +14,8 @@ PRINT_ALPACA: false # Print Alpaca logo in console
|
|||||||
SARIF_REPORTER: true # Generate SARIF report
|
SARIF_REPORTER: true # Generate SARIF report
|
||||||
SHOW_SKIPPED_LINTERS: false # Show skipped linters in MegaLinter log
|
SHOW_SKIPPED_LINTERS: false # Show skipped linters in MegaLinter log
|
||||||
|
|
||||||
|
FILTER_REGEX_EXCLUDE: '(\.serena/)'
|
||||||
|
|
||||||
DISABLE_LINTERS:
|
DISABLE_LINTERS:
|
||||||
- REPOSITORY_DEVSKIM
|
- REPOSITORY_DEVSKIM
|
||||||
- GO_REVIVE # run as part of golangci-lint
|
- GO_REVIVE # run as part of golangci-lint
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: golangci-lint
|
- id: golangci-lint
|
||||||
name: golangci-lint
|
name: golangci-lint
|
||||||
entry: golangci-lint run
|
entry: go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.1 run
|
||||||
language: system
|
language: system
|
||||||
types: [go]
|
types: [go]
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
||||||
- repo: https://github.com/google/yamlfmt
|
- repo: https://github.com/google/yamlfmt
|
||||||
rev: v0.20.0
|
rev: v0.21.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: yamlfmt
|
- id: yamlfmt
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ repos:
|
|||||||
args: [-q, -c, .markdown-link-check.json]
|
args: [-q, -c, .markdown-link-check.json]
|
||||||
|
|
||||||
- repo: https://github.com/rhysd/actionlint
|
- repo: https://github.com/rhysd/actionlint
|
||||||
rev: v1.7.9
|
rev: v1.7.11
|
||||||
hooks:
|
hooks:
|
||||||
- id: actionlint
|
- id: actionlint
|
||||||
args: ["-shellcheck="]
|
args: ["-shellcheck="]
|
||||||
@@ -59,26 +59,34 @@ repos:
|
|||||||
- id: shfmt
|
- id: shfmt
|
||||||
|
|
||||||
- repo: https://github.com/checkmake/checkmake
|
- repo: https://github.com/checkmake/checkmake
|
||||||
rev: 0.2.2
|
rev: v0.3.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: checkmake
|
- id: checkmake
|
||||||
name: Makefile Linter
|
name: Makefile Linter
|
||||||
files: ^Makefile$
|
files: ^Makefile$
|
||||||
|
|
||||||
- repo: https://github.com/bridgecrewio/checkov.git
|
- repo: https://github.com/bridgecrewio/checkov.git
|
||||||
rev: "3.2.495"
|
rev: "3.2.506"
|
||||||
hooks:
|
hooks:
|
||||||
- id: checkov
|
- id: checkov
|
||||||
args:
|
args:
|
||||||
- "--quiet"
|
- "--quiet"
|
||||||
|
|
||||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||||
rev: 0.36.0
|
rev: 0.37.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-github-workflows
|
- id: check-github-workflows
|
||||||
args: ["--verbose"]
|
args: ["--verbose"]
|
||||||
|
|
||||||
- repo: https://github.com/editorconfig-checker/editorconfig-checker
|
- repo: https://github.com/editorconfig-checker/editorconfig-checker
|
||||||
rev: v3.6.0
|
rev: v3.6.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: editorconfig-checker
|
- id: editorconfig-checker
|
||||||
|
|
||||||
|
- repo: https://github.com/hukkin/mdformat
|
||||||
|
rev: 1.0.0
|
||||||
|
hooks:
|
||||||
|
- id: mdformat
|
||||||
|
additional_dependencies:
|
||||||
|
- mdformat-gfm
|
||||||
|
exclude: ^(\.serena/|\.github/ISSUE_TEMPLATE/)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
@@ -62,4 +62,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Various minor bug fixes and improved test coverage.
|
- Various minor bug fixes and improved test coverage.
|
||||||
- **Test safety**: Eliminated potential for real sudo execution during testing
|
- **Test safety**: Eliminated potential for real sudo execution during testing
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|||||||
@@ -29,6 +29,6 @@ Claude Code **MUST** follow ALL instructions in [AGENTS.md](AGENTS.md) when work
|
|||||||
|
|
||||||
**The f2b project is in production-ready state** with all critical infrastructure completed.
|
**The f2b project is in production-ready state** with all critical infrastructure completed.
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
**📋 For all development work, refer to [AGENTS.md](AGENTS.md) for complete instructions.**
|
**📋 For all development work, refer to [AGENTS.md](AGENTS.md) for complete instructions.**
|
||||||
|
|||||||
@@ -121,8 +121,8 @@ version 2.0, available at
|
|||||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||||
enforcement ladder](https://github.com/mozilla/diversity).
|
enforcement ladder](https://github.com/mozilla/diversity).
|
||||||
|
|
||||||
[homepage]: https://www.contributor-covenant.org
|
|
||||||
|
|
||||||
For answers to common questions about this code of conduct, see the FAQ at
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
<https://www.contributor-covenant.org/faq>. Translations are available at
|
<https://www.contributor-covenant.org/faq>. Translations are available at
|
||||||
<https://www.contributor-covenant.org/translations>.
|
<https://www.contributor-covenant.org/translations>.
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Thank you for your interest in contributing to **f2b**! Your help is appreciated,
|
Thank you for your interest in contributing to **f2b**! Your help is appreciated,
|
||||||
whether you are fixing bugs, adding features, improving documentation, or helping others.
|
whether you are fixing bugs, adding features, improving documentation, or helping others.
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## How to Contribute
|
## How to Contribute
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ go test ./...
|
|||||||
- Describe your changes, reference related issues, and explain any design decisions.
|
- Describe your changes, reference related issues, and explain any design decisions.
|
||||||
- Be ready to discuss and revise your code based on feedback.
|
- Be ready to discuss and revise your code based on feedback.
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## Code Style
|
## Code Style
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ go test ./...
|
|||||||
- Handle sudo privileges securely - validate before escalation, use mocks in tests.
|
- Handle sudo privileges securely - validate before escalation, use mocks in tests.
|
||||||
- Use argument arrays for command execution, never shell string concatenation.
|
- Use argument arrays for command execution, never shell string concatenation.
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## Security & Testing Guidelines
|
## Security & Testing Guidelines
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ For comprehensive security guidelines, testing patterns, and examples, see:
|
|||||||
- [docs/testing.md](docs/testing.md) - Testing strategies and mock patterns
|
- [docs/testing.md](docs/testing.md) - Testing strategies and mock patterns
|
||||||
- [AGENTS.md](AGENTS.md) - AI/LLM contributor guidelines
|
- [AGENTS.md](AGENTS.md) - AI/LLM contributor guidelines
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## Communication
|
## Communication
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ For comprehensive security guidelines, testing patterns, and examples, see:
|
|||||||
- Review the [Code of Conduct](CODE_OF_CONDUCT.md).
|
- Review the [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||||
- For large or breaking changes, open an issue to discuss your approach before submitting a PR.
|
- For large or breaking changes, open an issue to discuss your approach before submitting a PR.
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## Additional Notes
|
## Additional Notes
|
||||||
|
|
||||||
@@ -95,9 +95,10 @@ For comprehensive security guidelines, testing patterns, and examples, see:
|
|||||||
- If you are an AI/LLM agent, please see [AGENTS.md](AGENTS.md) for additional guidelines.
|
- If you are an AI/LLM agent, please see [AGENTS.md](AGENTS.md) for additional guidelines.
|
||||||
- By contributing, you agree that your contributions will be licensed under the MIT License.
|
- By contributing, you agree that your contributions will be licensed under the MIT License.
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
Thank you for helping make **f2b** better!
|
Thank you for helping make **f2b** better!
|
||||||
|
|
||||||
[effective_go]: https://golang.org/doc/effective_go.html
|
|
||||||
[contributing](CONTRIBUTING.md)
|
[contributing](CONTRIBUTING.md)
|
||||||
|
|
||||||
|
[effective_go]: https://golang.org/doc/effective_go.html
|
||||||
|
|||||||
200
Makefile
200
Makefile
@@ -1,10 +1,36 @@
|
|||||||
# f2b Makefile
|
# f2b Makefile
|
||||||
|
|
||||||
.PHONY: help all build test lint fmt clean install dev-deps ci \
|
.PHONY: help all build test lint fmt clean install
|
||||||
check-deps test-verbose test-coverage update-deps \
|
.PHONY: ci ci-coverage test-verbose test-coverage update-deps fmt-md
|
||||||
lint-go lint-md lint-yaml lint-actions lint-make \
|
.PHONY: lint-go lint-md lint-yaml lint-actions lint-make
|
||||||
ci ci-coverage security dev-setup pre-commit-setup \
|
.PHONY: security dev-setup pre-commit-setup
|
||||||
release-dry-run release release-snapshot release-check _check-tag
|
.PHONY: release-dry-run release release-snapshot release-check _check-tag
|
||||||
|
|
||||||
|
# Tool versions (managed by Renovate)
|
||||||
|
# renovate: datasource=go depName=github.com/goreleaser/goreleaser/v2
|
||||||
|
GORELEASER_VERSION := v2.14.1
|
||||||
|
# renovate: datasource=go depName=github.com/golangci/golangci-lint/v2/cmd/golangci-lint
|
||||||
|
GOLANGCI_LINT_VERSION := v2.10.1
|
||||||
|
# renovate: datasource=go depName=github.com/google/yamlfmt/cmd/yamlfmt
|
||||||
|
YAMLFMT_VERSION := v0.21.0
|
||||||
|
# renovate: datasource=go depName=github.com/rhysd/actionlint/cmd/actionlint
|
||||||
|
ACTIONLINT_VERSION := v1.7.11
|
||||||
|
# renovate: datasource=go depName=golang.org/x/tools/cmd/goimports
|
||||||
|
GOIMPORTS_VERSION := v0.42.0
|
||||||
|
# renovate: datasource=go depName=github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker
|
||||||
|
EDITORCONFIG_CHECKER_VERSION := v3.6.1
|
||||||
|
# renovate: datasource=go depName=github.com/securego/gosec/v2/cmd/gosec
|
||||||
|
GOSEC_VERSION := v2.24.0
|
||||||
|
# renovate: datasource=go depName=honnef.co/go/tools/cmd/staticcheck
|
||||||
|
STATICCHECK_VERSION := v0.7.0
|
||||||
|
# renovate: datasource=go depName=github.com/mgechev/revive
|
||||||
|
REVIVE_VERSION := v1.14.0
|
||||||
|
# renovate: datasource=go depName=github.com/checkmake/checkmake/cmd/checkmake
|
||||||
|
CHECKMAKE_VERSION := v0.3.2
|
||||||
|
# renovate: datasource=go depName=github.com/segmentio/golines
|
||||||
|
GOLINES_VERSION := v0.13.0
|
||||||
|
# renovate: datasource=npm depName=markdownlint-cli2
|
||||||
|
MARKDOWNLINT_CLI2_VERSION := 0.21.0
|
||||||
|
|
||||||
# Default target
|
# Default target
|
||||||
help: ## Show this help message
|
help: ## Show this help message
|
||||||
@@ -14,7 +40,7 @@ help: ## Show this help message
|
|||||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-15s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-15s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||||
|
|
||||||
all: ci ## Run all CI checks (same as ci target)
|
all: ci ## Run all CI checks (same as ci target)
|
||||||
@echo "All checks completed ✓"
|
@echo "All checks completed"
|
||||||
|
|
||||||
# Build targets
|
# Build targets
|
||||||
build: ## Build the f2b binary
|
build: ## Build the f2b binary
|
||||||
@@ -23,107 +49,6 @@ build: ## Build the f2b binary
|
|||||||
install: ## Install f2b globally
|
install: ## Install f2b globally
|
||||||
go install github.com/ivuorinen/f2b@latest
|
go install github.com/ivuorinen/f2b@latest
|
||||||
|
|
||||||
# Development dependencies
|
|
||||||
dev-deps: ## Install development dependencies
|
|
||||||
@echo "Installing development dependencies..."
|
|
||||||
@echo ""
|
|
||||||
@echo "Installing goreleaser..."
|
|
||||||
@go install github.com/goreleaser/goreleaser/v2@v2.12.0;
|
|
||||||
# renovate: datasource=go depName=github.com/goreleaser/goreleaser/v2
|
|
||||||
@GOLANGCI_VERSION=$$(golangci-lint version 2>/dev/null \
|
|
||||||
| grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "0.0.0"); \
|
|
||||||
EXPECTED_VERSION="2.7.2"; \
|
|
||||||
if [ "$$GOLANGCI_VERSION" != "$$EXPECTED_VERSION" ]; then \
|
|
||||||
echo "Installing golangci-lint v$$EXPECTED_VERSION (current: v$$GOLANGCI_VERSION)..."; \
|
|
||||||
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v$$EXPECTED_VERSION; \
|
|
||||||
fi
|
|
||||||
# renovate: datasource=go depName=github.com/golangci/golangci-lint/v2/cmd/golangci-lint
|
|
||||||
@command -v markdownlint-cli2 >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing markdownlint-cli2..."; \
|
|
||||||
npm install -g markdownlint-cli2; \
|
|
||||||
}
|
|
||||||
@command -v markdown-link-check >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing markdown-link-check..."; \
|
|
||||||
npm install -g markdown-link-check; \
|
|
||||||
}
|
|
||||||
@command -v yamlfmt >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing yamlfmt..."; \
|
|
||||||
go install github.com/google/yamlfmt/cmd/yamlfmt@v0.17.2; \
|
|
||||||
}
|
|
||||||
# renovate: datasource=go depName=github.com/google/yamlfmt/cmd/yamlfmt
|
|
||||||
@command -v actionlint >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing actionlint..."; \
|
|
||||||
go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.7; \
|
|
||||||
}
|
|
||||||
# renovate: datasource=go depName=github.com/rhysd/actionlint/cmd/actionlint
|
|
||||||
@command -v goimports >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing goimports..."; \
|
|
||||||
go install golang.org/x/tools/cmd/goimports@v0.28.0; \
|
|
||||||
}
|
|
||||||
# renovate: datasource=go depName=golang.org/x/tools/cmd/goimports
|
|
||||||
@command -v editorconfig-checker >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing editorconfig-checker..."; \
|
|
||||||
go install github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.4.0; \
|
|
||||||
}
|
|
||||||
# renovate: datasource=go depName=github.com/editorconfig-checker/editorconfig-checker/v3
|
|
||||||
@command -v gosec >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing gosec..."; \
|
|
||||||
go install github.com/securego/gosec/v2/cmd/gosec@v2.22.8; \
|
|
||||||
}
|
|
||||||
# renovate: datasource=go depName=github.com/securego/gosec/v2/cmd/gosec
|
|
||||||
@command -v staticcheck >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing staticcheck..."; \
|
|
||||||
go install honnef.co/go/tools/cmd/staticcheck@2024.1.1; \
|
|
||||||
}
|
|
||||||
# renovate: datasource=go depName=honnef.co/go/tools/cmd/staticcheck
|
|
||||||
@command -v revive >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing revive..."; \
|
|
||||||
go install github.com/mgechev/revive@v1.12.0; \
|
|
||||||
}
|
|
||||||
# renovate: datasource=go depName=github.com/mgechev/revive
|
|
||||||
@command -v checkmake >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing checkmake..."; \
|
|
||||||
go install github.com/checkmake/checkmake/cmd/checkmake@0.2.2; \
|
|
||||||
}
|
|
||||||
# renovate: datasource=go depName=github.com/checkmake/checkmake/cmd/checkmake
|
|
||||||
@command -v golines >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing golines..."; \
|
|
||||||
go install github.com/segmentio/golines@v0.13.0; \
|
|
||||||
}
|
|
||||||
# renovate: datasource=go depName=github.com/segmentio/golines
|
|
||||||
|
|
||||||
check-deps: ## Check if all development dependencies are installed
|
|
||||||
@echo "Checking development dependencies..."
|
|
||||||
@command -v go >/dev/null 2>&1 || { \
|
|
||||||
echo "go is not installed"; exit 1; }
|
|
||||||
@command -v goreleaser >/dev/null 2>&1 || {
|
|
||||||
echo "goreleaser is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v golangci-lint >/dev/null 2>&1 || {
|
|
||||||
echo "golangci-lint is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v markdownlint-cli2 >/dev/null 2>&1 || {
|
|
||||||
echo "markdownlint-cli2 is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v markdown-link-check >/dev/null 2>&1 || {
|
|
||||||
echo "markdown-link-check is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v goimports >/dev/null 2>&1 || {
|
|
||||||
echo "goimports is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v editorconfig-checker >/dev/null 2>&1 || {
|
|
||||||
echo "editorconfig-checker is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v gosec >/dev/null 2>&1 || {
|
|
||||||
echo "gosec is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v staticcheck >/dev/null 2>&1 || {
|
|
||||||
echo "staticcheck is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v revive >/dev/null 2>&1 || {
|
|
||||||
echo "revive is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v checkmake >/dev/null 2>&1 || {
|
|
||||||
echo "checkmake is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v yamlfmt >/dev/null 2>&1 || {
|
|
||||||
echo "yamlfmt is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v actionlint >/dev/null 2>&1 || {
|
|
||||||
echo "actionlint is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@command -v golines >/dev/null 2>&1 || {
|
|
||||||
echo "golines is not installed (run: make dev-deps)"; exit 1; }
|
|
||||||
@echo "All dependencies are installed ✓"
|
|
||||||
|
|
||||||
# Testing targets
|
# Testing targets
|
||||||
test: ## Run all tests
|
test: ## Run all tests
|
||||||
go test ./...
|
go test ./...
|
||||||
@@ -134,42 +59,38 @@ test-verbose: ## Run tests with verbose output
|
|||||||
test-coverage: ## Run tests with coverage report
|
test-coverage: ## Run tests with coverage report
|
||||||
go test -coverprofile=coverage.out ./...
|
go test -coverprofile=coverage.out ./...
|
||||||
go tool cover -html=coverage.out -o coverage.html
|
go tool cover -html=coverage.out -o coverage.html
|
||||||
@echo "Coverage report saved to coverage.html"
|
|
||||||
|
|
||||||
update-deps: ## Update Go dependencies to latest patch versions
|
update-deps: ## Update Go dependencies to latest patch versions
|
||||||
@echo "Updating Go dependencies (patch versions only)..."
|
|
||||||
go get -u=patch ./...
|
go get -u=patch ./...
|
||||||
go mod tidy
|
go mod tidy
|
||||||
go mod verify
|
go mod verify
|
||||||
@echo "Dependencies updated ✓"
|
|
||||||
@echo "Updated dependencies:"
|
|
||||||
@go list -u -m all | grep '\[' || true
|
@go list -u -m all | grep '\[' || true
|
||||||
|
|
||||||
# Code quality targets
|
# Code quality targets
|
||||||
fmt: ## Format Go code
|
fmt: ## Format Go code
|
||||||
gofmt -w .
|
gofmt -w .
|
||||||
@echo "Go code formatted ✓"
|
|
||||||
|
fmt-md: ## Format Markdown files
|
||||||
|
@pre-commit run mdformat --all-files
|
||||||
|
|
||||||
lint: ## Run all linters using pre-commit (preferred method)
|
lint: ## Run all linters using pre-commit (preferred method)
|
||||||
@echo "Running pre-commit linters..."
|
|
||||||
@pre-commit run --all-files
|
@pre-commit run --all-files
|
||||||
@echo "All linting completed ✓"
|
|
||||||
|
|
||||||
lint-go: ## Run only Go linters
|
lint-go: ## Run only Go linters
|
||||||
go vet ./...
|
go vet ./...
|
||||||
golangci-lint run --timeout=5m
|
go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) run --timeout=5m
|
||||||
|
|
||||||
lint-md: ## Run only Markdown linter
|
lint-md: ## Run only Markdown linter
|
||||||
markdownlint-cli2 *.md **/*.md
|
npx --yes markdownlint-cli2@$(MARKDOWNLINT_CLI2_VERSION) "*.md" "**/*.md"
|
||||||
|
|
||||||
lint-yaml: ## Run only YAML linter
|
lint-yaml: ## Run only YAML linter
|
||||||
yamlfmt -lint .
|
go run github.com/google/yamlfmt/cmd/yamlfmt@$(YAMLFMT_VERSION) -lint .
|
||||||
|
|
||||||
lint-actions: ## Run only GitHub Actions linter
|
lint-actions: ## Run only GitHub Actions linter
|
||||||
actionlint .github/workflows/*.yml
|
go run github.com/rhysd/actionlint/cmd/actionlint@$(ACTIONLINT_VERSION) .github/workflows/*.yml
|
||||||
|
|
||||||
lint-make: ## Run only Makefile linter
|
lint-make: ## Run only Makefile linter
|
||||||
checkmake Makefile
|
go run github.com/checkmake/checkmake/cmd/checkmake@$(CHECKMAKE_VERSION) Makefile
|
||||||
|
|
||||||
# CI targets
|
# CI targets
|
||||||
ci: fmt lint test ## Run all CI checks (format, lint, test)
|
ci: fmt lint test ## Run all CI checks (format, lint, test)
|
||||||
@@ -178,48 +99,28 @@ ci-coverage: fmt lint test-coverage ## Run CI checks with coverage
|
|||||||
|
|
||||||
# Security targets
|
# Security targets
|
||||||
security: ## Run security checks
|
security: ## Run security checks
|
||||||
gosec ./...
|
go run github.com/securego/gosec/v2/cmd/gosec@$(GOSEC_VERSION) ./...
|
||||||
|
|
||||||
# Cleanup targets
|
# Cleanup targets
|
||||||
clean: ## Clean build artifacts
|
clean: ## Clean build artifacts
|
||||||
rm -f f2b
|
rm -f f2b coverage.out coverage.html
|
||||||
rm -f coverage.out
|
|
||||||
rm -f coverage.html
|
|
||||||
go clean
|
go clean
|
||||||
|
|
||||||
# Development targets
|
# Development targets
|
||||||
dev-setup: dev-deps ## Set up development environment
|
dev-setup: pre-commit-setup ## Set up development environment
|
||||||
@echo "Setting up development environment..."
|
|
||||||
@echo "Installing pre-commit hooks..."
|
|
||||||
@command -v pre-commit >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing pre-commit..."; \
|
|
||||||
pip install pre-commit; \
|
|
||||||
}
|
|
||||||
@pre-commit install
|
|
||||||
@echo "Development environment setup complete ✓"
|
|
||||||
|
|
||||||
pre-commit-setup: ## Install and configure pre-commit hooks
|
pre-commit-setup: ## Install and configure pre-commit hooks
|
||||||
@echo "Installing pre-commit..."
|
@command -v pre-commit >/dev/null 2>&1 || pip install pre-commit
|
||||||
@command -v pre-commit >/dev/null 2>&1 || { \
|
|
||||||
echo "Installing pre-commit..."; \
|
|
||||||
pip install pre-commit; \
|
|
||||||
}
|
|
||||||
@pre-commit install
|
@pre-commit install
|
||||||
@echo "Pre-commit hooks installed ✓"
|
|
||||||
|
|
||||||
# Release targets
|
# Release targets
|
||||||
release-dry-run: ## Test release process without creating artifacts
|
release-dry-run: ## Test release process without creating artifacts
|
||||||
@echo "Testing release process..."
|
|
||||||
@VERSION=$$(git describe --tags --exact-match 2>/dev/null || echo "v0.0.0-dev"); \
|
@VERSION=$$(git describe --tags --exact-match 2>/dev/null || echo "v0.0.0-dev"); \
|
||||||
echo "Building version: $$VERSION"; \
|
echo "Building version: $$VERSION"; \
|
||||||
go build -ldflags "-X github.com/ivuorinen/f2b/cmd.version=$$VERSION" -o f2b-test .
|
go build -ldflags "-X github.com/ivuorinen/f2b/cmd.version=$$VERSION" -o f2b-test . && rm -f f2b-test
|
||||||
@rm -f f2b-test
|
|
||||||
@echo "Release dry-run complete ✓"
|
|
||||||
|
|
||||||
release: ## Create a new release using GoReleaser
|
release: _check-tag ## Create a new release using GoReleaser
|
||||||
@echo "Creating release with GoReleaser..."
|
go run github.com/goreleaser/goreleaser/v2@$(GORELEASER_VERSION) release --clean
|
||||||
@$(MAKE) _check-tag
|
|
||||||
@goreleaser release --clean
|
|
||||||
|
|
||||||
_check-tag: ## Internal: Check if a git tag exists
|
_check-tag: ## Internal: Check if a git tag exists
|
||||||
@if [ -z "$$(git describe --exact-match 2>/dev/null)" ]; then \
|
@if [ -z "$$(git describe --exact-match 2>/dev/null)" ]; then \
|
||||||
@@ -228,10 +129,7 @@ _check-tag: ## Internal: Check if a git tag exists
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
release-snapshot: ## Create a snapshot release (no tag required)
|
release-snapshot: ## Create a snapshot release (no tag required)
|
||||||
@echo "Creating snapshot release with GoReleaser..."
|
go run github.com/goreleaser/goreleaser/v2@$(GORELEASER_VERSION) release --snapshot --clean
|
||||||
goreleaser release --snapshot --clean
|
|
||||||
|
|
||||||
release-check: ## Check if GoReleaser configuration is valid
|
release-check: ## Check if GoReleaser configuration is valid
|
||||||
@echo "Checking GoReleaser configuration..."
|
go run github.com/goreleaser/goreleaser/v2@$(GORELEASER_VERSION) check
|
||||||
goreleaser check
|
|
||||||
@echo "GoReleaser configuration is valid ✓"
|
|
||||||
|
|||||||
55
README.md
55
README.md
@@ -7,7 +7,7 @@ Built with Go, featuring automatic sudo privilege management, shell completion,
|
|||||||
[](https://golang.org/)
|
[](https://golang.org/)
|
||||||
[](https://github.com/ivuorinen/f2b/actions)
|
[](https://github.com/ivuorinen/f2b/actions)
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 🚀 Quick Start
|
## 🚀 Quick Start
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ make build
|
|||||||
go build -ldflags "-X github.com/ivuorinen/f2b/cmd.version=1.2.3" -o f2b .
|
go build -ldflags "-X github.com/ivuorinen/f2b/cmd.version=1.2.3" -o f2b .
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## ✨ Key Features
|
## ✨ Key Features
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ go build -ldflags "-X github.com/ivuorinen/f2b/cmd.version=1.2.3" -o f2b .
|
|||||||
- **Thread Safety**: Extensive race condition testing and protection
|
- **Thread Safety**: Extensive race condition testing and protection
|
||||||
- **Security Audit Trail**: Comprehensive logging of all privileged operations
|
- **Security Audit Trail**: Comprehensive logging of all privileged operations
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 📋 Usage Examples
|
## 📋 Usage Examples
|
||||||
|
|
||||||
@@ -190,7 +190,7 @@ f2b completion fish > ~/.config/fish/completions/f2b.fish
|
|||||||
f2b completion powershell | Out-String | Invoke-Expression
|
f2b completion powershell | Out-String | Invoke-Expression
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## ⚙️ Configuration
|
## ⚙️ Configuration
|
||||||
|
|
||||||
@@ -249,7 +249,7 @@ f2b logs sshd --limit 50 --format=json
|
|||||||
f2b --log-level=debug --log-file=/tmp/f2b-debug.log ban 192.168.1.100
|
f2b --log-level=debug --log-file=/tmp/f2b-debug.log ban 192.168.1.100
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 🔐 Security & Privileges
|
## 🔐 Security & Privileges
|
||||||
|
|
||||||
@@ -268,7 +268,7 @@ f2b is designed with security as a fundamental principle:
|
|||||||
For detailed security practices, threat model, and contribution security guidelines, see
|
For detailed security practices, threat model, and contribution security guidelines, see
|
||||||
[docs/security.md](docs/security.md).
|
[docs/security.md](docs/security.md).
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 📖 Complete Command Reference
|
## 📖 Complete Command Reference
|
||||||
|
|
||||||
@@ -322,7 +322,7 @@ For convenience, most commands have short aliases:
|
|||||||
- `ban` → `banip`, `b`
|
- `ban` → `banip`, `b`
|
||||||
- `unban` → `unbanip`, `ub`
|
- `unban` → `unbanip`, `ub`
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 🏗️ Architecture
|
## 🏗️ Architecture
|
||||||
|
|
||||||
@@ -338,8 +338,8 @@ f2b is built as an **enterprise-grade** Go application following modern architec
|
|||||||
|
|
||||||
### 📊 **Quality Metrics**
|
### 📊 **Quality Metrics**
|
||||||
|
|
||||||
- **Test Coverage**: 76.8% (cmd/), 59.3% (fail2ban/) - Above industry standards
|
- **Test Coverage**: Comprehensive coverage across all packages - above industry standards
|
||||||
- **Modern Testing**: Fluent testing framework reducing code duplication by 60-70%
|
- **Modern Testing**: Fluent testing framework with significant reduction in test duplication
|
||||||
- **Security Testing**: 13 comprehensive attack vector test cases implemented
|
- **Security Testing**: 13 comprehensive attack vector test cases implemented
|
||||||
- **Performance**: Context-aware operations with configurable timeouts and resource management
|
- **Performance**: Context-aware operations with configurable timeouts and resource management
|
||||||
|
|
||||||
@@ -363,7 +363,7 @@ f2b is built as an **enterprise-grade** Go application following modern architec
|
|||||||
For detailed architecture information, implementation patterns, and extension guidelines,
|
For detailed architecture information, implementation patterns, and extension guidelines,
|
||||||
see [docs/architecture.md](docs/architecture.md).
|
see [docs/architecture.md](docs/architecture.md).
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 🧪 Development & Testing
|
## 🧪 Development & Testing
|
||||||
|
|
||||||
@@ -395,8 +395,7 @@ This project uses [pre-commit](https://pre-commit.com/) for unified linting and
|
|||||||
Install the development dependencies and hooks:
|
Install the development dependencies and hooks:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make dev-deps
|
make dev-setup
|
||||||
make pre-commit-setup
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Run all linters:
|
Run all linters:
|
||||||
@@ -428,7 +427,7 @@ f2b logs-watch all --limit 20 | while read line; do
|
|||||||
done
|
done
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 🚀 Releases
|
## 🚀 Releases
|
||||||
|
|
||||||
@@ -438,19 +437,19 @@ Releases are automated using [GoReleaser](https://goreleaser.com/). To create a
|
|||||||
|
|
||||||
1. **Tag the release:**
|
1. **Tag the release:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git tag -a v1.2.3 -m "Release v1.2.3"
|
git tag -a v1.2.3 -m "Release v1.2.3"
|
||||||
git push origin v1.2.3
|
git push origin v1.2.3
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **GitHub Actions will automatically:**
|
2. **GitHub Actions will automatically:**
|
||||||
|
|
||||||
- Build binaries for multiple platforms (Linux, macOS, Windows, BSD)
|
- Build binaries for multiple platforms (Linux, macOS, Windows, BSD)
|
||||||
- Create a GitHub release with changelog
|
- Create a GitHub release with changelog
|
||||||
- Upload release artifacts
|
- Upload release artifacts
|
||||||
- Build and push Docker images
|
- Build and push Docker images
|
||||||
- Update Homebrew tap (if configured)
|
- Update Homebrew tap (if configured)
|
||||||
- Generate .deb, .rpm, and .apk packages
|
- Generate .deb, .rpm, and .apk packages
|
||||||
|
|
||||||
### Manual Release (Development)
|
### Manual Release (Development)
|
||||||
|
|
||||||
@@ -476,7 +475,7 @@ Each release includes:
|
|||||||
- Docker images at `ghcr.io/ivuorinen/f2b` with architecture-specific tags
|
- Docker images at `ghcr.io/ivuorinen/f2b` with architecture-specific tags
|
||||||
- Linux packages (.deb, .rpm, .apk) for multiple architectures
|
- Linux packages (.deb, .rpm, .apk) for multiple architectures
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 🤝 Contributing
|
## 🤝 Contributing
|
||||||
|
|
||||||
@@ -500,25 +499,25 @@ Please see:
|
|||||||
- [docs/security.md](docs/security.md) - Security practices and guidelines
|
- [docs/security.md](docs/security.md) - Security practices and guidelines
|
||||||
- [docs/testing.md](docs/testing.md) - Testing strategies and patterns
|
- [docs/testing.md](docs/testing.md) - Testing strategies and patterns
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 📄 License
|
## 📄 License
|
||||||
|
|
||||||
[MIT License](LICENSE.md).
|
[MIT License](LICENSE.md).
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 👨💻 Author
|
## 👨💻 Author
|
||||||
|
|
||||||
**Ismo Vuorinen** ([@ivuorinen](https://github.com/ivuorinen))
|
**Ismo Vuorinen** ([@ivuorinen](https://github.com/ivuorinen))
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## 🆘 Support
|
## 🆘 Support
|
||||||
|
|
||||||
- 📝 [Open an issue](https://github.com/ivuorinen/f2b/issues)
|
- 📝 [Open an issue](https://github.com/ivuorinen/f2b/issues)
|
||||||
- 📖 [Read the FAQ](docs/faq.md)
|
- 📖 [Read the FAQ](docs/faq.md)
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
_Built with ❤️ and Go. Securing systems one ban at a time._
|
_Built with ❤️ and Go. Securing systems one ban at a time._
|
||||||
|
|||||||
@@ -513,7 +513,7 @@ func TestPersistentPreRun(t *testing.T) {
|
|||||||
t.Fatalf("failed to create temp file: %v", err)
|
t.Fatalf("failed to create temp file: %v", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.Remove(tmpFile.Name()); err != nil {
|
if err := os.Remove(tmpFile.Name()); err != nil { // #nosec G703 -- test file, path from CreateTemp
|
||||||
t.Fatalf("failed to remove temp file: %v", err)
|
t.Fatalf("failed to remove temp file: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -52,46 +52,44 @@ func printMetricsPlain(output io.Writer, snapshot MetricsSnapshot) error {
|
|||||||
|
|
||||||
// System metrics
|
// System metrics
|
||||||
sb.WriteString("System:\n")
|
sb.WriteString("System:\n")
|
||||||
sb.WriteString(fmt.Sprintf(" Uptime: %ds\n", snapshot.UptimeSeconds))
|
fmt.Fprintf(&sb, " Uptime: %ds\n", snapshot.UptimeSeconds)
|
||||||
sb.WriteString(fmt.Sprintf(" Max Memory: %.2f MB\n", float64(snapshot.MaxMemoryUsage)/(1024*1024)))
|
fmt.Fprintf(&sb, " Max Memory: %.2f MB\n", float64(snapshot.MaxMemoryUsage)/(1024*1024))
|
||||||
sb.WriteString(fmt.Sprintf(" Goroutines: %d\n\n", snapshot.GoroutineCount))
|
fmt.Fprintf(&sb, " Goroutines: %d\n\n", snapshot.GoroutineCount)
|
||||||
|
|
||||||
// Command metrics
|
// Command metrics
|
||||||
sb.WriteString("Commands:\n")
|
sb.WriteString("Commands:\n")
|
||||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtTotalExecutions, snapshot.CommandExecutions))
|
fmt.Fprintf(&sb, shared.MetricsFmtTotalExecutions, snapshot.CommandExecutions)
|
||||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtTotalFailures, snapshot.CommandFailures))
|
fmt.Fprintf(&sb, shared.MetricsFmtTotalFailures, snapshot.CommandFailures)
|
||||||
if snapshot.CommandExecutions > 0 {
|
if snapshot.CommandExecutions > 0 {
|
||||||
avgLatency := float64(snapshot.CommandTotalDuration) / float64(snapshot.CommandExecutions)
|
avgLatency := float64(snapshot.CommandTotalDuration) / float64(snapshot.CommandExecutions)
|
||||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtAverageLatencyTop, avgLatency))
|
fmt.Fprintf(&sb, shared.MetricsFmtAverageLatencyTop, avgLatency)
|
||||||
}
|
}
|
||||||
sb.WriteString("\n")
|
sb.WriteString("\n")
|
||||||
|
|
||||||
// Ban/Unban metrics
|
// Ban/Unban metrics
|
||||||
sb.WriteString("Ban Operations:\n")
|
sb.WriteString("Ban Operations:\n")
|
||||||
sb.WriteString(fmt.Sprintf(" Ban Operations: %d (failures: %d)\n", snapshot.BanOperations, snapshot.BanFailures))
|
fmt.Fprintf(&sb, shared.MetricsFmtBanOperations, snapshot.BanOperations, snapshot.BanFailures)
|
||||||
sb.WriteString(
|
fmt.Fprintf(&sb, shared.MetricsFmtUnbanOperations, snapshot.UnbanOperations, snapshot.UnbanFailures)
|
||||||
fmt.Sprintf(" Unban Operations: %d (failures: %d)\n", snapshot.UnbanOperations, snapshot.UnbanFailures),
|
|
||||||
)
|
|
||||||
sb.WriteString("\n")
|
sb.WriteString("\n")
|
||||||
|
|
||||||
// Client metrics
|
// Client metrics
|
||||||
sb.WriteString("Client Operations:\n")
|
sb.WriteString("Client Operations:\n")
|
||||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtTotalOperations, snapshot.ClientOperations))
|
fmt.Fprintf(&sb, shared.MetricsFmtTotalOperations, snapshot.ClientOperations)
|
||||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtTotalFailures, snapshot.ClientFailures))
|
fmt.Fprintf(&sb, shared.MetricsFmtTotalFailures, snapshot.ClientFailures)
|
||||||
if snapshot.ClientOperations > 0 {
|
if snapshot.ClientOperations > 0 {
|
||||||
avgLatency := float64(snapshot.ClientTotalDuration) / float64(snapshot.ClientOperations)
|
avgLatency := float64(snapshot.ClientTotalDuration) / float64(snapshot.ClientOperations)
|
||||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtAverageLatencyTop, avgLatency))
|
fmt.Fprintf(&sb, shared.MetricsFmtAverageLatencyTop, avgLatency)
|
||||||
}
|
}
|
||||||
sb.WriteString("\n")
|
sb.WriteString("\n")
|
||||||
|
|
||||||
// Validation metrics
|
// Validation metrics
|
||||||
sb.WriteString("Validation:\n")
|
sb.WriteString("Validation:\n")
|
||||||
sb.WriteString(fmt.Sprintf(" Cache Hits: %d\n", snapshot.ValidationCacheHits))
|
fmt.Fprintf(&sb, " Cache Hits: %d\n", snapshot.ValidationCacheHits)
|
||||||
sb.WriteString(fmt.Sprintf(" Cache Misses: %d\n", snapshot.ValidationCacheMiss))
|
fmt.Fprintf(&sb, " Cache Misses: %d\n", snapshot.ValidationCacheMiss)
|
||||||
sb.WriteString(fmt.Sprintf(" Failures: %d\n", snapshot.ValidationFailures))
|
fmt.Fprintf(&sb, " Failures: %d\n", snapshot.ValidationFailures)
|
||||||
if total := snapshot.ValidationCacheHits + snapshot.ValidationCacheMiss; total > 0 {
|
if total := snapshot.ValidationCacheHits + snapshot.ValidationCacheMiss; total > 0 {
|
||||||
hitRate := float64(snapshot.ValidationCacheHits) / float64(total) * 100
|
hitRate := float64(snapshot.ValidationCacheHits) / float64(total) * 100
|
||||||
sb.WriteString(fmt.Sprintf(" Cache Hit Rate: %.2f%%\n", hitRate))
|
fmt.Fprintf(&sb, " Cache Hit Rate: %.2f%%\n", hitRate)
|
||||||
}
|
}
|
||||||
sb.WriteString("\n")
|
sb.WriteString("\n")
|
||||||
|
|
||||||
|
|||||||
26
docs/api.md
26
docs/api.md
@@ -240,7 +240,7 @@ const (
|
|||||||
The configuration system supports the following environment variables:
|
The configuration system supports the following environment variables:
|
||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
| -------- | ----------- | ------- |
|
| ---------------------- | -------------------------- | ------------------------ |
|
||||||
| `F2B_LOG_DIR` | Log directory path | `/var/log` |
|
| `F2B_LOG_DIR` | Log directory path | `/var/log` |
|
||||||
| `F2B_FILTER_DIR` | Filter directory path | `/etc/fail2ban/filter.d` |
|
| `F2B_FILTER_DIR` | Filter directory path | `/etc/fail2ban/filter.d` |
|
||||||
| `F2B_LOG_LEVEL` | Log level | `info` |
|
| `F2B_LOG_LEVEL` | Log level | `info` |
|
||||||
@@ -550,30 +550,30 @@ func (h *HTTPHandler) writeError(w http.ResponseWriter, code int, err error) {
|
|||||||
### Error Handling Best Practices
|
### Error Handling Best Practices
|
||||||
|
|
||||||
1. Always use contextual errors for user-facing messages
|
1. Always use contextual errors for user-facing messages
|
||||||
2. Provide remediation hints where possible
|
1. Provide remediation hints where possible
|
||||||
3. Log errors with appropriate context
|
1. Log errors with appropriate context
|
||||||
4. Use error categories for systematic handling
|
1. Use error categories for systematic handling
|
||||||
|
|
||||||
### Context Usage
|
### Context Usage
|
||||||
|
|
||||||
1. Always use context for operations that can timeout
|
1. Always use context for operations that can timeout
|
||||||
2. Propagate context through the call chain
|
1. Propagate context through the call chain
|
||||||
3. Add relevant context values for logging
|
1. Add relevant context values for logging
|
||||||
4. Use context cancellation for cleanup
|
1. Use context cancellation for cleanup
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
1. Use the fluent testing framework for command tests
|
1. Use the fluent testing framework for command tests
|
||||||
2. Always use mock environments for integration tests
|
1. Always use mock environments for integration tests
|
||||||
3. Test both success and failure scenarios
|
1. Test both success and failure scenarios
|
||||||
4. Include timeout testing for long-running operations
|
1. Include timeout testing for long-running operations
|
||||||
|
|
||||||
### Performance
|
### Performance
|
||||||
|
|
||||||
1. Use the metrics system to monitor performance
|
1. Use the metrics system to monitor performance
|
||||||
2. Implement proper caching where appropriate
|
1. Implement proper caching where appropriate
|
||||||
3. Use object pooling for frequently allocated objects
|
1. Use object pooling for frequently allocated objects
|
||||||
4. Profile and optimize hot paths
|
1. Profile and optimize hot paths
|
||||||
|
|
||||||
This documentation provides a comprehensive overview of the f2b internal APIs and patterns.
|
This documentation provides a comprehensive overview of the f2b internal APIs and patterns.
|
||||||
For specific implementation details, refer to the source code and inline documentation.
|
For specific implementation details, refer to the source code and inline documentation.
|
||||||
|
|||||||
@@ -35,17 +35,21 @@ validation caching, and parallel processing capabilities for enterprise-grade re
|
|||||||
### fail2ban/ Package
|
### fail2ban/ Package
|
||||||
|
|
||||||
- **Purpose**: Core business logic and system interaction
|
- **Purpose**: Core business logic and system interaction
|
||||||
|
|
||||||
- **Key Interfaces**:
|
- **Key Interfaces**:
|
||||||
|
|
||||||
- `Client`: Main interface for fail2ban operations with context support
|
- `Client`: Main interface for fail2ban operations with context support
|
||||||
- `Runner`: Command execution interface
|
- `Runner`: Command execution interface
|
||||||
- `SudoChecker`: Privilege validation interface
|
- `SudoChecker`: Privilege validation interface
|
||||||
|
|
||||||
- **Implementations**:
|
- **Implementations**:
|
||||||
|
|
||||||
- `RealClient`: Production fail2ban client with timeout handling
|
- `RealClient`: Production fail2ban client with timeout handling
|
||||||
- `MockClient`: Comprehensive test double with thread-safe operations
|
- `MockClient`: Comprehensive test double with thread-safe operations
|
||||||
- `NoOpClient`: Safe fallback implementation
|
- `NoOpClient`: Safe fallback implementation
|
||||||
|
|
||||||
- **Advanced Features**:
|
- **Advanced Features**:
|
||||||
|
|
||||||
- Context-aware operations with timeout and cancellation support
|
- Context-aware operations with timeout and cancellation support
|
||||||
- Validation caching system with thread-safe operations
|
- Validation caching system with thread-safe operations
|
||||||
- Optimized ban record parsing with object pooling
|
- Optimized ban record parsing with object pooling
|
||||||
@@ -105,14 +109,14 @@ validation caching, and parallel processing capabilities for enterprise-grade re
|
|||||||
### Command Execution Flow
|
### Command Execution Flow
|
||||||
|
|
||||||
1. **CLI Parsing**: Cobra processes command-line arguments
|
1. **CLI Parsing**: Cobra processes command-line arguments
|
||||||
2. **Context Creation**: Create context with timeout for operation
|
1. **Context Creation**: Create context with timeout for operation
|
||||||
3. **Validation**: Input validation with caching and sanitization
|
1. **Validation**: Input validation with caching and sanitization
|
||||||
4. **Privilege Check**: Determine if sudo is required
|
1. **Privilege Check**: Determine if sudo is required
|
||||||
5. **Metrics Start**: Begin performance metrics collection
|
1. **Metrics Start**: Begin performance metrics collection
|
||||||
6. **Business Logic**: Execute fail2ban operations via Client interface with context
|
1. **Business Logic**: Execute fail2ban operations via Client interface with context
|
||||||
7. **Parallel Processing**: Use parallel workers for multi-jail operations
|
1. **Parallel Processing**: Use parallel workers for multi-jail operations
|
||||||
8. **Metrics End**: Record operation timing and success/failure
|
1. **Metrics End**: Record operation timing and success/failure
|
||||||
9. **Output**: Format and display results (plain or JSON)
|
1. **Output**: Format and display results (plain or JSON)
|
||||||
|
|
||||||
### Dependency Flow
|
### Dependency Flow
|
||||||
|
|
||||||
@@ -170,25 +174,25 @@ fail2ban/client.go
|
|||||||
### Adding New Commands
|
### Adding New Commands
|
||||||
|
|
||||||
1. Create new file in `cmd/` package
|
1. Create new file in `cmd/` package
|
||||||
2. Implement command using established patterns with context support
|
1. Implement command using established patterns with context support
|
||||||
3. Use dependency injection for testability
|
1. Use dependency injection for testability
|
||||||
4. Add performance metrics collection
|
1. Add performance metrics collection
|
||||||
5. Implement fluent testing framework patterns
|
1. Implement fluent testing framework patterns
|
||||||
6. Add comprehensive tests with mocks and context-aware operations
|
1. Add comprehensive tests with mocks and context-aware operations
|
||||||
|
|
||||||
### Adding New Backends
|
### Adding New Backends
|
||||||
|
|
||||||
1. Implement the `Client` interface
|
1. Implement the `Client` interface
|
||||||
2. Add any new required interfaces (Runner, etc.)
|
1. Add any new required interfaces (Runner, etc.)
|
||||||
3. Update main.go to support new backend
|
1. Update main.go to support new backend
|
||||||
4. Add configuration options
|
1. Add configuration options
|
||||||
|
|
||||||
### Adding New Output Formats
|
### Adding New Output Formats
|
||||||
|
|
||||||
1. Extend output formatting helpers
|
1. Extend output formatting helpers
|
||||||
2. Update command implementations
|
1. Update command implementations
|
||||||
3. Add format validation
|
1. Add format validation
|
||||||
4. Test with existing commands
|
1. Test with existing commands
|
||||||
|
|
||||||
## Testing Architecture
|
## Testing Architecture
|
||||||
|
|
||||||
|
|||||||
18
docs/faq.md
18
docs/faq.md
@@ -8,7 +8,7 @@
|
|||||||
extensible, and user-friendly alternative to Bash scripts for interacting with Fail2Ban, with automatic sudo
|
extensible, and user-friendly alternative to Bash scripts for interacting with Fail2Ban, with automatic sudo
|
||||||
privilege management, shell completion, and comprehensive security features.
|
privilege management, shell completion, and comprehensive security features.
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## Installation & Setup
|
## Installation & Setup
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ Or install globally:
|
|||||||
go install github.com/ivuorinen/f2b@latest
|
go install github.com/ivuorinen/f2b@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ f2b --command-timeout=45s ban 192.168.1.100
|
|||||||
f2b --parallel-timeout=120s banned all
|
f2b --parallel-timeout=120s banned all
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -193,9 +193,9 @@ f2b --parallel-timeout=120s banned all
|
|||||||
This means you need elevated privileges for the operation you're trying to perform:
|
This means you need elevated privileges for the operation you're trying to perform:
|
||||||
|
|
||||||
1. **Check your privileges:** Run `f2b --log-level=debug version` to see your privilege status
|
1. **Check your privileges:** Run `f2b --log-level=debug version` to see your privilege status
|
||||||
2. **Add sudo:** Try `sudo f2b [command]`
|
1. **Add sudo:** Try `sudo f2b [command]`
|
||||||
3. **Join sudo group:** Ask your admin to add you to the sudo group
|
1. **Join sudo group:** Ask your admin to add you to the sudo group
|
||||||
4. **Test sudo access:** Run `sudo -n true` to check if you can use sudo
|
1. **Test sudo access:** Run `sudo -n true` to check if you can use sudo
|
||||||
|
|
||||||
### The CLI says "permission denied" or "operation not permitted"
|
### The CLI says "permission denied" or "operation not permitted"
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ ls -la /etc/fail2ban/
|
|||||||
sudo fail2ban-client ping
|
sudo fail2ban-client ping
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
@@ -279,11 +279,11 @@ go test ./...
|
|||||||
|
|
||||||
See the `CONTRIBUTING.md` and the Contributing section in the README.
|
See the `CONTRIBUTING.md` and the Contributing section in the README.
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
## Still need help?
|
## Still need help?
|
||||||
|
|
||||||
- Open an issue on GitHub: https://github.com/ivuorinen/f2b/issues
|
- Open an issue on GitHub: https://github.com/ivuorinen/f2b/issues
|
||||||
- Contact the maintainer: ismo@ivuorinen.net
|
- Contact the maintainer: ismo@ivuorinen.net
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|||||||
@@ -226,10 +226,10 @@ Both workflows now use unified pre-commit:
|
|||||||
|
|
||||||
1. **Read configuration files first**: `.editorconfig`, `.golangci.yml`,
|
1. **Read configuration files first**: `.editorconfig`, `.golangci.yml`,
|
||||||
`.markdownlint.json`, `.yamlfmt.yaml`, `.pre-commit-config.yaml`
|
`.markdownlint.json`, `.yamlfmt.yaml`, `.pre-commit-config.yaml`
|
||||||
2. **Apply configuration rules** during development
|
1. **Apply configuration rules** during development
|
||||||
3. **Run pre-commit checks**: `pre-commit run --all-files`
|
1. **Run pre-commit checks**: `pre-commit run --all-files`
|
||||||
4. **Fix all issues** across the project
|
1. **Fix all issues** across the project
|
||||||
5. **Run tests**: `go test ./...`
|
1. **Run tests**: `go test ./...`
|
||||||
|
|
||||||
### Recommended IDE Setup
|
### Recommended IDE Setup
|
||||||
|
|
||||||
@@ -303,19 +303,19 @@ All YAML files include schema references for better IDE support:
|
|||||||
### Debugging Tips
|
### Debugging Tips
|
||||||
|
|
||||||
1. **Run individual hooks** to isolate issues
|
1. **Run individual hooks** to isolate issues
|
||||||
2. **Use `--verbose` flag** with pre-commit
|
1. **Use `--verbose` flag** with pre-commit
|
||||||
3. **Check configuration files** for rule customizations
|
1. **Check configuration files** for rule customizations
|
||||||
4. **Verify tool versions** match CI environment
|
1. **Verify tool versions** match CI environment
|
||||||
|
|
||||||
## Adding New Linting Rules
|
## Adding New Linting Rules
|
||||||
|
|
||||||
### Process
|
### Process
|
||||||
|
|
||||||
1. Update configuration files (`.markdownlint.json`, `.yamlfmt.yaml`, etc.)
|
1. Update configuration files (`.markdownlint.json`, `.yamlfmt.yaml`, etc.)
|
||||||
2. Test changes locally: `pre-commit run --all-files`
|
1. Test changes locally: `pre-commit run --all-files`
|
||||||
3. Update `.pre-commit-config.yaml` if adding new hooks
|
1. Update `.pre-commit-config.yaml` if adding new hooks
|
||||||
4. Document changes in this file
|
1. Document changes in this file
|
||||||
5. Consider backward compatibility
|
1. Consider backward compatibility
|
||||||
|
|
||||||
### Best Practices
|
### Best Practices
|
||||||
|
|
||||||
|
|||||||
@@ -57,13 +57,13 @@ f2b intelligently manages sudo requirements through a comprehensive privilege ch
|
|||||||
### Privilege Escalation Process
|
### Privilege Escalation Process
|
||||||
|
|
||||||
1. **Pre-flight Check**: Determine user capabilities before command execution
|
1. **Pre-flight Check**: Determine user capabilities before command execution
|
||||||
2. **Context Creation**: Create context with timeout for the operation
|
1. **Context Creation**: Create context with timeout for the operation
|
||||||
3. **Command Classification**: Identify if the operation requires privileges
|
1. **Command Classification**: Identify if the operation requires privileges
|
||||||
4. **Smart Escalation**: Only add sudo when necessary for specific commands
|
1. **Smart Escalation**: Only add sudo when necessary for specific commands
|
||||||
5. **Validation**: Ensure privilege escalation succeeded with timeout protection
|
1. **Validation**: Ensure privilege escalation succeeded with timeout protection
|
||||||
6. **Execution**: Run command with appropriate privileges and context
|
1. **Execution**: Run command with appropriate privileges and context
|
||||||
7. **Timeout Handling**: Gracefully handle hanging operations with cancellation
|
1. **Timeout Handling**: Gracefully handle hanging operations with cancellation
|
||||||
8. **Audit**: Log privileged operations with context information
|
1. **Audit**: Log privileged operations with context information
|
||||||
|
|
||||||
### Error Handling
|
### Error Handling
|
||||||
|
|
||||||
@@ -358,10 +358,10 @@ func setupSecureTestEnvironment(t *testing.T) {
|
|||||||
- **Issue**: Insufficient path validation against sophisticated attacks
|
- **Issue**: Insufficient path validation against sophisticated attacks
|
||||||
- **Impact**: Access to files outside intended directories
|
- **Impact**: Access to files outside intended directories
|
||||||
- **Fix**: Comprehensive path traversal protection with extensive test cases covering:
|
- **Fix**: Comprehensive path traversal protection with extensive test cases covering:
|
||||||
- Unicode normalization attacks (\u002e\u002e)
|
- Unicode normalization attacks (\\u002e\\u002e)
|
||||||
- Mixed case traversal (/var/LOG/../../../etc/passwd)
|
- Mixed case traversal (/var/LOG/../../../etc/passwd)
|
||||||
- Multiple slashes (/var/log////../../etc/passwd)
|
- Multiple slashes (/var/log////../../etc/passwd)
|
||||||
- Windows-style paths on Unix (/var/log\..\..\..\etc\passwd)
|
- Windows-style paths on Unix (`/var/log\..\..\..\etc\passwd`)
|
||||||
- URL encoding variants (%2e%2e%2f)
|
- URL encoding variants (%2e%2e%2f)
|
||||||
- Null byte injection attacks
|
- Null byte injection attacks
|
||||||
|
|
||||||
@@ -382,15 +382,15 @@ func setupSecureTestEnvironment(t *testing.T) {
|
|||||||
### Defense in Depth
|
### Defense in Depth
|
||||||
|
|
||||||
1. **Input Validation**: First line of defense against malicious input with caching
|
1. **Input Validation**: First line of defense against malicious input with caching
|
||||||
2. **Advanced Path Traversal Protection**: Extensive sophisticated attack vector protection
|
1. **Advanced Path Traversal Protection**: Extensive sophisticated attack vector protection
|
||||||
3. **Privilege Validation**: Ensure user has necessary permissions with timeout protection
|
1. **Privilege Validation**: Ensure user has necessary permissions with timeout protection
|
||||||
4. **Context-Aware Execution**: Use argument arrays with timeout and cancellation support
|
1. **Context-Aware Execution**: Use argument arrays with timeout and cancellation support
|
||||||
5. **Safe Execution**: Never use shell strings, always use context-aware operations
|
1. **Safe Execution**: Never use shell strings, always use context-aware operations
|
||||||
6. **Error Handling**: Fail safely without information leakage, include context information
|
1. **Error Handling**: Fail safely without information leakage, include context information
|
||||||
7. **Audit Logging**: Track privileged operations with contextual information
|
1. **Audit Logging**: Track privileged operations with contextual information
|
||||||
8. **Test Isolation**: Prevent test-time security compromises with comprehensive mocks
|
1. **Test Isolation**: Prevent test-time security compromises with comprehensive mocks
|
||||||
9. **Performance Security**: Validation caching prevents DoS through repeated validation
|
1. **Performance Security**: Validation caching prevents DoS through repeated validation
|
||||||
10. **Timeout Protection**: Prevent resource exhaustion through hanging operations
|
1. **Timeout Protection**: Prevent resource exhaustion through hanging operations
|
||||||
|
|
||||||
### Security Boundaries
|
### Security Boundaries
|
||||||
|
|
||||||
@@ -403,13 +403,13 @@ User Input → Context → Validation → Path Traversal → Privilege Check →
|
|||||||
**Enhanced Security Flow:**
|
**Enhanced Security Flow:**
|
||||||
|
|
||||||
1. **Context Creation**: Establish timeout and cancellation context
|
1. **Context Creation**: Establish timeout and cancellation context
|
||||||
2. **Input Sanitization**: Clean and validate all user input
|
1. **Input Sanitization**: Clean and validate all user input
|
||||||
3. **Cache Validation**: Check validation cache for performance and DoS protection
|
1. **Cache Validation**: Check validation cache for performance and DoS protection
|
||||||
4. **Path Traversal Protection**: Block extensive sophisticated attack vectors
|
1. **Path Traversal Protection**: Block extensive sophisticated attack vectors
|
||||||
5. **Privilege Verification**: Confirm user permissions with timeout protection
|
1. **Privilege Verification**: Confirm user permissions with timeout protection
|
||||||
6. **Context-Aware Execution**: Execute with timeout and cancellation support
|
1. **Context-Aware Execution**: Execute with timeout and cancellation support
|
||||||
7. **Timeout Handling**: Gracefully handle hanging operations
|
1. **Timeout Handling**: Gracefully handle hanging operations
|
||||||
8. **Comprehensive Auditing**: Log all operations with context information
|
1. **Comprehensive Auditing**: Log all operations with context information
|
||||||
|
|
||||||
## Incident Response
|
## Incident Response
|
||||||
|
|
||||||
@@ -418,17 +418,17 @@ User Input → Context → Validation → Path Traversal → Privilege Check →
|
|||||||
**For security vulnerabilities:**
|
**For security vulnerabilities:**
|
||||||
|
|
||||||
1. **Do not** open public GitHub issues
|
1. **Do not** open public GitHub issues
|
||||||
2. Email: `ismo@ivuorinen.net` with subject "SECURITY: f2b vulnerability"
|
1. Email: `ismo@ivuorinen.net` with subject "SECURITY: f2b vulnerability"
|
||||||
3. Include: Description, impact assessment, reproduction steps
|
1. Include: Description, impact assessment, reproduction steps
|
||||||
4. Expect: Acknowledgment within 48 hours
|
1. Expect: Acknowledgment within 48 hours
|
||||||
|
|
||||||
### Security Update Process
|
### Security Update Process
|
||||||
|
|
||||||
1. **Assessment**: Evaluate impact and affected versions
|
1. **Assessment**: Evaluate impact and affected versions
|
||||||
2. **Development**: Create fix with security tests
|
1. **Development**: Create fix with security tests
|
||||||
3. **Testing**: Comprehensive security testing
|
1. **Testing**: Comprehensive security testing
|
||||||
4. **Release**: Coordinated disclosure with security advisory
|
1. **Release**: Coordinated disclosure with security advisory
|
||||||
5. **Communication**: Notify users via GitHub security advisories
|
1. **Communication**: Notify users via GitHub security advisories
|
||||||
|
|
||||||
## Security Best Practices
|
## Security Best Practices
|
||||||
|
|
||||||
|
|||||||
@@ -604,11 +604,11 @@ go tool cover -func=coverage.out | grep total
|
|||||||
### Avoid These Mistakes
|
### Avoid These Mistakes
|
||||||
|
|
||||||
1. **Real sudo execution in tests** - Always use MockSudoChecker
|
1. **Real sudo execution in tests** - Always use MockSudoChecker
|
||||||
2. **Hardcoded file paths** - Use temporary files or mocks
|
1. **Hardcoded file paths** - Use temporary files or mocks
|
||||||
3. **Network dependencies** - Mock all external calls
|
1. **Network dependencies** - Mock all external calls
|
||||||
4. **Race conditions** - Use proper synchronization in concurrent tests
|
1. **Race conditions** - Use proper synchronization in concurrent tests
|
||||||
5. **Leaked goroutines** - Clean up background processes
|
1. **Leaked goroutines** - Clean up background processes
|
||||||
6. **Platform dependencies** - Write portable tests
|
1. **Platform dependencies** - Write portable tests
|
||||||
|
|
||||||
### Enhanced Security Testing Checklist
|
### Enhanced Security Testing Checklist
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ func (r *OSRunner) CombinedOutputWithContext(ctx context.Context, name string, a
|
|||||||
if err := validateCommandExecution(ctx, name, args); err != nil {
|
if err := validateCommandExecution(ctx, name, args); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// #nosec G204 -- command validated by validateCommandExecution
|
||||||
return exec.CommandContext(ctx, name, args...).CombinedOutput()
|
return exec.CommandContext(ctx, name, args...).CombinedOutput()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ func (r *OSRunner) CombinedOutputWithSudoContext(ctx context.Context, name strin
|
|||||||
|
|
||||||
// If already root, no need for sudo
|
// If already root, no need for sudo
|
||||||
if checker.IsRoot() {
|
if checker.IsRoot() {
|
||||||
return exec.CommandContext(ctx, name, args...).CombinedOutput()
|
return exec.CommandContext(ctx, name, args...).CombinedOutput() // #nosec G204 -- command validated above
|
||||||
}
|
}
|
||||||
|
|
||||||
// If command requires sudo and user has privileges, use sudo
|
// If command requires sudo and user has privileges, use sudo
|
||||||
@@ -104,7 +105,7 @@ func (r *OSRunner) CombinedOutputWithSudoContext(ctx context.Context, name strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise run without sudo
|
// Otherwise run without sudo
|
||||||
return exec.CommandContext(ctx, name, args...).CombinedOutput()
|
return exec.CommandContext(ctx, name, args...).CombinedOutput() // #nosec G204 -- command validated above
|
||||||
}
|
}
|
||||||
|
|
||||||
// runnerManager provides thread-safe access to the global Runner.
|
// runnerManager provides thread-safe access to the global Runner.
|
||||||
|
|||||||
7
main.go
7
main.go
@@ -34,7 +34,12 @@ func main() {
|
|||||||
// Check if this is a sudo privilege error
|
// Check if this is a sudo privilege error
|
||||||
if strings.Contains(err.Error(), "fail2ban operations require sudo privileges") {
|
if strings.Contains(err.Error(), "fail2ban operations require sudo privileges") {
|
||||||
fmt.Fprintln(os.Stderr, "Hint: Try running with 'sudo' or ensure your user is in the sudo group")
|
fmt.Fprintln(os.Stderr, "Hint: Try running with 'sudo' or ensure your user is in the sudo group")
|
||||||
fmt.Fprintln(os.Stderr, "Example: sudo", strings.Join(os.Args, " "))
|
// #nosec G705 -- stderr hint, not user-facing HTML
|
||||||
|
fmt.Fprintln(
|
||||||
|
os.Stderr,
|
||||||
|
"Example: sudo",
|
||||||
|
strings.Join(os.Args, " "),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -179,7 +180,7 @@ func BenchmarkGlobalStateAccess(b *testing.B) {
|
|||||||
fail2ban.GetLogDir()
|
fail2ban.GetLogDir()
|
||||||
} else {
|
} else {
|
||||||
// 50% writes
|
// 50% writes
|
||||||
fail2ban.SetLogDir("/tmp/test-" + string(rune(b.N)))
|
fail2ban.SetLogDir("/tmp/test-" + strconv.Itoa(b.N))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ivuorinen/f2b/fail2ban"
|
"github.com/ivuorinen/f2b/fail2ban"
|
||||||
@@ -378,24 +380,28 @@ func TestSecurityAudit_ConcurrentSafety(t *testing.T) {
|
|||||||
|
|
||||||
// Multiple goroutines modifying global state should not cause races
|
// Multiple goroutines modifying global state should not cause races
|
||||||
// This is tested by running with -race flag in CI
|
// This is tested by running with -race flag in CI
|
||||||
for i := 0; i < 10; i++ {
|
var wg sync.WaitGroup
|
||||||
go func(id int) {
|
for i := range 10 {
|
||||||
fail2ban.SetLogDir("/tmp/test-" + string(rune(id)))
|
wg.Go(func() {
|
||||||
|
fail2ban.SetLogDir("/tmp/test-" + strconv.Itoa(i))
|
||||||
fail2ban.GetLogDir()
|
fail2ban.GetLogDir()
|
||||||
}(i)
|
})
|
||||||
}
|
}
|
||||||
|
wg.Wait()
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("CacheStatisticsSafety", func(_ *testing.T) {
|
t.Run("CacheStatisticsSafety", func(_ *testing.T) {
|
||||||
processor := fail2ban.NewOptimizedLogProcessor()
|
processor := fail2ban.NewOptimizedLogProcessor()
|
||||||
|
|
||||||
// Multiple goroutines accessing cache statistics should be safe
|
// Multiple goroutines accessing cache statistics should be safe
|
||||||
for i := 0; i < 10; i++ {
|
var wg sync.WaitGroup
|
||||||
go func() {
|
for range 10 {
|
||||||
|
wg.Go(func() {
|
||||||
processor.GetCacheStats()
|
processor.GetCacheStats()
|
||||||
processor.ClearCaches()
|
processor.ClearCaches()
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
wg.Wait()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -499,4 +499,10 @@ const (
|
|||||||
|
|
||||||
// MetricsFmtAverageLatencyTop is the format for average latency (top-level)
|
// MetricsFmtAverageLatencyTop is the format for average latency (top-level)
|
||||||
MetricsFmtAverageLatencyTop = " Average Latency: %.2f ms\n"
|
MetricsFmtAverageLatencyTop = " Average Latency: %.2f ms\n"
|
||||||
|
|
||||||
|
// MetricsFmtBanOperations is the format for ban operations with failures
|
||||||
|
MetricsFmtBanOperations = " Ban Operations: %d (failures: %d)\n"
|
||||||
|
|
||||||
|
// MetricsFmtUnbanOperations is the format for unban operations with failures
|
||||||
|
MetricsFmtUnbanOperations = " Unban Operations: %d (failures: %d)\n"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user