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
20 changes: 10 additions & 10 deletions .claude/skills/linting-code/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ description: >

## Tools and where configuration lives

| Tool | Checks | Config |
| --- | --- | --- |
| ShellCheck | Shell syntax, quoting, portability, common bugs | `.pre-commit-config.yaml` (args: `--severity=warning --external-sources`) |
| MarkdownLint | Markdown formatting, list style, line length | `.markdownlint.yaml` |
| Tool | Checks | Config |
| ------------ | ----------------------------------------------- | ------------------------------------------------------------------------- |
| ShellCheck | Shell syntax, quoting, portability, common bugs | `.pre-commit-config.yaml` (args: `--severity=warning --external-sources`) |
| MarkdownLint | Markdown formatting, list style, line length | `.markdownlint.yaml` |

Both run through `pre-commit` so versions are pinned. Always use the Make targets or `pre-commit` directly — do not invoke `shellcheck` or `markdownlint` as standalone commands.

Expand Down Expand Up @@ -74,8 +74,8 @@ pre-commit run markdownlint --all-files
* Blank line above and below every heading (MD022)
* Ordered lists: use `1.` for every item, or true sequential numbers; never an arbitrary
starting number (MD029)
* Table separator rows: always `| --- | --- |`, **never** `|---|---|` — MD060 compact style
requires a space to the left and right of every `---` cell (MD060)
* Table column style: `"aligned"` (MD060) — all column widths must be padded uniformly so every
pipe is vertically aligned; the separator row dashes must span the full column width
* Specify a language on all fenced code blocks where possible (optional but preferred)

## Interpreting failures
Expand All @@ -88,10 +88,10 @@ Look up unknown codes at `https://www.shellcheck.net/wiki/SCXXX`.

Most common codes in this project:

| Code | Cause | Fix |
| --- | --- | --- |
| SC2086 | Unquoted variable | Wrap in `"$var"` |
| SC2155 | Combined `local`/assign | Split: `local x; x=$(...)` |
| Code | Cause | Fix |
| ------ | --------------------------------- | ------------------------------- |
| SC2086 | Unquoted variable | Wrap in `"$var"` |
| SC2155 | Combined `local`/assign | Split: `local x; x=$(...)` |
| SC2181 | Check `$?` instead of direct `if` | Use `if command; then` directly |

### MarkdownLint
Expand Down
16 changes: 8 additions & 8 deletions .claude/skills/pre-pr-checks/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ Resolve conflicts, then re-run the full test suite.

## Quick-reference: common pre-PR failures

| Symptom | Cause | Fix |
| --- | --- | --- |
| ShellCheck SC2086 | Unquoted variable | `"$var"` |
| ShellCheck SC2155 | Combined declare/assign | `local x; x=$(...)` |
| MarkdownLint MD004 | List marker is `-` | Change to `*` |
| Test not run | Call missing at bottom of suite | Add the call |
| Assertion not reached | Missing `\|\| return` on prior assertion | Add `\|\| return` |
| No release triggered | Commit type not release-triggering | Check `.releaserc.json` |
| Symptom | Cause | Fix |
| --------------------- | ---------------------------------------- | ----------------------- |
| ShellCheck SC2086 | Unquoted variable | `"$var"` |
| ShellCheck SC2155 | Combined declare/assign | `local x; x=$(...)` |
| MarkdownLint MD004 | List marker is `-` | Change to `*` |
| Test not run | Call missing at bottom of suite | Add the call |
| Assertion not reached | Missing `\|\| return` on prior assertion | Add `\|\| return` |
| No release triggered | Commit type not release-triggering | Check `.releaserc.json` |
54 changes: 45 additions & 9 deletions .claude/skills/running-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ This lists every runnable suite name. `test_example.sh` is a contributor templat

Default to targeted. Only run the full suite for broad changes or as a pre-PR gate.

| What changed | Run |
| --- | --- |
| A specific functional area (e.g. format handling, log levels) | The matching suite(s) only |
| `logging.sh` core logic (init, output routing, sanitization) | Full suite |
| `install.sh` | `test_install` only |
| Config file parsing | `test_config` and `test_config_security` |
| Security-related code | Relevant security suites + full suite |
| New test file added | New suite only, then full suite |
| Pre-PR / CI gate | Full suite |
| What changed | Run |
| ------------------------------------------------------------- | ---------------------------------------- |
| A specific functional area (e.g. format handling, log levels) | The matching suite(s) only |
| `logging.sh` core logic (init, output routing, sanitization) | Full suite |
| `install.sh` | `test_install` only |
| Config file parsing | `test_config` and `test_config_security` |
| Security-related code | Relevant security suites + full suite |
| New test file added | New suite only, then full suite |
| Pre-PR / CI gate | Full suite |

### Mapping changed code to suites

