mirror of
https://github.com/ivuorinen/f2b.git
synced 2026-03-07 02:58:02 +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}]
|
||||
indent_style = tab
|
||||
|
||||
[*.md]
|
||||
indent_size = unset
|
||||
|
||||
[.github/renovate.json]
|
||||
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: ''
|
||||
labels: bug
|
||||
assignees: ivuorinen
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
@@ -14,9 +13,9 @@ A clear and concise description of what the bug is.
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Run command: `f2b [command]`
|
||||
2. With arguments: `[arguments]`
|
||||
3. Expected behavior: `[what should happen]`
|
||||
4. Actual result: `[what actually happened]`
|
||||
1. With arguments: `[arguments]`
|
||||
1. Expected behavior: `[what should happen]`
|
||||
1. Actual result: `[what actually happened]`
|
||||
|
||||
**Expected behavior**
|
||||
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: ''
|
||||
labels: enhancement
|
||||
assignees: ivuorinen
|
||||
|
||||
---
|
||||
|
||||
**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",
|
||||
"extends": ["github>ivuorinen/renovate-config", "github>renovatebot/presets:golang", "schedule:weekly"],
|
||||
"extends": ["github>ivuorinen/renovate-config", "schedule:weekly"],
|
||||
"customManagers": [
|
||||
{
|
||||
"customType": "regex",
|
||||
"fileMatch": ["^Makefile$", "\\.mk$"],
|
||||
"managerFilePatterns": ["^Makefile$", ".*\\.mk$"],
|
||||
"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"
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
"packageRules": [
|
||||
{
|
||||
"matchManagers": ["custom.regex"],
|
||||
"matchFileNames": ["Makefile", "*.mk"],
|
||||
"matchFileNames": ["Makefile", "**/*.mk"],
|
||||
"groupName": "development tools",
|
||||
"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
|
||||
id: claude
|
||||
uses: anthropics/claude-code-action@f64219702d7454cf29fe32a74104be6ed43dc637 # v1.0.34
|
||||
uses: anthropics/claude-code-action@ba7fa4bcf054319261202aef93d71a89112a8d00 # v1.0.64
|
||||
with:
|
||||
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
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
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
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
@@ -46,6 +46,9 @@ jobs:
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: pip install pyyaml
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
|
||||
with:
|
||||
@@ -58,7 +61,7 @@ jobs:
|
||||
go test -race -covermode=atomic -coverprofile=coverage.out ./...
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: coverage-report
|
||||
path: coverage.out
|
||||
@@ -66,4 +69,4 @@ jobs:
|
||||
- name: Run PR Lint
|
||||
# Custom PR linting action that performs additional PR-specific checks
|
||||
# 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
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Install GoReleaser
|
||||
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
|
||||
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
|
||||
with:
|
||||
install-only: true
|
||||
version: "~> v2"
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
|
||||
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
|
||||
with:
|
||||
version: "~> v2"
|
||||
args: release --clean
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
# HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload Release Assets
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: release-artifacts
|
||||
path: dist/
|
||||
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -23,4 +23,4 @@ jobs:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
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
|
||||
issues: write
|
||||
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
|
||||
# Anonymous test data from real fail2ban logs
|
||||
!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
|
||||
SHOW_SKIPPED_LINTERS: false # Show skipped linters in MegaLinter log
|
||||
|
||||
FILTER_REGEX_EXCLUDE: '(\.serena/)'
|
||||
|
||||
DISABLE_LINTERS:
|
||||
- REPOSITORY_DEVSKIM
|
||||
- GO_REVIVE # run as part of golangci-lint
|
||||
|
||||
@@ -25,13 +25,13 @@ repos:
|
||||
hooks:
|
||||
- id: 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
|
||||
types: [go]
|
||||
pass_filenames: false
|
||||
|
||||
- repo: https://github.com/google/yamlfmt
|
||||
rev: v0.20.0
|
||||
rev: v0.21.0
|
||||
hooks:
|
||||
- id: yamlfmt
|
||||
|
||||
@@ -48,7 +48,7 @@ repos:
|
||||
args: [-q, -c, .markdown-link-check.json]
|
||||
|
||||
- repo: https://github.com/rhysd/actionlint
|
||||
rev: v1.7.9
|
||||
rev: v1.7.11
|
||||
hooks:
|
||||
- id: actionlint
|
||||
args: ["-shellcheck="]
|
||||
@@ -59,26 +59,34 @@ repos:
|
||||
- id: shfmt
|
||||
|
||||
- repo: https://github.com/checkmake/checkmake
|
||||
rev: 0.2.2
|
||||
rev: v0.3.2
|
||||
hooks:
|
||||
- id: checkmake
|
||||
name: Makefile Linter
|
||||
files: ^Makefile$
|
||||
|
||||
- repo: https://github.com/bridgecrewio/checkov.git
|
||||
rev: "3.2.495"
|
||||
rev: "3.2.506"
|
||||
hooks:
|
||||
- id: checkov
|
||||
args:
|
||||
- "--quiet"
|
||||
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.36.0
|
||||
rev: 0.37.0
|
||||
hooks:
|
||||
- id: check-github-workflows
|
||||
args: ["--verbose"]
|
||||
|
||||
- repo: https://github.com/editorconfig-checker/editorconfig-checker
|
||||
rev: v3.6.0
|
||||
rev: v3.6.1
|
||||
hooks:
|
||||
- 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/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## [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.
|
||||
- **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.
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
**📋 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
|
||||
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
|
||||
<https://www.contributor-covenant.org/faq>. Translations are available at
|
||||
<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,
|
||||
whether you are fixing bugs, adding features, improving documentation, or helping others.
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## How to Contribute
|
||||
|
||||
@@ -48,7 +48,7 @@ go test ./...
|
||||
- Describe your changes, reference related issues, and explain any design decisions.
|
||||
- Be ready to discuss and revise your code based on feedback.
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## Code Style
|
||||
|
||||
@@ -61,7 +61,7 @@ go test ./...
|
||||
- Handle sudo privileges securely - validate before escalation, use mocks in tests.
|
||||
- Use argument arrays for command execution, never shell string concatenation.
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 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
|
||||
- [AGENTS.md](AGENTS.md) - AI/LLM contributor guidelines
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## Communication
|
||||
|
||||
@@ -86,7 +86,7 @@ For comprehensive security guidelines, testing patterns, and examples, see:
|
||||
- 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.
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 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.
|
||||
- By contributing, you agree that your contributions will be licensed under the MIT License.
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
Thank you for helping make **f2b** better!
|
||||
|
||||
[effective_go]: https://golang.org/doc/effective_go.html
|
||||
[contributing](CONTRIBUTING.md)
|
||||
|
||||
[effective_go]: https://golang.org/doc/effective_go.html
|
||||
|
||||
200
Makefile
200
Makefile
@@ -1,10 +1,36 @@
|
||||
# f2b Makefile
|
||||
|
||||
.PHONY: help all build test lint fmt clean install dev-deps ci \
|
||||
check-deps test-verbose test-coverage update-deps \
|
||||
lint-go lint-md lint-yaml lint-actions lint-make \
|
||||
ci ci-coverage security dev-setup pre-commit-setup \
|
||||
release-dry-run release release-snapshot release-check _check-tag
|
||||
.PHONY: help all build test lint fmt clean install
|
||||
.PHONY: ci ci-coverage test-verbose test-coverage update-deps fmt-md
|
||||
.PHONY: lint-go lint-md lint-yaml lint-actions lint-make
|
||||
.PHONY: security dev-setup pre-commit-setup
|
||||
.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
|
||||
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)
|
||||
|
||||
all: ci ## Run all CI checks (same as ci target)
|
||||
@echo "All checks completed ✓"
|
||||
@echo "All checks completed"
|
||||
|
||||
# Build targets
|
||||
build: ## Build the f2b binary
|
||||
@@ -23,107 +49,6 @@ build: ## Build the f2b binary
|
||||
install: ## Install f2b globally
|
||||
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
|
||||
test: ## Run all tests
|
||||
go test ./...
|
||||
@@ -134,42 +59,38 @@ test-verbose: ## Run tests with verbose output
|
||||
test-coverage: ## Run tests with coverage report
|
||||
go test -coverprofile=coverage.out ./...
|
||||
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
|
||||
@echo "Updating Go dependencies (patch versions only)..."
|
||||
go get -u=patch ./...
|
||||
go mod tidy
|
||||
go mod verify
|
||||
@echo "Dependencies updated ✓"
|
||||
@echo "Updated dependencies:"
|
||||
@go list -u -m all | grep '\[' || true
|
||||
|
||||
# Code quality targets
|
||||
fmt: ## Format Go code
|
||||
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)
|
||||
@echo "Running pre-commit linters..."
|
||||
@pre-commit run --all-files
|
||||
@echo "All linting completed ✓"
|
||||
|
||||
lint-go: ## Run only Go linters
|
||||
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
|
||||
markdownlint-cli2 *.md **/*.md
|
||||
npx --yes markdownlint-cli2@$(MARKDOWNLINT_CLI2_VERSION) "*.md" "**/*.md"
|
||||
|
||||
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
|
||||
actionlint .github/workflows/*.yml
|
||||
go run github.com/rhysd/actionlint/cmd/actionlint@$(ACTIONLINT_VERSION) .github/workflows/*.yml
|
||||
|
||||
lint-make: ## Run only Makefile linter
|
||||
checkmake Makefile
|
||||
go run github.com/checkmake/checkmake/cmd/checkmake@$(CHECKMAKE_VERSION) Makefile
|
||||
|
||||
# CI targets
|
||||
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: ## Run security checks
|
||||
gosec ./...
|
||||
go run github.com/securego/gosec/v2/cmd/gosec@$(GOSEC_VERSION) ./...
|
||||
|
||||
# Cleanup targets
|
||||
clean: ## Clean build artifacts
|
||||
rm -f f2b
|
||||
rm -f coverage.out
|
||||
rm -f coverage.html
|
||||
rm -f f2b coverage.out coverage.html
|
||||
go clean
|
||||
|
||||
# Development targets
|
||||
dev-setup: dev-deps ## 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 ✓"
|
||||
dev-setup: pre-commit-setup ## Set up development environment
|
||||
|
||||
pre-commit-setup: ## Install and configure pre-commit hooks
|
||||
@echo "Installing pre-commit..."
|
||||
@command -v pre-commit >/dev/null 2>&1 || { \
|
||||
echo "Installing pre-commit..."; \
|
||||
pip install pre-commit; \
|
||||
}
|
||||
@command -v pre-commit >/dev/null 2>&1 || pip install pre-commit
|
||||
@pre-commit install
|
||||
@echo "Pre-commit hooks installed ✓"
|
||||
|
||||
# Release targets
|
||||
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"); \
|
||||
echo "Building version: $$VERSION"; \
|
||||
go build -ldflags "-X github.com/ivuorinen/f2b/cmd.version=$$VERSION" -o f2b-test .
|
||||
@rm -f f2b-test
|
||||
@echo "Release dry-run complete ✓"
|
||||
go build -ldflags "-X github.com/ivuorinen/f2b/cmd.version=$$VERSION" -o f2b-test . && rm -f f2b-test
|
||||
|
||||
release: ## Create a new release using GoReleaser
|
||||
@echo "Creating release with GoReleaser..."
|
||||
@$(MAKE) _check-tag
|
||||
@goreleaser release --clean
|
||||
release: _check-tag ## Create a new release using GoReleaser
|
||||
go run github.com/goreleaser/goreleaser/v2@$(GORELEASER_VERSION) release --clean
|
||||
|
||||
_check-tag: ## Internal: Check if a git tag exists
|
||||
@if [ -z "$$(git describe --exact-match 2>/dev/null)" ]; then \
|
||||
@@ -228,10 +129,7 @@ _check-tag: ## Internal: Check if a git tag exists
|
||||
fi
|
||||
|
||||
release-snapshot: ## Create a snapshot release (no tag required)
|
||||
@echo "Creating snapshot release with GoReleaser..."
|
||||
goreleaser release --snapshot --clean
|
||||
go run github.com/goreleaser/goreleaser/v2@$(GORELEASER_VERSION) release --snapshot --clean
|
||||
|
||||
release-check: ## Check if GoReleaser configuration is valid
|
||||
@echo "Checking GoReleaser configuration..."
|
||||
goreleaser check
|
||||
@echo "GoReleaser configuration is valid ✓"
|
||||
go run github.com/goreleaser/goreleaser/v2@$(GORELEASER_VERSION) check
|
||||
|
||||
55
README.md
55
README.md
@@ -7,7 +7,7 @@ Built with Go, featuring automatic sudo privilege management, shell completion,
|
||||
[](https://golang.org/)
|
||||
[](https://github.com/ivuorinen/f2b/actions)
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
@@ -79,7 +79,7 @@ make build
|
||||
go build -ldflags "-X github.com/ivuorinen/f2b/cmd.version=1.2.3" -o f2b .
|
||||
```
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## ✨ 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
|
||||
- **Security Audit Trail**: Comprehensive logging of all privileged operations
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 📋 Usage Examples
|
||||
|
||||
@@ -190,7 +190,7 @@ f2b completion fish > ~/.config/fish/completions/f2b.fish
|
||||
f2b completion powershell | Out-String | Invoke-Expression
|
||||
```
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## ⚙️ 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
|
||||
```
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 🔐 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
|
||||
[docs/security.md](docs/security.md).
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 📖 Complete Command Reference
|
||||
|
||||
@@ -322,7 +322,7 @@ For convenience, most commands have short aliases:
|
||||
- `ban` → `banip`, `b`
|
||||
- `unban` → `unbanip`, `ub`
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
@@ -338,8 +338,8 @@ f2b is built as an **enterprise-grade** Go application following modern architec
|
||||
|
||||
### 📊 **Quality Metrics**
|
||||
|
||||
- **Test Coverage**: 76.8% (cmd/), 59.3% (fail2ban/) - Above industry standards
|
||||
- **Modern Testing**: Fluent testing framework reducing code duplication by 60-70%
|
||||
- **Test Coverage**: Comprehensive coverage across all packages - above industry standards
|
||||
- **Modern Testing**: Fluent testing framework with significant reduction in test duplication
|
||||
- **Security Testing**: 13 comprehensive attack vector test cases implemented
|
||||
- **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,
|
||||
see [docs/architecture.md](docs/architecture.md).
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 🧪 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:
|
||||
|
||||
```bash
|
||||
make dev-deps
|
||||
make pre-commit-setup
|
||||
make dev-setup
|
||||
```
|
||||
|
||||
Run all linters:
|
||||
@@ -428,7 +427,7 @@ f2b logs-watch all --limit 20 | while read line; do
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 🚀 Releases
|
||||
|
||||
@@ -438,19 +437,19 @@ Releases are automated using [GoReleaser](https://goreleaser.com/). To create a
|
||||
|
||||
1. **Tag the release:**
|
||||
|
||||
```bash
|
||||
git tag -a v1.2.3 -m "Release v1.2.3"
|
||||
git push origin v1.2.3
|
||||
```
|
||||
```bash
|
||||
git tag -a v1.2.3 -m "Release v1.2.3"
|
||||
git push origin v1.2.3
|
||||
```
|
||||
|
||||
2. **GitHub Actions will automatically:**
|
||||
|
||||
- Build binaries for multiple platforms (Linux, macOS, Windows, BSD)
|
||||
- Create a GitHub release with changelog
|
||||
- Upload release artifacts
|
||||
- Build and push Docker images
|
||||
- Update Homebrew tap (if configured)
|
||||
- Generate .deb, .rpm, and .apk packages
|
||||
- Build binaries for multiple platforms (Linux, macOS, Windows, BSD)
|
||||
- Create a GitHub release with changelog
|
||||
- Upload release artifacts
|
||||
- Build and push Docker images
|
||||
- Update Homebrew tap (if configured)
|
||||
- Generate .deb, .rpm, and .apk packages
|
||||
|
||||
### Manual Release (Development)
|
||||
|
||||
@@ -476,7 +475,7 @@ Each release includes:
|
||||
- Docker images at `ghcr.io/ivuorinen/f2b` with architecture-specific tags
|
||||
- Linux packages (.deb, .rpm, .apk) for multiple architectures
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
@@ -500,25 +499,25 @@ Please see:
|
||||
- [docs/security.md](docs/security.md) - Security practices and guidelines
|
||||
- [docs/testing.md](docs/testing.md) - Testing strategies and patterns
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 📄 License
|
||||
|
||||
[MIT License](LICENSE.md).
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 👨💻 Author
|
||||
|
||||
**Ismo Vuorinen** ([@ivuorinen](https://github.com/ivuorinen))
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 🆘 Support
|
||||
|
||||
- 📝 [Open an issue](https://github.com/ivuorinen/f2b/issues)
|
||||
- 📖 [Read the FAQ](docs/faq.md)
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
_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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -52,46 +52,44 @@ func printMetricsPlain(output io.Writer, snapshot MetricsSnapshot) error {
|
||||
|
||||
// System metrics
|
||||
sb.WriteString("System:\n")
|
||||
sb.WriteString(fmt.Sprintf(" Uptime: %ds\n", snapshot.UptimeSeconds))
|
||||
sb.WriteString(fmt.Sprintf(" Max Memory: %.2f MB\n", float64(snapshot.MaxMemoryUsage)/(1024*1024)))
|
||||
sb.WriteString(fmt.Sprintf(" Goroutines: %d\n\n", snapshot.GoroutineCount))
|
||||
fmt.Fprintf(&sb, " Uptime: %ds\n", snapshot.UptimeSeconds)
|
||||
fmt.Fprintf(&sb, " Max Memory: %.2f MB\n", float64(snapshot.MaxMemoryUsage)/(1024*1024))
|
||||
fmt.Fprintf(&sb, " Goroutines: %d\n\n", snapshot.GoroutineCount)
|
||||
|
||||
// Command metrics
|
||||
sb.WriteString("Commands:\n")
|
||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtTotalExecutions, snapshot.CommandExecutions))
|
||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtTotalFailures, snapshot.CommandFailures))
|
||||
fmt.Fprintf(&sb, shared.MetricsFmtTotalExecutions, snapshot.CommandExecutions)
|
||||
fmt.Fprintf(&sb, shared.MetricsFmtTotalFailures, snapshot.CommandFailures)
|
||||
if snapshot.CommandExecutions > 0 {
|
||||
avgLatency := float64(snapshot.CommandTotalDuration) / float64(snapshot.CommandExecutions)
|
||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtAverageLatencyTop, avgLatency))
|
||||
fmt.Fprintf(&sb, shared.MetricsFmtAverageLatencyTop, avgLatency)
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Ban/Unban metrics
|
||||
sb.WriteString("Ban Operations:\n")
|
||||
sb.WriteString(fmt.Sprintf(" Ban Operations: %d (failures: %d)\n", snapshot.BanOperations, snapshot.BanFailures))
|
||||
sb.WriteString(
|
||||
fmt.Sprintf(" Unban Operations: %d (failures: %d)\n", snapshot.UnbanOperations, snapshot.UnbanFailures),
|
||||
)
|
||||
fmt.Fprintf(&sb, shared.MetricsFmtBanOperations, snapshot.BanOperations, snapshot.BanFailures)
|
||||
fmt.Fprintf(&sb, shared.MetricsFmtUnbanOperations, snapshot.UnbanOperations, snapshot.UnbanFailures)
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Client metrics
|
||||
sb.WriteString("Client Operations:\n")
|
||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtTotalOperations, snapshot.ClientOperations))
|
||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtTotalFailures, snapshot.ClientFailures))
|
||||
fmt.Fprintf(&sb, shared.MetricsFmtTotalOperations, snapshot.ClientOperations)
|
||||
fmt.Fprintf(&sb, shared.MetricsFmtTotalFailures, snapshot.ClientFailures)
|
||||
if snapshot.ClientOperations > 0 {
|
||||
avgLatency := float64(snapshot.ClientTotalDuration) / float64(snapshot.ClientOperations)
|
||||
sb.WriteString(fmt.Sprintf(shared.MetricsFmtAverageLatencyTop, avgLatency))
|
||||
fmt.Fprintf(&sb, shared.MetricsFmtAverageLatencyTop, avgLatency)
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Validation metrics
|
||||
sb.WriteString("Validation:\n")
|
||||
sb.WriteString(fmt.Sprintf(" Cache Hits: %d\n", snapshot.ValidationCacheHits))
|
||||
sb.WriteString(fmt.Sprintf(" Cache Misses: %d\n", snapshot.ValidationCacheMiss))
|
||||
sb.WriteString(fmt.Sprintf(" Failures: %d\n", snapshot.ValidationFailures))
|
||||
fmt.Fprintf(&sb, " Cache Hits: %d\n", snapshot.ValidationCacheHits)
|
||||
fmt.Fprintf(&sb, " Cache Misses: %d\n", snapshot.ValidationCacheMiss)
|
||||
fmt.Fprintf(&sb, " Failures: %d\n", snapshot.ValidationFailures)
|
||||
if total := snapshot.ValidationCacheHits + snapshot.ValidationCacheMiss; total > 0 {
|
||||
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")
|
||||
|
||||
|
||||
40
docs/api.md
40
docs/api.md
@@ -239,14 +239,14 @@ const (
|
||||
|
||||
The configuration system supports the following environment variables:
|
||||
|
||||
| Variable | Description | Default |
|
||||
| -------- | ----------- | ------- |
|
||||
| `F2B_LOG_DIR` | Log directory path | `/var/log` |
|
||||
| `F2B_FILTER_DIR` | Filter directory path | `/etc/fail2ban/filter.d` |
|
||||
| `F2B_LOG_LEVEL` | Log level | `info` |
|
||||
| `F2B_COMMAND_TIMEOUT` | Command timeout | `30s` |
|
||||
| `F2B_FILE_TIMEOUT` | File operation timeout | `10s` |
|
||||
| `F2B_PARALLEL_TIMEOUT` | Parallel operation timeout | `60s` |
|
||||
| Variable | Description | Default |
|
||||
| ---------------------- | -------------------------- | ------------------------ |
|
||||
| `F2B_LOG_DIR` | Log directory path | `/var/log` |
|
||||
| `F2B_FILTER_DIR` | Filter directory path | `/etc/fail2ban/filter.d` |
|
||||
| `F2B_LOG_LEVEL` | Log level | `info` |
|
||||
| `F2B_COMMAND_TIMEOUT` | Command timeout | `30s` |
|
||||
| `F2B_FILE_TIMEOUT` | File operation timeout | `10s` |
|
||||
| `F2B_PARALLEL_TIMEOUT` | Parallel operation timeout | `60s` |
|
||||
|
||||
### Path Security
|
||||
|
||||
@@ -550,30 +550,30 @@ func (h *HTTPHandler) writeError(w http.ResponseWriter, code int, err error) {
|
||||
### Error Handling Best Practices
|
||||
|
||||
1. Always use contextual errors for user-facing messages
|
||||
2. Provide remediation hints where possible
|
||||
3. Log errors with appropriate context
|
||||
4. Use error categories for systematic handling
|
||||
1. Provide remediation hints where possible
|
||||
1. Log errors with appropriate context
|
||||
1. Use error categories for systematic handling
|
||||
|
||||
### Context Usage
|
||||
|
||||
1. Always use context for operations that can timeout
|
||||
2. Propagate context through the call chain
|
||||
3. Add relevant context values for logging
|
||||
4. Use context cancellation for cleanup
|
||||
1. Propagate context through the call chain
|
||||
1. Add relevant context values for logging
|
||||
1. Use context cancellation for cleanup
|
||||
|
||||
### Testing
|
||||
|
||||
1. Use the fluent testing framework for command tests
|
||||
2. Always use mock environments for integration tests
|
||||
3. Test both success and failure scenarios
|
||||
4. Include timeout testing for long-running operations
|
||||
1. Always use mock environments for integration tests
|
||||
1. Test both success and failure scenarios
|
||||
1. Include timeout testing for long-running operations
|
||||
|
||||
### Performance
|
||||
|
||||
1. Use the metrics system to monitor performance
|
||||
2. Implement proper caching where appropriate
|
||||
3. Use object pooling for frequently allocated objects
|
||||
4. Profile and optimize hot paths
|
||||
1. Implement proper caching where appropriate
|
||||
1. Use object pooling for frequently allocated objects
|
||||
1. Profile and optimize hot paths
|
||||
|
||||
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.
|
||||
|
||||
@@ -35,17 +35,21 @@ validation caching, and parallel processing capabilities for enterprise-grade re
|
||||
### fail2ban/ Package
|
||||
|
||||
- **Purpose**: Core business logic and system interaction
|
||||
|
||||
- **Key Interfaces**:
|
||||
|
||||
- `Client`: Main interface for fail2ban operations with context support
|
||||
- `Runner`: Command execution interface
|
||||
- `SudoChecker`: Privilege validation interface
|
||||
|
||||
- **Implementations**:
|
||||
|
||||
- `RealClient`: Production fail2ban client with timeout handling
|
||||
- `MockClient`: Comprehensive test double with thread-safe operations
|
||||
- `NoOpClient`: Safe fallback implementation
|
||||
|
||||
- **Advanced Features**:
|
||||
|
||||
- Context-aware operations with timeout and cancellation support
|
||||
- Validation caching system with thread-safe operations
|
||||
- Optimized ban record parsing with object pooling
|
||||
@@ -105,14 +109,14 @@ validation caching, and parallel processing capabilities for enterprise-grade re
|
||||
### Command Execution Flow
|
||||
|
||||
1. **CLI Parsing**: Cobra processes command-line arguments
|
||||
2. **Context Creation**: Create context with timeout for operation
|
||||
3. **Validation**: Input validation with caching and sanitization
|
||||
4. **Privilege Check**: Determine if sudo is required
|
||||
5. **Metrics Start**: Begin performance metrics collection
|
||||
6. **Business Logic**: Execute fail2ban operations via Client interface with context
|
||||
7. **Parallel Processing**: Use parallel workers for multi-jail operations
|
||||
8. **Metrics End**: Record operation timing and success/failure
|
||||
9. **Output**: Format and display results (plain or JSON)
|
||||
1. **Context Creation**: Create context with timeout for operation
|
||||
1. **Validation**: Input validation with caching and sanitization
|
||||
1. **Privilege Check**: Determine if sudo is required
|
||||
1. **Metrics Start**: Begin performance metrics collection
|
||||
1. **Business Logic**: Execute fail2ban operations via Client interface with context
|
||||
1. **Parallel Processing**: Use parallel workers for multi-jail operations
|
||||
1. **Metrics End**: Record operation timing and success/failure
|
||||
1. **Output**: Format and display results (plain or JSON)
|
||||
|
||||
### Dependency Flow
|
||||
|
||||
@@ -170,25 +174,25 @@ fail2ban/client.go
|
||||
### Adding New Commands
|
||||
|
||||
1. Create new file in `cmd/` package
|
||||
2. Implement command using established patterns with context support
|
||||
3. Use dependency injection for testability
|
||||
4. Add performance metrics collection
|
||||
5. Implement fluent testing framework patterns
|
||||
6. Add comprehensive tests with mocks and context-aware operations
|
||||
1. Implement command using established patterns with context support
|
||||
1. Use dependency injection for testability
|
||||
1. Add performance metrics collection
|
||||
1. Implement fluent testing framework patterns
|
||||
1. Add comprehensive tests with mocks and context-aware operations
|
||||
|
||||
### Adding New Backends
|
||||
|
||||
1. Implement the `Client` interface
|
||||
2. Add any new required interfaces (Runner, etc.)
|
||||
3. Update main.go to support new backend
|
||||
4. Add configuration options
|
||||
1. Add any new required interfaces (Runner, etc.)
|
||||
1. Update main.go to support new backend
|
||||
1. Add configuration options
|
||||
|
||||
### Adding New Output Formats
|
||||
|
||||
1. Extend output formatting helpers
|
||||
2. Update command implementations
|
||||
3. Add format validation
|
||||
4. Test with existing commands
|
||||
1. Update command implementations
|
||||
1. Add format validation
|
||||
1. Test with existing commands
|
||||
|
||||
## 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
|
||||
privilege management, shell completion, and comprehensive security features.
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## Installation & Setup
|
||||
|
||||
@@ -34,7 +34,7 @@ Or install globally:
|
||||
go install github.com/ivuorinen/f2b@latest
|
||||
```
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -171,7 +171,7 @@ f2b --command-timeout=45s ban 192.168.1.100
|
||||
f2b --parallel-timeout=120s banned all
|
||||
```
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## 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:
|
||||
|
||||
1. **Check your privileges:** Run `f2b --log-level=debug version` to see your privilege status
|
||||
2. **Add sudo:** Try `sudo f2b [command]`
|
||||
3. **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. **Add sudo:** Try `sudo f2b [command]`
|
||||
1. **Join sudo group:** Ask your admin to add you to the sudo group
|
||||
1. **Test sudo access:** Run `sudo -n true` to check if you can use sudo
|
||||
|
||||
### The CLI says "permission denied" or "operation not permitted"
|
||||
|
||||
@@ -265,7 +265,7 @@ ls -la /etc/fail2ban/
|
||||
sudo fail2ban-client ping
|
||||
```
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## Development
|
||||
|
||||
@@ -279,11 +279,11 @@ go test ./...
|
||||
|
||||
See the `CONTRIBUTING.md` and the Contributing section in the README.
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
## Still need help?
|
||||
|
||||
- Open an issue on GitHub: https://github.com/ivuorinen/f2b/issues
|
||||
- Contact the maintainer: ismo@ivuorinen.net
|
||||
|
||||
---
|
||||
______________________________________________________________________
|
||||
|
||||
@@ -225,11 +225,11 @@ Both workflows now use unified pre-commit:
|
||||
### Before Committing
|
||||
|
||||
1. **Read configuration files first**: `.editorconfig`, `.golangci.yml`,
|
||||
`.markdownlint.json`, `.yamlfmt.yaml`, `.pre-commit-config.yaml`
|
||||
2. **Apply configuration rules** during development
|
||||
3. **Run pre-commit checks**: `pre-commit run --all-files`
|
||||
4. **Fix all issues** across the project
|
||||
5. **Run tests**: `go test ./...`
|
||||
`.markdownlint.json`, `.yamlfmt.yaml`, `.pre-commit-config.yaml`
|
||||
1. **Apply configuration rules** during development
|
||||
1. **Run pre-commit checks**: `pre-commit run --all-files`
|
||||
1. **Fix all issues** across the project
|
||||
1. **Run tests**: `go test ./...`
|
||||
|
||||
### Recommended IDE Setup
|
||||
|
||||
@@ -303,19 +303,19 @@ All YAML files include schema references for better IDE support:
|
||||
### Debugging Tips
|
||||
|
||||
1. **Run individual hooks** to isolate issues
|
||||
2. **Use `--verbose` flag** with pre-commit
|
||||
3. **Check configuration files** for rule customizations
|
||||
4. **Verify tool versions** match CI environment
|
||||
1. **Use `--verbose` flag** with pre-commit
|
||||
1. **Check configuration files** for rule customizations
|
||||
1. **Verify tool versions** match CI environment
|
||||
|
||||
## Adding New Linting Rules
|
||||
|
||||
### Process
|
||||
|
||||
1. Update configuration files (`.markdownlint.json`, `.yamlfmt.yaml`, etc.)
|
||||
2. Test changes locally: `pre-commit run --all-files`
|
||||
3. Update `.pre-commit-config.yaml` if adding new hooks
|
||||
4. Document changes in this file
|
||||
5. Consider backward compatibility
|
||||
1. Test changes locally: `pre-commit run --all-files`
|
||||
1. Update `.pre-commit-config.yaml` if adding new hooks
|
||||
1. Document changes in this file
|
||||
1. Consider backward compatibility
|
||||
|
||||
### Best Practices
|
||||
|
||||
|
||||
@@ -57,13 +57,13 @@ f2b intelligently manages sudo requirements through a comprehensive privilege ch
|
||||
### Privilege Escalation Process
|
||||
|
||||
1. **Pre-flight Check**: Determine user capabilities before command execution
|
||||
2. **Context Creation**: Create context with timeout for the operation
|
||||
3. **Command Classification**: Identify if the operation requires privileges
|
||||
4. **Smart Escalation**: Only add sudo when necessary for specific commands
|
||||
5. **Validation**: Ensure privilege escalation succeeded with timeout protection
|
||||
6. **Execution**: Run command with appropriate privileges and context
|
||||
7. **Timeout Handling**: Gracefully handle hanging operations with cancellation
|
||||
8. **Audit**: Log privileged operations with context information
|
||||
1. **Context Creation**: Create context with timeout for the operation
|
||||
1. **Command Classification**: Identify if the operation requires privileges
|
||||
1. **Smart Escalation**: Only add sudo when necessary for specific commands
|
||||
1. **Validation**: Ensure privilege escalation succeeded with timeout protection
|
||||
1. **Execution**: Run command with appropriate privileges and context
|
||||
1. **Timeout Handling**: Gracefully handle hanging operations with cancellation
|
||||
1. **Audit**: Log privileged operations with context information
|
||||
|
||||
### Error Handling
|
||||
|
||||
@@ -358,10 +358,10 @@ func setupSecureTestEnvironment(t *testing.T) {
|
||||
- **Issue**: Insufficient path validation against sophisticated attacks
|
||||
- **Impact**: Access to files outside intended directories
|
||||
- **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)
|
||||
- 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)
|
||||
- Null byte injection attacks
|
||||
|
||||
@@ -382,15 +382,15 @@ func setupSecureTestEnvironment(t *testing.T) {
|
||||
### Defense in Depth
|
||||
|
||||
1. **Input Validation**: First line of defense against malicious input with caching
|
||||
2. **Advanced Path Traversal Protection**: Extensive sophisticated attack vector protection
|
||||
3. **Privilege Validation**: Ensure user has necessary permissions with timeout protection
|
||||
4. **Context-Aware Execution**: Use argument arrays with timeout and cancellation support
|
||||
5. **Safe Execution**: Never use shell strings, always use context-aware operations
|
||||
6. **Error Handling**: Fail safely without information leakage, include context information
|
||||
7. **Audit Logging**: Track privileged operations with contextual information
|
||||
8. **Test Isolation**: Prevent test-time security compromises with comprehensive mocks
|
||||
9. **Performance Security**: Validation caching prevents DoS through repeated validation
|
||||
10. **Timeout Protection**: Prevent resource exhaustion through hanging operations
|
||||
1. **Advanced Path Traversal Protection**: Extensive sophisticated attack vector protection
|
||||
1. **Privilege Validation**: Ensure user has necessary permissions with timeout protection
|
||||
1. **Context-Aware Execution**: Use argument arrays with timeout and cancellation support
|
||||
1. **Safe Execution**: Never use shell strings, always use context-aware operations
|
||||
1. **Error Handling**: Fail safely without information leakage, include context information
|
||||
1. **Audit Logging**: Track privileged operations with contextual information
|
||||
1. **Test Isolation**: Prevent test-time security compromises with comprehensive mocks
|
||||
1. **Performance Security**: Validation caching prevents DoS through repeated validation
|
||||
1. **Timeout Protection**: Prevent resource exhaustion through hanging operations
|
||||
|
||||
### Security Boundaries
|
||||
|
||||
@@ -403,13 +403,13 @@ User Input → Context → Validation → Path Traversal → Privilege Check →
|
||||
**Enhanced Security Flow:**
|
||||
|
||||
1. **Context Creation**: Establish timeout and cancellation context
|
||||
2. **Input Sanitization**: Clean and validate all user input
|
||||
3. **Cache Validation**: Check validation cache for performance and DoS protection
|
||||
4. **Path Traversal Protection**: Block extensive sophisticated attack vectors
|
||||
5. **Privilege Verification**: Confirm user permissions with timeout protection
|
||||
6. **Context-Aware Execution**: Execute with timeout and cancellation support
|
||||
7. **Timeout Handling**: Gracefully handle hanging operations
|
||||
8. **Comprehensive Auditing**: Log all operations with context information
|
||||
1. **Input Sanitization**: Clean and validate all user input
|
||||
1. **Cache Validation**: Check validation cache for performance and DoS protection
|
||||
1. **Path Traversal Protection**: Block extensive sophisticated attack vectors
|
||||
1. **Privilege Verification**: Confirm user permissions with timeout protection
|
||||
1. **Context-Aware Execution**: Execute with timeout and cancellation support
|
||||
1. **Timeout Handling**: Gracefully handle hanging operations
|
||||
1. **Comprehensive Auditing**: Log all operations with context information
|
||||
|
||||
## Incident Response
|
||||
|
||||
@@ -418,17 +418,17 @@ User Input → Context → Validation → Path Traversal → Privilege Check →
|
||||
**For security vulnerabilities:**
|
||||
|
||||
1. **Do not** open public GitHub issues
|
||||
2. Email: `ismo@ivuorinen.net` with subject "SECURITY: f2b vulnerability"
|
||||
3. Include: Description, impact assessment, reproduction steps
|
||||
4. Expect: Acknowledgment within 48 hours
|
||||
1. Email: `ismo@ivuorinen.net` with subject "SECURITY: f2b vulnerability"
|
||||
1. Include: Description, impact assessment, reproduction steps
|
||||
1. Expect: Acknowledgment within 48 hours
|
||||
|
||||
### Security Update Process
|
||||
|
||||
1. **Assessment**: Evaluate impact and affected versions
|
||||
2. **Development**: Create fix with security tests
|
||||
3. **Testing**: Comprehensive security testing
|
||||
4. **Release**: Coordinated disclosure with security advisory
|
||||
5. **Communication**: Notify users via GitHub security advisories
|
||||
1. **Development**: Create fix with security tests
|
||||
1. **Testing**: Comprehensive security testing
|
||||
1. **Release**: Coordinated disclosure with security advisory
|
||||
1. **Communication**: Notify users via GitHub security advisories
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
|
||||
@@ -604,11 +604,11 @@ go tool cover -func=coverage.out | grep total
|
||||
### Avoid These Mistakes
|
||||
|
||||
1. **Real sudo execution in tests** - Always use MockSudoChecker
|
||||
2. **Hardcoded file paths** - Use temporary files or mocks
|
||||
3. **Network dependencies** - Mock all external calls
|
||||
4. **Race conditions** - Use proper synchronization in concurrent tests
|
||||
5. **Leaked goroutines** - Clean up background processes
|
||||
6. **Platform dependencies** - Write portable tests
|
||||
1. **Hardcoded file paths** - Use temporary files or mocks
|
||||
1. **Network dependencies** - Mock all external calls
|
||||
1. **Race conditions** - Use proper synchronization in concurrent tests
|
||||
1. **Leaked goroutines** - Clean up background processes
|
||||
1. **Platform dependencies** - Write portable tests
|
||||
|
||||
### 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 {
|
||||
return nil, err
|
||||
}
|
||||
// #nosec G204 -- command validated by validateCommandExecution
|
||||
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 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
|
||||
@@ -104,7 +105,7 @@ func (r *OSRunner) CombinedOutputWithSudoContext(ctx context.Context, name strin
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
7
main.go
7
main.go
@@ -34,7 +34,12 @@ func main() {
|
||||
// Check if this is a sudo privilege error
|
||||
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, "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)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -179,7 +180,7 @@ func BenchmarkGlobalStateAccess(b *testing.B) {
|
||||
fail2ban.GetLogDir()
|
||||
} else {
|
||||
// 50% writes
|
||||
fail2ban.SetLogDir("/tmp/test-" + string(rune(b.N)))
|
||||
fail2ban.SetLogDir("/tmp/test-" + strconv.Itoa(b.N))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -4,7 +4,9 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/ivuorinen/f2b/fail2ban"
|
||||
@@ -378,24 +380,28 @@ func TestSecurityAudit_ConcurrentSafety(t *testing.T) {
|
||||
|
||||
// Multiple goroutines modifying global state should not cause races
|
||||
// This is tested by running with -race flag in CI
|
||||
for i := 0; i < 10; i++ {
|
||||
go func(id int) {
|
||||
fail2ban.SetLogDir("/tmp/test-" + string(rune(id)))
|
||||
var wg sync.WaitGroup
|
||||
for i := range 10 {
|
||||
wg.Go(func() {
|
||||
fail2ban.SetLogDir("/tmp/test-" + strconv.Itoa(i))
|
||||
fail2ban.GetLogDir()
|
||||
}(i)
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
})
|
||||
|
||||
t.Run("CacheStatisticsSafety", func(_ *testing.T) {
|
||||
processor := fail2ban.NewOptimizedLogProcessor()
|
||||
|
||||
// Multiple goroutines accessing cache statistics should be safe
|
||||
for i := 0; i < 10; i++ {
|
||||
go func() {
|
||||
var wg sync.WaitGroup
|
||||
for range 10 {
|
||||
wg.Go(func() {
|
||||
processor.GetCacheStats()
|
||||
processor.ClearCaches()
|
||||
}()
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -499,4 +499,10 @@ const (
|
||||
|
||||
// MetricsFmtAverageLatencyTop is the format for average latency (top-level)
|
||||
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