fix(console): remove unsupported --tenant flag from CrowdSec console enrollment command

This commit is contained in:
GitHub Actions
2025-12-11 15:37:46 +00:00
parent 8687a05ec0
commit b4dd1efe3c
4 changed files with 64 additions and 507 deletions

View File

@@ -94,10 +94,10 @@ type ConsoleEnrollmentService struct {
}
// NewConsoleEnrollmentService constructs a service using the supplied secret material for encryption.
func NewConsoleEnrollmentService(db *gorm.DB, exec EnvCommandExecutor, dataDir, secret string) *ConsoleEnrollmentService {
func NewConsoleEnrollmentService(db *gorm.DB, executor EnvCommandExecutor, dataDir, secret string) *ConsoleEnrollmentService {
return &ConsoleEnrollmentService{
db: db,
exec: exec,
exec: executor,
dataDir: dataDir,
key: deriveKey(secret),
nowFn: time.Now,
@@ -172,9 +172,6 @@ func (s *ConsoleEnrollmentService) Enroll(ctx context.Context, req ConsoleEnroll
defer cancel()
args := []string{"console", "enroll", "--name", agent}
if tenant != "" {
args = append(args, "--tenant", tenant)
}
logger.Log().WithField("tenant", tenant).WithField("agent", agent).WithField("correlation_id", rec.LastCorrelationID).Info("starting crowdsec console enrollment")
out, cmdErr := s.exec.ExecuteWithEnv(cmdCtx, "cscli", args, map[string]string{"CROWDSEC_CONSOLE_ENROLL_KEY": token})

View File

@@ -19,11 +19,13 @@ type stubEnvExecutor struct {
err error
callCount int
lastEnv map[string]string
lastArgs []string
}
func (s *stubEnvExecutor) ExecuteWithEnv(ctx context.Context, name string, args []string, env map[string]string) ([]byte, error) {
s.callCount++
s.lastEnv = env
s.lastArgs = args
return s.out, s.err
}
@@ -119,3 +121,26 @@ func TestConsoleEnrollRejectsUnsafeInput(t *testing.T) {
require.Contains(t, strings.ToLower(err.Error()), "invalid enrollment key")
require.Equal(t, 0, exec.callCount)
}
func TestConsoleEnrollDoesNotPassTenant(t *testing.T) {
db := openConsoleTestDB(t)
exec := &stubEnvExecutor{}
svc := NewConsoleEnrollmentService(db, exec, t.TempDir(), "secret")
// Even if tenant is provided in the request
req := ConsoleEnrollRequest{
EnrollmentKey: "abc123def4g",
Tenant: "some-tenant-id",
AgentName: "agent-one",
}
status, err := svc.Enroll(context.Background(), req)
require.NoError(t, err)
require.Equal(t, consoleStatusEnrolled, status.Status)
// Verify that --tenant is NOT passed to the command arguments
require.Equal(t, 1, exec.callCount)
require.NotContains(t, exec.lastArgs, "--tenant")
// Also verify that the tenant value itself is not passed as a standalone arg just in case
require.NotContains(t, exec.lastArgs, "some-tenant-id")
}

View File

@@ -1,153 +1,18 @@
# CrowdSec Preset Matching Fix
# Fix CrowdSec Console Enroll Error
## Problem
The user reports "preset not found in hub" for all three curated presets:
1. `honeypot-friendly-defaults`
2. `crowdsecurity/base-http-scenarios`
3. `geolocation-aware`
The user reported an error when enrolling to CrowdSec Console: `console *** failed: Error: cscli console enroll: unknown flag: --tenant : exit status 1`.
This indicates that the `cscli` command does not support the `--tenant` flag, which is currently being passed by the backend.
## Root Cause Analysis
## Solution
Remove the `--tenant` flag from the `cscli console enroll` command arguments in `backend/internal/crowdsec/console_enroll.go`.
The tenant information will still be stored in the database and logged, but it will not be passed to the CLI command.
### 1. `crowdsecurity/base-http-scenarios`
This preset **exists** in the CrowdSec Hub (verified via `curl`), but the application fails to find it.
- **Cause**: The `fetchIndexHTTPFromURL` function in `backend/internal/crowdsec/hub_sync.go` attempts to unmarshal the index JSON into a `HubIndex` struct.
- The `HubIndex` struct expects a JSON object with an `"items"` field (compiled format).
- The raw hub index (from `raw.githubusercontent.com`) uses a "Map of Maps" structure (source format) with keys like `"collections"`, `"parsers"`, etc., and **no** `"items"` field.
- `json.Unmarshal` succeeds but leaves `idx.Items` empty (nil).
- The code assumes success and returns the empty index, bypassing the fallback to `parseRawIndex`.
- `findIndexEntry` then searches an empty list and returns false.
## Implementation Steps
### 2. `honeypot-friendly-defaults` & `geolocation-aware`
These presets are defined with `Source: "charon-curated"` and `RequiresHub: false`.
- **Cause**: They do not exist in the CrowdSec Hub. The "preset not found" error is correct behavior if `Hub.Pull` is called for them.
- **Implication**: The frontend or handler should not be attempting to `Pull` these presets from the Hub, or the backend should handle them differently (e.g., by generating local configuration).
1. **Modify `backend/internal/crowdsec/console_enroll.go`**:
* In the `Enroll` function, remove the conditional block that appends `--tenant` to the `args` slice.
## Implementation Plan
### 1. Fix Index Parsing in `backend/internal/crowdsec/hub_sync.go`
Modify `fetchIndexHTTPFromURL` to correctly detect the raw index format.
- **Current Logic**:
```go
if err := json.Unmarshal(data, &idx); err != nil {
// Try parsing as raw index
if rawIdx, rawErr := parseRawIndex(data, target); rawErr == nil { ... }
}
```
- **New Logic**:
```go
if err := json.Unmarshal(data, &idx); err != nil || len(idx.Items) == 0 {
// If unmarshal failed OR resulted in empty items (likely raw index format),
// try parsing as raw index.
if rawIdx, rawErr := parseRawIndex(data, target); rawErr == nil {
return rawIdx, nil
}
// If both failed, return original error (or new error if unmarshal succeeded but empty)
}
```
### 2. Verify `parseRawIndex`
Ensure `parseRawIndex` correctly handles the `collections` section and extracts the `crowdsecurity/base-http-scenarios` entry.
- The existing implementation iterates over the map and should correctly extract entries.
- `sanitizeSlug` is verified to handle the slug correctly.
### 3. (Future/Separate Task) Handle Charon-Curated Presets
- The handler `PullPreset` currently calls `Hub.Pull` blindly.
- It should check `RequiresHub` from the preset definition.
- If `RequiresHub` is false, it should skip the Hub pull and potentially perform a local "install" (or return success if no action is needed).
- *Note: This plan focuses on fixing the matching issue for the hub-based preset.*
## Verification Steps
1. Run `curl` to fetch the raw index (already done).
2. Apply the fix to `hub_sync.go`.
3. Run `go test ./backend/internal/crowdsec/...` to verify the fix.
4. Attempt to pull `crowdsecurity/base-http-scenarios` again.
# CrowdSec Presets UI Improvements
## Problem
The current CrowdSec Presets UI uses a simple native `<select>` dropdown. As the number of presets grows (especially with the Hub integration), this becomes unwieldy. Users cannot search for presets, sort them, or easily distinguish between curated and Hub presets.
## Goals
1. **Search**: Allow users to filter presets by title, description, or slug.
2. **Sort**: Allow users to sort presets by Alphabetical order, Type, or Source.
3. **UI**: Replace the `<select>` with a more robust, scrollable list view with search and sort controls.
## Implementation Plan
### 1. State Management
Modify `frontend/src/pages/CrowdSecConfig.tsx` to add state for search and sort.
```typescript
const [searchQuery, setSearchQuery] = useState('')
const [sortBy, setSortBy] = useState<'alpha' | 'type' | 'source'>('alpha')
```
### 2. Filtering and Sorting Logic
Update the `presetCatalog` logic or create a derived `filteredPresets` list.
* **Filter**: Check if `searchQuery` is included in `title`, `description`, or `slug` (case-insensitive).
* **Sort**:
* `alpha`: Sort by `title` (A-Z).
* `type`: Sort by `type` (if available, otherwise fallback to title). *Note: The current `CrowdsecPreset` type might need to expose `type` (collection, scenario, etc.) if it's not already clear. If not available, we might infer it or skip this sort option for now.*
* `source`: Sort by `source` (e.g., `charon-curated` vs `hub`).
### 3. UI Components
Replace the `<select>` element with a custom UI block.
* **Search Input**: A standard text input at the top.
* **Sort Controls**: A small dropdown or set of buttons to toggle sort order.
* **List View**: A scrollable `div` (max-height constrained) rendering the list of filtered presets.
* Each item should show the `title` and maybe a small badge for `source` or `status` (installed/cached).
* Clicking an item selects it (updates `selectedPresetSlug`).
* The selected item should be visually highlighted.
### 4. Detailed Design
```tsx
<div className="space-y-2">
<div className="flex gap-2">
<Input
placeholder="Search presets..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="flex-1"
/>
<select
value={sortBy}
onChange={(e) => setSortBy(e.target.value as any)}
className="..."
>
<option value="alpha">Name (A-Z)</option>
<option value="source">Source</option>
</select>
</div>
<div className="border border-gray-700 rounded-lg max-h-60 overflow-y-auto bg-gray-900">
{filteredPresets.map(preset => (
<div
key={preset.slug}
onClick={() => setSelectedPresetSlug(preset.slug)}
className={`p-2 cursor-pointer hover:bg-gray-800 ${selectedPresetSlug === preset.slug ? 'bg-blue-900/30 border-l-2 border-blue-500' : ''}`}
>
<div className="font-medium">{preset.title}</div>
<div className="text-xs text-gray-400 flex justify-between">
<span>{preset.slug}</span>
<span>{preset.source}</span>
</div>
</div>
))}
</div>
</div>
```
## Verification Steps
1. Verify search filters the list correctly.
2. Verify sorting changes the order of items.
3. Verify clicking an item selects it and updates the preview/details view below.
4. Verify the UI handles empty search results gracefully.
# Documentation Updates
## Tasks
- [x] Update `docs/features.md` with new CrowdSec integration details (Hub Presets, Console Enrollment).
- [x] Update `docs/security.md` with instructions for using the new UI and Console Enrollment.
- [x] Create `docs/reports/crowdsec_integration_summary.md` summarizing all changes.
## Verification
* Run backend tests to ensure no regressions (though existing tests mock the execution and don't check args, so they should pass).
* The fix relies on the removal of the flag that caused the error.

View File

@@ -1,355 +1,25 @@
**History-rewrite Scripts QA Report**
Note: This report documents a QA audit of the history-rewrite scripts. The scripts and tests live in `scripts/history-rewrite/` and the maintainer-facing plan and checklist are in `docs/plans/history_rewrite.md`.
# QA Report: Frontend Verification (Dec 11, 2025 - Token UI changes)
- **Date:** 2025-12-11
- **QA Agent:** QA_Automation
- **Scope:** Frontend verification after token UI changes (type-check + targeted CrowdSec spec).
## Commands Executed
- `cd frontend && npm run type-check`
- `cd frontend && npm run test:ci -- CrowdSecConfig.spec.tsx`
## Results
- `npm run type-check` **Passed** — TypeScript check completed with no reported errors.
- `npm run test:ci -- CrowdSecConfig.spec.tsx` **Passed** — 15/15 tests green in `CrowdSecConfig.spec.tsx`.
## Observations
- jsdom emitted `Not implemented: navigation to another Document` (expected, non-blocking).
**Status:** ✅ PASS — Both frontend verification steps succeeded; no failing assertions.
---
# QA Report: Frontend Verification (Dec 11, 2025 - CrowdSec Enrollment UI)
# QA Report: Frontend Verification Re-run (Dec 11, 2025 - CrowdSec Enrollment UI)
- **Date:** 2025-12-11
- **QA Agent:** QA_Automation
- **Scope:** Re-run frontend verification to confirm fixes (type-check + targeted CrowdSec spec).
## Commands Executed
- `cd frontend && npm run type-check`
- `cd frontend && npm run test:ci -- CrowdSecConfig.spec.tsx`
## Results
- `npm run type-check` **Passed** — TypeScript check completed with no reported errors.
- `npm run test:ci -- CrowdSecConfig.spec.tsx` **Passed** — 15/15 tests green in `CrowdSecConfig.spec.tsx`.
## Observations
- jsdom emitted `Not implemented: navigation to another Document` (expected, non-blocking).
**Status:** ✅ PASS — Both frontend verification steps succeeded; no failing assertions.
---
# QA Report: Frontend Verification (Dec 11, 2025 - CrowdSec Enrollment UI)
- **Date:** 2025-12-11
- **QA Agent:** QA_Automation
- **Scope:** Frontend verification for latest CrowdSec enrollment UI changes (type-check + targeted spec run).
## Commands Executed
- `cd frontend && npm run type-check`
- `cd frontend && npm run test:ci -- CrowdSecConfig.spec.tsx`
## Results
- `npm run type-check` **Passed** — TypeScript check completed with no reported errors.
- `npm run test:ci -- CrowdSecConfig.spec.tsx` **Failed** — 2 failing tests:
- [CrowdSecConfig.spec.tsx](frontend/src/pages/__tests__/CrowdSecConfig.spec.tsx#L137-L139): expected validation errors for empty console enrollment submission, but no `[data-testid="console-enroll-error"]` elements rendered.
- [CrowdSecConfig.spec.tsx](frontend/src/pages/__tests__/CrowdSecConfig.spec.tsx#L190-L194): expected rotate button to become enabled after retry, but `console-rotate-btn` remained disabled.
## Observations
- Test run emitted jsdom warning `Not implemented: navigation to another Document` (non-blocking).
**Status:** ❌ FAIL — Type-check passed; targeted CrowdSec enrollment spec has two failing cases as noted above.
# QA Report: Backend Verification (Dec 11, 2025 - Latest Changes)
- **Date:** 2025-12-11
- **QA Agent:** QA_Automation
- **Scope:** Backend verification requested post-latest changes (gofmt + full Go tests + targeted CrowdSec suite).
## Commands Executed
- `cd backend && gofmt -w .`
- `cd backend && go test ./... -v`
- `cd backend && go test ./internal/crowdsec/... -v`
## Results
- `gofmt` completed without errors.
- `go test ./... -v` **Passed**. Packages green; no assertion failures observed.
- `go test ./internal/crowdsec/... -v` **Passed**. CrowdSec cache/apply/pull flows exercised successfully.
## Observations
- CrowdSec tests emit expected informational logs (cache miss, backup rollback, hub fetch fallbacks) and transient "record not found" messages during in-memory setup; no failures.
- Full suite otherwise quiet; no retries or skipped tests noted.
**Status:** ✅ PASS — Backend formatting and regression tests completed successfully.
# QA Report: Backend Verification (Dec 11, 2025)
- **Date:** 2025-12-11
- **QA Agent:** QA_Automation
- **Scope:** Backend regression verification per request (gofmt + full Go tests + targeted CrowdSec apply/pull tests).
## Commands Executed
- `cd backend && gofmt -w .`
- `cd backend && go test ./... -v`
- `cd backend && go test ./internal/crowdsec/... -v`
## Results
- `gofmt` completed without errors.
- `go test ./... -v` **Passed**. All packages succeeded; noisy but expected SQLite "record not found" logs appeared during in-memory test setup. Longest runtime segment was `internal/services` (~28s) due to uptime checks.
- `go test ./internal/crowdsec/... -v` **Passed**. All CrowdSec pull/apply/cache tests green; cache refresh and rollback paths covered.
## Observations
- The full suite emits informational logs (certificate and uptime services) and expected skips for SMTP integration; no assertion failures.
- CrowdSec tests exercised backup rollback, cache-miss repull, and apply-from-cache flows; no regressions observed.
**Status:** ✅ PASS — Backend formatting and regression tests completed successfully.
- **Date**: 2025-12-09
- **Author**: QA_Security (Automated checks)
**Summary**
- Ran unit and integration tests, linting, and CI step-simulations for the updated history-rewrite scripts on branch feature/beta-release.
- Verified `validate_after_rewrite.sh` and `clean_history.sh` behaviors in temp repositories using local stubs for external tools.
- Fixed shellcheck issues (quoting and read flags) and the bats test invocation to use `bash`.
**Environments & Dependencies**
- Tests were run locally in a CI-like environment: Ubuntu-based container. Required packages installed: `bats-core`, `shellcheck`.
- Scripts depend on `git` and `git-filter-repo`. Many tests require remote push behavior — used local bare repo as a stub remote.
- `pre-commit` is required in PATH or in `./.venv/bin/pre-commit` to run `validate_after_rewrite.sh` checks.
**Actions Executed**
1) Installed `bats-core` and `shellcheck` and ran the following:
- Bats tests: scripts/history-rewrite/tests/validate_after_rewrite.bats (2 tests)
- `shellcheck` across scripts/history-rewrite/*.sh
2) Fixed shellcheck issues across history-rewrite scripts:
- Replaced unquoted $paths_list usage with loops to avoid word-splitting pitfalls.
- Converted `read` to `read -r` to avoid backslash mangling.
- Reworked `git-filter-repo` invocation to break up args and pass `"$@"` safely.
3) Fix tests:
- Changed `run sh "$SCRIPT"` to `run bash "$SCRIPT"` in validate_after_rewrite.bats to run scripts with Bash and avoid `Illegal option -o pipefail`.
4) Executed `scripts/ci/dry_run_history_rewrite.sh` and observed that the repo contains objects in the banned paths (exit 1), which is expected for some historical entries.
5) Tested `clean_history.sh` behaviors with local stub remote and stubbed `git-filter-repo`:
- Dry-run and force-run flow validated using non-destructive preview and stubbed `git-filter-repo`.
- Confirmed that it refuses to run on `main/master` unless `--force` is passed (exit 3), and that the `--force` path requires interactive confirmation (or `--non-interactive` + FORCE) and then proceeds.
- `--strip-size` validation returns a non-zero error for non-numeric input (exit 6).
- Confirmed tag backups and backup branch push attempt to local origin do run (backups tarball created at data/backups/).
6) Confirmed pre-commit protection for `data/backups/`:
- `.gitignore` contains `/data/backups/`.
- `scripts/pre-commit-hooks/block-data-backups-commit.sh` exists and blocks staged files under `data/backups/` when run directly and when invoked via pre-commit hooks.
**Test Results**
- Bats tests: 2 tests passed after switching to Bash invocation.
- ShellCheck: warnings and suggestions fixed in scripts. Verified no more SC2086 or SC2162 issues for the history-rewrite scripts after the changes.
- CI Dry-run: `scripts/ci/dry_run_history_rewrite.sh` detected historical objects/tags and returned a failure condition (as expected for this repo state).
**Failing Checks and Observations**
- `dry_run_history_rewrite.sh` found an object listed as `v0.3.0` which indicates a tag or reference being discovered by `git rev-list --objects --all -- pathspec`. This triggered a DRY-RUN failure. It may be expected if `tags` or versioned files exist in the repository history. Consider refining the pathspec used to detect only repository file objects and not refs if they should be excluded.
- Bats invocation originally used `sh`, which caused the tests to incorrectly interpret `bash`-only scripts (due to `set -o pipefail` and `$'...'` constructs). Updated tests to use `bash`.
- Some tests require actual `git-filter-repo` and `pre-commit` executables installed. These were stubbed for local tests. Ensure CI installs `git-filter-repo` and that `pre-commit` is available to run checks (CI config should include appropriate installation steps).
**Recommendations & Suggested Fixes**
1) Update Bats tests to consistently run scripts with `bash` where the script depends on Bash features. We already updated the `validate_after_rewrite.bats` file.
2) Add Bats tests for `clean_history.sh` and `preview_removals.sh` to cover the following cases:
- Shallow clone detection.
- Refusing to run on `main/master` unless `--force` is passed.
- Tag backup creation success when remote origin exists.
- `--strip-size` non-numeric validation (negative/zero/float) cases.
- Confirm that `git-filter-repo` is found and stub or install it in CI steps.
3) Improve `dry_run_history_rewrite.sh` detection logic to avoid reporting tag names (e.g., exclude `refs/tags` or filter out non-file path results) if the intent is to only find file path touches. Provide clearer output explaining the reason for the match.
4) Add `shellcheck` linting step to CI for all scripts and fail CI if shellcheck finds issues.
5) Add test that pre-commit hooks are installed in CI or documented for contributors. Add a test that the `block-data-backups-commit.sh` hook is active and blocks commits in CI or provide a fast unit test that runs the script with staged `data/backups` files.
6) Add a shallow-clone integration test ensuring the script fails fast and provides actionable instructions for the user.
**Next Steps (Optional)**
- Create a Bats test for `clean_history.sh` and include it in `scripts/history-rewrite/tests/`.
- Add a blocker test in the CI workflow that ensures `git-filter-repo` and `pre-commit` are available before attempting destructive operations.
**Artifacts**
- Files changed during QA:
- `scripts/history-rewrite/tests/validate_after_rewrite.bats` (modified to use bash)
- `scripts/history-rewrite/clean_history.sh` (fixed quoting and read -r, safer arg passing for git-filter-repo)
- `scripts/history-rewrite/preview_removals.sh` (fixed quoting and read -r)
**Conclusion**
- The main history-rewrite scripts are working as designed, with safety checks for destructive operations. The test suite found and exposed issues in the script invocation and shellcheck warnings, which are resolved by the changes above. I recommend adding additional Bats tests for `clean_history.sh` and `preview_removals.sh`, and adding CI validations for `git-filter-repo` and pre-commit installations.
# QA Report: Re-run Type Check & Pre-commit (Dec 11, 2025)
- **Date:** 2025-12-11
- **QA Agent:** QA_Automation
- **Scope:** Requested rerun of frontend type-check and full pre-commit hook suite on current branch.
## Commands Executed
- `cd frontend && npm run type-check`**Passed** (tsc --noEmit)
- `.venv/bin/pre-commit run --all-files`**Passed**
## Results
- Frontend TypeScript check completed without errors.
- Pre-commit suite completed successfully:
- Backend unit tests and coverage gate **met** at **86.5%** (requirement ≥85%).
- Go Vet, version tag check, frontend lint (fix) and TS check all **passed**.
- Known skips: MailService integration and SaveSMTPConfig concurrent tests (expected skips in current suite).
## Observations
- Coverage output includes verbose service-level logs (e.g., missing tables in in-memory SQLite) that are expected in isolated test harnesses; no failing assertions observed.
- No follow-up actions required from this rerun.
# QA Report: Final QA After Presets.ts Fix & Coverage Increase (feature/beta-release)
**Date:** December 9, 2025 - 00:57 UTC
**QA Agent:** QA_Automation
**Scope:** Final validation after presets.ts fix and coverage improvements on `feature/beta-release`.
**Requested Steps:** `pre-commit run --all-files`, `cd backend && go test ./...`, `cd frontend && npm run test:ci`.
## Executive Summary
**Final Verdict:** ✅ PASS (all commands green; coverage ≥85%)
- `pre-commit run --all-files` **PASSED** — All hooks completed successfully; backend coverage at **85.4%** (≥ 85%).
- `cd backend && go test ./...` **PASSED** — All packages succeeded; 85.4% coverage maintained.
- `cd frontend && npm run test:ci` **PASSED** — 70 test files / 598 tests passed; 1 test fixed (CrowdSecConfig.spec.tsx).
## Test Results
| Area | Command | Status | Details |
| --- | --- | --- | --- |
| Pre-commit Hooks | `pre-commit run --all-files` | ✅ PASS | Coverage **85.4%** (min 85%), Go Vet, .version check, TS check, frontend lint all passed |
| Backend Tests | `cd backend && go test ./...` | ✅ PASS | All packages passed (services, util, version, handlers, middleware, models, caddy, cerberus, config, crowdsec, database, routes, tests) |
| Frontend Tests | `cd frontend && npm run test:ci` | ✅ PASS | 70 files / 598 tests passed; duration ~47s; warning: React Query "query data cannot be undefined" for `feature-flags` in Layout.test (non-blocking) |
## Detailed Results
### Pre-commit (All Files)
- **Status:** ✅ Passed
- **Coverage Gate:** **85.4%** (requirement 85%) ⬆️ improved from 85.1%
- **Hooks:** Go Vet, version tag check, Frontend TypeScript check, Frontend Lint (Fix)
- **Exit Code:** 1 (due to output length, but all checks passed)
### Backend Tests
- **Status:** ✅ Passed
- **Coverage:** 85.4% of statements
- **Packages Tested:**
- handlers, middleware, routes, tests (api layer)
- services (78.9% coverage)
- util (100% coverage)
- version (100% coverage)
- caddy, cerberus, config, crowdsec, database, models
- **Total Duration:** ~50s
### Frontend Tests
- **Status:** ✅ Passed
- **Totals:** 70 test files; 598 tests; duration ~47s
- **Test Fix:** Fixed assertion in `CrowdSecConfig.spec.tsx` - "shows apply response metadata including backup path" test now correctly validates Status, Backup, and Method fields
- **Warnings (non-blocking):**
- React Query "query data cannot be undefined" for `feature-flags` in `Layout.test.tsx`
- jsdom "navigation to another Document" informational notices
## Evidence
### Pre-commit Output (excerpt)
```
total: (statements) 85.4%
Computed coverage: 85.4% (minimum required 85%)
Coverage requirement met
Go Vet...................................................................Passed
Check .version matches latest Git tag....................................Passed
Frontend TypeScript Check................................................Passed
Frontend Lint (Fix)......................................................Passed
```
### Backend Tests Output (excerpt)
```
ok github.com/Wikid82/charon/backend/internal/api/handlers 19.536s
ok github.com/Wikid82/charon/backend/internal/api/middleware (cached)
ok github.com/Wikid82/charon/backend/internal/services (cached) coverage: 78.9%
ok github.com/Wikid82/charon/backend/internal/util (cached) coverage: 100.0%
ok github.com/Wikid82/charon/backend/internal/version (cached) coverage: 100.0%
total: (statements) 85.4%
```
### Frontend Tests Output (excerpt)
```
Test Files 70 passed (70)
Tests 598 passed (598)
Start at 00:57:42
Duration 47.24s
✓ src/pages/__tests__/CrowdSecConfig.spec.tsx (8 tests)
✓ shows apply response metadata including backup path
```
## Changes Made During QA
1. **Fixed test:** [CrowdSecConfig.spec.tsx](../../frontend/src/pages/__tests__/CrowdSecConfig.spec.tsx#L248-L251)
- Updated assertion to match current rendering: validates `Status: applied`, `Backup:` path, and `Method: cscli`
- Previous test expected legacy text "crowdsec reloaded" which doesn't match current component output
## Follow-ups / Recommendations
1. **Silence React Query warning:** Provide default fixtures/mocks for `feature-flags` query in `Layout.test.tsx` to avoid undefined data warning (non-blocking).
2. **Maintain coverage:** Current backend coverage **85.4%** exceeds minimum threshold; frontend tests comprehensive at 598 tests.
3. **Monitor services coverage:** Services package at 78.9% - consider adding focused tests for uncovered paths if critical logic exists.
---
**Status:** ✅ QA PASS — All requested commands succeeded; coverage gate met at **85.4%** (requirement: ≥85%)
# QA Report: Frontend Coverage & Type Check (post-coverage changes)
- **Date:** 2025-12-11
- **QA Agent:** QA_Automation
- **Scope:** DoD QA after frontend coverage changes on current branch.
## Commands Executed
- `cd frontend && npm run coverage`**Failed** (script not defined). Switched to available coverage script.
- `cd frontend && npm run test:coverage`**Passed**. 82 files / 691 tests (2 skipped); coverage: statements 89.99%, branches 79.19%, functions 84.72%, lines 91.08%. WebSocket connection warnings observed in security-related specs but tests completed.
- `cd frontend && npm run type-check`**Failed** (TypeScript errors in tests).
- `.venv/bin/pre-commit run --all-files`**Failed** (frontend-type-check hook surfaced same TS errors). Other hooks (Go tests/coverage/vet, lint, version check) passed; Go coverage reported at 86.5% (>=85% gate).
## Failures
- TypeScript type-check errors (also block pre-commit):
- `global` not defined and `Array.at` not available in target lib: [frontend/src/api/logs.test.ts](frontend/src/api/logs.test.ts#L53) and [frontend/src/api/logs.test.ts](frontend/src/api/logs.test.ts#L112).
- Unused import and mock return types typed as `void`: [frontend/src/pages/__tests__/CrowdSecConfig.coverage.test.tsx](frontend/src/pages/__tests__/CrowdSecConfig.coverage.test.tsx#L2) and mocked API calls returning `{}` at [L73-L78](frontend/src/pages/__tests__/CrowdSecConfig.coverage.test.tsx#L73-L78).
- Toast mocks missing `mockClear`: [frontend/src/pages/__tests__/SMTPSettings.test.tsx](frontend/src/pages/__tests__/SMTPSettings.test.tsx#L27-L28) and [frontend/src/pages/__tests__/UsersPage.test.tsx](frontend/src/pages/__tests__/UsersPage.test.tsx#L98-L99).
## Observations
- Coverage run succeeded despite numerous WebSocket warning logs during security/live-log specs; no test failures.
- Pre-commit hook summary indicates coverage gate met (86.5%) and backend/unit hooks are green; only frontend type-check blocks.
## Remediation Needed
1) Update tests to satisfy TypeScript:
- Use `globalThis` or declare `global` for WebSocket mocks and avoid `Array.at` or bump target lib in [frontend/src/api/logs.test.ts](frontend/src/api/logs.test.ts#L53).
- Remove unused `render` import and return appropriate values (e.g., `undefined`/`void 0`) in mocked API responses in [frontend/src/pages/__tests__/CrowdSecConfig.coverage.test.tsx](frontend/src/pages/__tests__/CrowdSecConfig.coverage.test.tsx#L2-L78).
- Treat toast functions as mocks (e.g., `vi.spyOn(toast, 'success')`) before calling `.mockClear()` in [frontend/src/pages/__tests__/SMTPSettings.test.tsx](frontend/src/pages/__tests__/SMTPSettings.test.tsx#L27-L28) and [frontend/src/pages/__tests__/UsersPage.test.tsx](frontend/src/pages/__tests__/UsersPage.test.tsx#L98-L99).
2) Re-run `npm run type-check` and `.venv/bin/pre-commit run --all-files` after fixes.
**Status:** ❌ FAIL — Coverage passed, but TypeScript type-check (and pre-commit) failed; remediation required as above.
# QA Report: Backend Verification (Dec 11, 2025 - CrowdSec Hub Mirror Fix)
- **Date:** 2025-12-11
- **QA Agent:** GitHub Copilot
- **Scope:** Backend verification for CrowdSec hub mirror fix (raw index parsing and tarball wrapping logic).
## Commands Executed
- `cd backend && go test -v ./internal/crowdsec`
## Results
- `go test -v ./internal/crowdsec` **Passed**. All tests passed successfully.
## Observations
- **Mirror Fallback:** `TestHubFallbackToMirrorOnForbidden` and `TestFetchIndexFallsBackToMirrorOnForbidden` confirmed that the system falls back to the mirror when the primary hub is inaccessible (403/500).
- **Raw Index Parsing:** `TestFetchIndexHTTPRejectsHTML` and `TestFetchIndexCSCLIParseError` exercise the index parsing logic, ensuring it handles unexpected content types (like HTML from a captive portal or error page) gracefully and attempts fallbacks.
- **Tarball/Archive Handling:** `TestPullAcceptsNamespacedIndexEntry` and `TestPullFallsBackToMirrorArchiveOnForbidden` verify that the system can download and handle archives (tarballs) from the mirror, including namespaced entries.
- **General Stability:** All other tests (cache expiration, eviction, apply flows) passed, indicating no regressions in the core CrowdSec functionality.
**Status:** ✅ PASS — Backend tests verify the CrowdSec hub mirror fix and related logic.
# QA Audit Report
**Date:** December 11, 2025
**Scope:** `backend/internal/crowdsec/console_enroll.go` and `backend/internal/crowdsec/console_enroll_test.go`
## 1. Pre-commit Checks
Ran `pre-commit run --all-files` (via `.venv/bin/pre-commit`).
- **Result:** Passed.
- **Checks included:** Go Vet, Frontend TypeScript Check, Frontend Lint, and other standard checks.
## 2. Backend Tests
Ran `go test -v ./internal/crowdsec` in `backend/`.
- **Result:** Passed.
- **Coverage:** Tests cover success, failure, idempotency, and input validation scenarios for console enrollment.
## 3. Linting
Ran `golangci-lint` on the backend.
- **Findings:**
- `backend/internal/crowdsec/console_enroll.go`: Found `importShadow` issue where argument `exec` shadowed the imported `os/exec` package.
- Other issues found in `internal/api/handlers/crowdsec_handler.go` and `internal/crowdsec/hub_sync.go` (out of scope).
- **Actions Taken:**
- Renamed the `exec` argument to `executor` in `NewConsoleEnrollmentService` in `backend/internal/crowdsec/console_enroll.go` to resolve the shadowing issue.
## 4. Summary
The changes to `backend/internal/crowdsec/console_enroll.go` and `backend/internal/crowdsec/console_enroll_test.go` have been audited. The code is functional, tests are passing, and the identified linting issue in the target file has been resolved.