Expand Down Expand Up @@ -94,6 +94,42 @@ make test
make test-junit
```

### Stop at first failure (fail-fast)

Use this when a test run is failing and you want to isolate the broken suite quickly,
especially during `make sonar-analysis` debugging:

```bash
# Via Make
make test-fail-fast

# Or directly
./tests/run_tests.sh --fail-fast

# Short form
./tests/run_tests.sh -x
```

In sequential mode the runner stops immediately after the first failing suite.
In parallel mode it stops before any subsequent pipeline step.

### Debug a failing `make sonar-analysis`

kcov (used by `make coverage`) changes the execution environment — it sets `BASH_ENV`
and installs a `DEBUG` trap, which can cause tests to fail that pass normally. To isolate
the kcov-specific failure quickly, use `coverage-debug` which runs kcov in sequential
fail-fast mode:

```bash
make coverage-debug
```

Once the failing suite is identified, re-run it without kcov to confirm:

```bash
./tests/run_tests.sh <suite_name>
```

## Reading output

```
Expand Down
20 changes: 10 additions & 10 deletions .claude/skills/security-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,16 +204,16 @@ value, and `SCRIPT_NAME` at the end of `init_logger` regardless of source.

## Security test suite map

| Area | Test suite(s) |
| --- | --- |
| ANSI injection | `test_ansi_injection` |
| Log injection (newlines) | `test_unsafe_newlines` |
| Path traversal | `test_path_traversal` |
| TOCTOU / symlink attacks | `test_toctou_protection` |
| Config file injection | `test_config_security` |
| Environment variable attacks | `test_environment_security` |
| Sensitive data isolation | `test_sensitive_data` |
| Script name sanitization | `test_script_name_sanitization` |
| Area | Test suite(s) |
| ---------------------------- | ------------------------------- |
| ANSI injection | `test_ansi_injection` |
| Log injection (newlines) | `test_unsafe_newlines` |
| Path traversal | `test_path_traversal` |
| TOCTOU / symlink attacks | `test_toctou_protection` |
| Config file injection | `test_config_security` |
| Environment variable attacks | `test_environment_security` |
| Sensitive data isolation | `test_sensitive_data` |
| Script name sanitization | `test_script_name_sanitization` |

Run all security suites together:

Expand Down
42 changes: 21 additions & 21 deletions .claude/skills/writing-commits/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,33 @@ Commit history drives automated versioning via `semantic-release`. Incorrect for

## Type — required

| Type | Version bump | Use for |
| --- | --- | --- |
| `feat` | minor | New user-visible functionality |
| `fix` | patch | Bug fixes |
| `perf` | patch | Performance improvements |
| `revert` | patch | Reverting a prior commit |
| `refactor` | patch | Internal restructuring, no behaviour change |
| `docs` | none | Documentation-only changes |
| `style` | none | Whitespace/formatting, no logic change |
| `test` | none | Adding or updating tests |
| `chore` | none | Build, tooling, dependency changes |
| `ci` | none | GitHub Actions or CI config changes |
| Type | Version bump | Use for |
| ---------- | ------------ | ------------------------------------------- |
| `feat` | minor | New user-visible functionality |
| `fix` | patch | Bug fixes |
| `perf` | patch | Performance improvements |
| `revert` | patch | Reverting a prior commit |
| `refactor` | patch | Internal restructuring, no behaviour change |
| `docs` | none | Documentation-only changes |
| `style` | none | Whitespace/formatting, no logic change |
| `test` | none | Adding or updating tests |
| `chore` | none | Build, tooling, dependency changes |
| `ci` | none | GitHub Actions or CI config changes |

A `BREAKING CHANGE` footer triggers a **major** bump regardless of type.

## Scope — optional but strongly preferred

| Scope | Use for |
| --- | --- |
| `logging` | Core `logging.sh` functions |
| `config` | Configuration file handling |
| Scope | Use for |
| --------- | ----------------------------------------- |
| `logging` | Core `logging.sh` functions |
| `config` | Configuration file handling |
| `install` | `install.sh` and Makefile install targets |
| `tests` | Test files or test infrastructure |
| `docs` | Documentation files |
| `scripts` | Utility or demo scripts |
| `ci` | GitHub Actions workflows |
| `deps` | Dependency / Dependabot changes |
| `tests` | Test files or test infrastructure |
| `docs` | Documentation files |
| `scripts` | Utility or demo scripts |
| `ci` | GitHub Actions workflows |
| `deps` | Dependency / Dependabot changes |

## Subject — required

Expand Down
2 changes: 1 addition & 1 deletion .markdownlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@

