diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml
index 7300e15c..5dad76b2 100644
--- a/.github/workflows/security.yml
+++ b/.github/workflows/security.yml
@@ -68,7 +68,6 @@ jobs:
timeout-minutes: 20
permissions:
contents: read
- issues: write # notify-scheduled-failure
strategy:
fail-fast: false
matrix:
@@ -92,29 +91,52 @@ jobs:
run: |
set -euo pipefail
case "${IMAGE}" in
- kates) tag=$(awk '/repository: ghcr.io\/bmscomp\/kates$/ {getline; print $2}' "${REF}" | tr -d '"'); ref="ghcr.io/bmscomp/kates:${tag}" ;;
+ kates) tag=$(awk '/repository: ghcr.io\/bmscomp\/kates$/ {found=1; next} found && /^[[:space:]]*tag:/ {print $2; exit}' "${REF}" | tr -d '"'); ref="ghcr.io/bmscomp/kates:${tag}" ;;
connect) ref=$(grep -m1 '^image:' "${REF}" | awk '{print $2}' | tr -d '"') ;;
kates-tester) ref=$(grep -m1 'ghcr.io/bmscomp/kates-tester:' "${REF}" | sed -E 's/.*(ghcr.io\/bmscomp\/kates-tester:[^"]+).*/\1/') ;;
esac
- if [ -z "${ref}" ] || [[ "${ref}" != *:* ]]; then
- echo "::error::could not resolve the ${IMAGE} image from ${REF}"
+ tag_part="${ref##*:}"
+ if [ -z "${ref}" ] || [[ "${ref}" != *:* ]] || [ -z "${tag_part}" ] || [[ "${tag_part}" == -* ]]; then
+ echo "::error::could not resolve a valid ${IMAGE} image tag from ${REF} (got '${ref}')"
exit 1
fi
echo "ref=${ref}" | tee -a "$GITHUB_OUTPUT"
- - name: Scan (Trivy)
+ # Same policy as ci.yml and the publish-*.yml workflows: HIGH is reported
+ # in the log, CRITICAL fails the weekly rescan.
+ - name: Report HIGH and CRITICAL vulnerabilities (Trivy)
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: image
image-ref: ${{ steps.pin.outputs.ref }}
scanners: vuln
severity: CRITICAL,HIGH
+ exit-code: "0"
+ ignore-unfixed: true
+ trivyignores: .trivyignore.yaml
+
+ - name: Gate on CRITICAL vulnerabilities (Trivy)
+ uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
+ with:
+ scan-type: image
+ image-ref: ${{ steps.pin.outputs.ref }}
+ scanners: vuln
+ severity: CRITICAL
exit-code: "1"
ignore-unfixed: true
trivyignores: .trivyignore.yaml
- - name: Open an issue for a failed weekly scan
- if: failure() && github.event_name == 'schedule'
- uses: ./.github/actions/notify-scheduled-failure
+ notify-failure:
+ name: Open an issue for a failed weekly scan
+ needs: [rescan-released]
+ if: always() && needs.rescan-released.result == 'failure' && github.event_name == 'schedule'
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ contents: read
+ issues: write
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ - uses: ./.github/actions/notify-scheduled-failure
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/Makefile b/Makefile
index c2b0f156..cddbbd48 100644
--- a/Makefile
+++ b/Makefile
@@ -493,9 +493,11 @@ cli-install: ## Build and install CLI on this machine (CLI_INSTALL_DIR to choos
fi; \
fi
sudo cp cli/dist/kates $(CLI_INSTALL_PATH)
- sudo xattr -dr com.apple.provenance $(CLI_INSTALL_PATH) 2>/dev/null || true
- sudo xattr -dr com.apple.quarantine $(CLI_INSTALL_PATH) 2>/dev/null || true
- sudo codesign -f -s - $(CLI_INSTALL_PATH)
+ @if [ "$$(uname -s)" = "Darwin" ]; then \
+ sudo xattr -dr com.apple.provenance $(CLI_INSTALL_PATH) 2>/dev/null || true; \
+ sudo xattr -dr com.apple.quarantine $(CLI_INSTALL_PATH) 2>/dev/null || true; \
+ sudo codesign -f -s - $(CLI_INSTALL_PATH); \
+ fi
@echo "✅ Installed:"
@# Run the file just written, by absolute path. Asking `kates` would
@# report whatever PATH resolves to, which is exactly the thing this
diff --git a/README.md b/README.md
index e7042b44..d8aeabde 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@
+
@@ -31,7 +32,7 @@ Performance tests work against any Kafka cluster the Kates API can reach; fault
## What it does
- **Performance tests.** Eight workload types (`LOAD`, `STRESS`, `SPIKE`, `ENDURANCE`, `VOLUME`, `CAPACITY`, `ROUND_TRIP`, `INTEGRITY`); `kates test types` lists every type the Kates API accepts. The default `native` benchmark backend runs Kafka producers and consumers inside the Kates API on virtual threads; `--backend trogdor` hands the workload to a Trogdor coordinator you run yourself. Reports give throughput, latency percentiles (`P50`, `P95`, `P99`) and error rate, and export as CSV, JUnit XML, Markdown, HTML or latency heatmaps.
-- **Fault injection.** Thirteen disruption types, from broker pod kills and network partitions to CPU, memory and I/O stress, DNS errors, disk fill and node drain (`kates disruption types`). The default install runs eleven of them through LitmusChaos. Network latency and disk fill time out, because the `kates-chaos` chart ships no Litmus experiment for them (see `experiments.definitions` in its values). The direct Kubernetes chaos provider covers eight.
+- **Fault injection.** Thirteen disruption types, from broker pod kills and network partitions to CPU, memory and I/O stress, DNS errors, disk fill and node drain (`kates disruption types`), run through LitmusChaos (eleven out of the box) or directly through the Kubernetes API (eight); [Chaos in practice](docs/book/07-chaos-practice.md) covers provider support and adding custom Litmus experiments.
- **Resilience runs and disruption plans.** `kates resilience run` pairs one load test with one fault and reports the before/after change and the recovery time. `kates disruption run` executes multi-step disruption plans; `kates disruption playbook list` shows the built-in playbooks. Plans get blast-radius checks, a dry run, ISR and consumer-lag tracking, and an A–F SLA grade against absolute latency, throughput and recovery-time thresholds.
- **Security audit.** `kates security audit` grades broker configuration A–F. Related commands map the checks to CIS, SOC 2 and PCI DSS, save a baseline and report drift from it.
- **CI gates.** `kates gate --min-grade B` runs a load test and exits non-zero below the performance grade, `kates test apply -f