Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 0 additions & 19 deletions .markdownlint.json

This file was deleted.

24 changes: 24 additions & 0 deletions .markdownlint.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// markdownlint config for the pre-commit hook (scripts/pre-commit-hooks/markdownlint-staged.sh),
// `make lint-markdown`, and `npm run lint:md`.
{
"default": true,
// TODO: the rules set to false below fire on pre-existing prose and are off so a commit touching an
// older doc does not fail on lines it did not write. Re-enable each one (delete its entry, which
// restores the default) once the repo-wide markdown cleanup lands. MD013 and MD040 were the loudest.
"MD001": false, // heading increment (pre-existing hit in CONTRIBUTING.md)
"MD013": false, // line length (was: line_length 120, heading_line_length 120, code_block_line_length 150, tables false)
"MD025": false, // multiple H1s (front-matter title + "# Title" in docs-site pages)
"MD036": false, // emphasis used as a heading
"MD040": false, // fenced code language
"MD060": false, // table column style
"MD024": {
"siblings_only": true
},
"MD033": {
"allowed_elements": ["details", "summary", "br", "sup", "sub", "kbd", "img"]
},
"MD041": false,
"MD046": {
"style": "fenced"
}
}
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ The CI-pinned version (currently v2.14.0, see `.github/workflows/quality-checks.

**Note:** Lefthook pre-commit-phase hooks will **BLOCK commits** if golangci-lint finds issues. This is intentional - fix the issues before committing.

Staged `.md` files are also checked by markdownlint on commit (config in `.markdownlint.jsonc`); run `make lint-markdown` to check every tracked markdown file.

### CI/CD Go Version Management

GitHub Actions workflows automatically use go 1.26.0 via `GOTOOLCHAIN: auto`, which allows the `setup-go` action to download and use the correct Go version even if the CI environment has an older version installed. This ensures consistent builds across all workflows.
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help plugin-powerdns plugin-powerdns-smoke install test build run clean docker-build docker-run build-offline release go-check gopls-logs lint-backend lint-agent lint-fast lint-staticcheck-only security-local
.PHONY: help plugin-powerdns plugin-powerdns-smoke install test build run clean docker-build docker-run build-offline release go-check gopls-logs lint-backend lint-agent lint-fast lint-staticcheck-only lint-markdown security-local

# Default target
help:
Expand Down Expand Up @@ -213,6 +213,10 @@ lint-staticcheck-only:
cd backend && golangci-lint run --config ../.golangci-fast.yml --enable-only staticcheck ./...
cd agent && golangci-lint run --config ../.golangci-fast.yml --enable-only staticcheck ./...

lint-markdown:
@echo "Running markdownlint on all tracked markdown files..."
scripts/pre-commit-hooks/markdownlint-staged.sh

lint-docker:
@echo "Running Hadolint..."
docker run --rm -i hadolint/hadolint < Dockerfile
Expand Down
56 changes: 44 additions & 12 deletions backend/internal/api/handlers/crowdsec_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ type CrowdsecHandler struct {
// signalProcess delivers a signal to a PID; overridable in tests.
signalProcess func(pid int, sig syscall.Signal) error

// mergeNotifications and scanPlaceholders are the import's notification steps; overridable in tests.
mergeNotifications func(snapshotDir, dataDir string) error
scanPlaceholders func(dataDir string) ([]string, error)

// dataMu serializes every operation that mutates DataDir (preset apply, config import, file write)
// and the export build; an export holds it only while writing its temporary file, never while sending.
// Lock order is always dataMu first, then HubService.mu.
Expand Down Expand Up @@ -352,6 +356,9 @@ const (
// nested installation reads.
const msgImportFlatArchive = "the archive keeps its configuration at the top level, but this CrowdSec installation reads it from the config folder; export a configuration from this page, or put the files in a config/ folder inside the archive"

// msgKeepCurrentFiles is the fixed message for an import that could not keep the current files.
const msgKeepCurrentFiles = "failed to keep the current CrowdSec files"

// errConfigFileNotFound is the fixed message for an import that contains no config.yaml in a
// location the engine reads (top level or config/).
var errConfigFileNotFound = errors.New("config.yaml was not found at the top level or in config/")
Expand Down Expand Up @@ -440,17 +447,19 @@ func NewCrowdsecHandler(db *gorm.DB, executor CrowdsecExecutor, binPath, dataDir
consoleSvc = crowdsec.NewConsoleEnrollmentService(db, &crowdsec.SecureCommandExecutor{}, dataDir, consoleSecret)
}
h := &CrowdsecHandler{
DB: db,
Executor: executor,
CmdExec: &RealCommandExecutor{},
BinPath: binPath,
DataDir: dataDir,
Hub: hubSvc,
Console: consoleSvc,
Security: securitySvc,
dashCache: newDashboardCache(),
validateLAPIURL: validateCrowdsecLAPIBaseURLDefault,
signalProcess: signalOSProcess,
DB: db,
Executor: executor,
CmdExec: &RealCommandExecutor{},
BinPath: binPath,
DataDir: dataDir,
Hub: hubSvc,
Console: consoleSvc,
Security: securitySvc,
dashCache: newDashboardCache(),
validateLAPIURL: validateCrowdsecLAPIBaseURLDefault,
signalProcess: signalOSProcess,
mergeNotifications: crowdsec.MergeRedactedNotifications,
scanPlaceholders: crowdsec.ScanPlaceholders,
}
hubSvc.Reload = h.reloadCrowdSec
if db != nil {
Expand Down Expand Up @@ -817,13 +826,22 @@ func (h *CrowdsecHandler) ImportConfig(c *gin.Context) {
}
}

// Fill the notification values the exported file blanked from the files being replaced, wherever the
// notification still points at the same target.
if mergeErr := h.mergeNotifications(backupDir, h.DataDir); mergeErr != nil {
logger.Log().WithField("error", sanitizeForLog(mergeErr.Error())).Warn("crowdsec import: keeping the current notification values failed")
rollback()
c.JSON(http.StatusInternalServerError, gin.H{"error": msgKeepCurrentFiles})
return
}

// The import cleared every file the archive did not replace: put back the ones CrowdSec cannot start
// without, and make sure a kept profile still resolves its notifications.
keptFiles, restoreErr := crowdsec.RestoreMissingCompanions(backupDir, h.DataDir, liveConfigPrefix(liveLayout))
if restoreErr != nil {
logger.Log().WithField("error", sanitizeForLog(restoreErr.Error())).Warn("crowdsec import: restoring the current files failed")
rollback()
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to keep the current CrowdSec files"})
c.JSON(http.StatusInternalServerError, gin.H{"error": msgKeepCurrentFiles})
return
}
if verifyErr := crowdsec.VerifyKeptProfile(h.DataDir, keptFiles); verifyErr != nil {
Expand All @@ -848,9 +866,23 @@ func (h *CrowdsecHandler) ImportConfig(c *gin.Context) {
if len(keptFiles) > 0 {
resp["kept_files"] = keptFiles
}
if needs := h.placeholderReport(); len(needs) > 0 {
resp["needs_values"] = needs
}
c.JSON(http.StatusOK, resp)
}

// placeholderReport lists the notification files of the imported tree that still hold blanked values.
// The report is informational: when it cannot be made the import still stands and the list is omitted.
func (h *CrowdsecHandler) placeholderReport() []string {
names, err := h.scanPlaceholders(h.DataDir)
if err != nil {
logger.Log().WithField("reported_files", len(names)).Warn("crowdsec import: could not list the notification files that still need values")
return nil
}
return names
}

// liveConfigPrefix is the folder below DataDir that holds the configuration CrowdSec reads.
func liveConfigPrefix(l crowdsec.Layout) string {
if l == crowdsec.LayoutNested {
Expand Down
Loading
Loading