# Table pipe style - require spaces around cell content
"MD060": {
"style": "spaced"
"style": "aligned"
}
}
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ All Markdown files must satisfy the rules in `.markdownlint.yaml`:
* **MD013** — line length: maximum 200 characters; code blocks and tables are exempt
* **MD022** — headings: one blank line above and below every heading
* **MD029** — ordered list style: use `1.` for every item, or true sequential numbers
* **MD060** — table separators: `| --- | --- |` with spaces, never `|---|---|`
* **MD060** — table column style: `"aligned"` — all column widths must be padded uniformly so
every pipe is vertically aligned; separator dashes must span the full column width

Rules explicitly disabled (permitted in this project): raw HTML (MD033), duplicate headings
across sections (MD024), emphasis as heading (MD036), language tag on fenced blocks (MD040),
Expand Down
14 changes: 8 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,14 @@ Please be respectful and professional in all interactions. Treat others with kin

The project supports additional code quality tools for local development:

| Command | Description | Requirements |
| --------------------- | ------------------------------- | --------------------------------------------- |
| `make test` | Run test suite | Bash 4.0+ |
| `make test-junit` | Run tests with JUnit XML output | Bash 4.0+ |
| `make coverage` | Run tests with code coverage | [kcov](https://github.com/SimonKagstrom/kcov) |
| `make sonar-analysis` | Full coverage + SonarQube scan | kcov, sonar-scanner, secret-tool |
| Command | Description | Requirements |
| --------------------- | --------------------------------------------- | --------------------------------------------- |
| `make test` | Run test suite | Bash 4.0+ |
| `make test-junit` | Run tests with JUnit XML output | Bash 4.0+ |
| `make test-fail-fast` | Run tests, stop at first failure | Bash 4.0+ |
| `make coverage` | Run tests with code coverage | [kcov](https://github.com/SimonKagstrom/kcov) |
| `make coverage-debug` | Run kcov coverage, stop at first failure | kcov |
| `make sonar-analysis` | Full coverage + SonarQube scan | kcov, sonar-scanner, secret-tool |

> **Note:** The `sonar` and `sonar-analysis` targets are configured for the maintainer's
> private SonarQube instance. See [Testing Documentation](docs/testing.md#code-coverage-and-static-analysis)
Expand Down
23 changes: 22 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ DOCS = README.md LICENSE CHANGELOG.md CONTRIBUTING.md CODE_OF_CONDUCT.md SECURIT
# Shell for execution
SHELL := /bin/bash

.PHONY: all help install install-user uninstall uninstall-user test test-quiet test-junit coverage sonar sonar-analysis lint lint-shell lint-markdown check demo demos clean pre-commit
.PHONY: all help install install-user uninstall uninstall-user test test-quiet test-junit test-fail-fast coverage coverage-debug sonar sonar-analysis lint lint-shell lint-markdown check demo demos clean pre-commit

all: help

Expand All @@ -34,7 +34,9 @@ help:
@echo "Development targets:"
@echo " make test Run test suite"
@echo " make test-junit Run tests with JUnit XML output"
@echo " make test-fail-fast Run tests, stop at first failure"
@echo " make coverage Run tests with kcov coverage"
@echo " make coverage-debug Run tests with kcov, stop at first failure"
@echo " make sonar Run SonarQube scanner (syncs version from logging.sh)"
@echo " make sonar-analysis Run coverage, JUnit tests, and SonarQube scan"
@echo " make demo Run all demo scripts"
Expand Down Expand Up @@ -133,6 +135,13 @@ test:
test-quiet:
@output=$$(./tests/run_tests.sh 2>&1) || { echo "$$output"; exit 1; }

test-fail-fast:
@echo "Running tests (fail-fast mode)..."
@if [ ! -x tests/run_tests.sh ]; then \
chmod +x tests/run_tests.sh || { echo "Error: Cannot make test runner executable"; exit 1; }; \
fi
@./tests/run_tests.sh --fail-fast

test-junit:
@echo "Running tests with JUnit XML output..."
@if [ ! -x tests/run_tests.sh ]; then \
Expand All @@ -154,6 +163,18 @@ coverage:
@echo ""
@echo "✓ Coverage report generated in coverage-report/"

coverage-debug:
@if ! command -v kcov >/dev/null 2>&1; then \
echo "Error: kcov not found."; \
echo "Install with: sudo dnf install kcov (Fedora) or sudo apt install kcov (Debian/Ubuntu)"; \
exit 1; \
fi
@echo "Running tests with kcov coverage (fail-fast mode)..."
@if [ ! -x tests/run_tests.sh ]; then \
chmod +x tests/run_tests.sh || { echo "Error: Cannot make test runner executable"; exit 1; }; \
fi
@TEST_PARALLEL_JOBS=1 kcov --include-path=./logging.sh coverage-report ./tests/run_tests.sh --fail-fast

sonar:
@if ! command -v sonar-scanner >/dev/null 2>&1; then \
echo "Error: sonar-scanner not found."; \
Expand Down
Loading
Loading