Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
baca55bd77 | ||
|
|
01176862d4
|
||
|
|
f7487b356a | ||
|
|
34ddd25ac9 | ||
|
|
4aeccb801e
|
No files matched your search
@@ -6,7 +6,7 @@ Latin: *munitor* (fortifier, protector) -- KofTwentyTwo's unified CircleCI orb f
|
||||
| --- | --- |
|
||||
| **Tier** | Internal until classified -- listed under *Awaiting classification* in the KofTwentyTwo standards [MAINTAINERS.md](https://github.com/KofTwentyTwo/standards/blob/main/MAINTAINERS.md); Product-tier requirements are being adopted |
|
||||
| **Standards** | Targets [KofTwentyTwo standards](https://github.com/KofTwentyTwo/standards) 1.0.0 |
|
||||
| **Orb** | [`kof22/munitor`](https://circleci.com/developer/orbs/orb/kof22/munitor), latest stable `0.3.6` |
|
||||
| **Orb** | [`kof22/munitor`](https://circleci.com/developer/orbs/orb/kof22/munitor), latest stable `0.3.7` |
|
||||
| **Security** | [SECURITY.md](SECURITY.md) |
|
||||
| **Contributing** | [CONTRIBUTING.md](CONTRIBUTING.md) |
|
||||
|
||||
@@ -70,16 +70,16 @@ Munitor validates branch names and will fail on non-conforming names.
|
||||
|
||||
Munitor is a public CircleCI orb: any CircleCI organization can use it without forking. This checklist covers what a new consumer needs, for example a Java/Maven web service. A QQQ application should also read the [QQQ adoption checklist](https://github.com/QRun-IO/qqq/blob/develop/docs/migration/adoption-checklist.adoc) (section 7 covers release tooling).
|
||||
|
||||
**Version.** Use `kof22/munitor@0.3.6` (or `@0.3` to float on the 0.3 line) in `.circleci/config.yml`, and the same value as `orb_version` in `.munitor.yml`. Keep the setup orb and the generated pipeline on the same line.
|
||||
**Version.** Use `kof22/munitor@0.3.7` (or `@0.3` to float on the 0.3 line) in `.circleci/config.yml`, and the same value as `orb_version` in `.munitor.yml`. Keep the setup orb and the generated pipeline on the same line.
|
||||
|
||||
### 1. Repository files
|
||||
|
||||
- `.circleci/config.yml`: the setup config from [Quick Start](#quick-start), pinned to `kof22/munitor@0.3.6`.
|
||||
- `.circleci/config.yml`: the setup config from [Quick Start](#quick-start), pinned to `kof22/munitor@0.3.7`.
|
||||
- `.munitor.yml`: pick a [pipeline type](#pipeline-types). A Java service is `java-webapp`. KofTwentyTwo's Website-Backend is a working example; a generalized version:
|
||||
|
||||
```yaml
|
||||
pipeline: java-webapp
|
||||
orb_version: "0.3.6"
|
||||
orb_version: "0.3.7"
|
||||
image_name: my-service
|
||||
java_version: "21"
|
||||
docker:
|
||||
|
||||
@@ -98,3 +98,6 @@ These fixes require normal feature-to-develop review and stable tag publication
|
||||
from main before website consumers can select the new version. Nothing deployed.
|
||||
|
||||
Runtime freshness validation: coordinating agent completed make all (lint, pack, orb validation, scripts,277template assertions) and all7BATS tests in Ubuntu. Real consumer image scan remains required after release.
|
||||
|
||||
## Release 0.3.7 preparation (2026-10-19)
|
||||
Includes merged PR38 (filesystem Trivy findings fail CI; current Semgrep image and zero-scan/configuration failures) and PR39 (pull fresh runtime bases and bypass cached JVM package-upgrade layers). Both feature PRs passed all CircleCI gates; PR39 also passed full local make all and seven BATS tests. Publish the stable orb only from a signed v0.3.7 tag on the reviewed main merge. Website-Backend must update both orb pins and pass real image/SAST scans before rollout. No vulnerability waiver or immutable-tag overwrite is part of this release.
|
||||
@@ -3,8 +3,8 @@ description: >
|
||||
parameters:
|
||||
version:
|
||||
type: string
|
||||
default: "1.61.1"
|
||||
default: "1.181.0"
|
||||
description: Semgrep image version tag.
|
||||
docker:
|
||||
- image: returntocorp/semgrep:<< parameters.version >>
|
||||
- image: semgrep/semgrep:<< parameters.version >>
|
||||
resource_class: medium
|
||||
+34
-11
@@ -15,22 +15,45 @@ munitor_header "run_semgrep"
|
||||
|
||||
CONFIG="${SEMGREP_CONFIG:-auto}"
|
||||
FAIL_ON_FINDINGS="${SEMGREP_FAIL_ON_FINDINGS:-true}"
|
||||
REPORT="${SEMGREP_REPORT:-/tmp/semgrep-results.json}"
|
||||
|
||||
echo "Running Semgrep SAST scan (config: ${CONFIG}, fail_on_findings: ${FAIL_ON_FINDINGS})..."
|
||||
|
||||
EXIT_CODE=0
|
||||
semgrep ci \
|
||||
--config "${CONFIG}" \
|
||||
--json \
|
||||
--output /tmp/semgrep-results.json || {
|
||||
EXIT_CODE=$?
|
||||
if [[ "${FAIL_ON_FINDINGS}" == "true" ]]; then
|
||||
echo "ERROR: Semgrep found issues."
|
||||
echo "Review the report at: /tmp/semgrep-results.json"
|
||||
exit "${EXIT_CODE}"
|
||||
else
|
||||
echo "WARNING: Semgrep found issues (warn-only mode, not failing build)."
|
||||
echo "Review the report at: /tmp/semgrep-results.json"
|
||||
fi
|
||||
}
|
||||
--output "${REPORT}" || EXIT_CODE=$?
|
||||
|
||||
# Summarise the report, and fail a scan that ran no rules or scanned no files:
|
||||
# semgrep exits 0 when the downloaded rules fail to parse (an outdated semgrep),
|
||||
# which used to pass this job without scanning anything.
|
||||
python3 - "${REPORT}" <<'PY'
|
||||
import json, sys
|
||||
report = json.load(open(sys.argv[1]))
|
||||
scanned = len(report.get("paths", {}).get("scanned", []))
|
||||
results = report.get("results", [])
|
||||
errors = report.get("errors", [])
|
||||
rule_errors = [e for e in errors if "rule" in str(e.get("type", "")).lower()
|
||||
or "config" in str(e.get("message", "")).lower()]
|
||||
print(f"Semgrep: {scanned} files scanned, {len(results)} findings, {len(errors)} errors.")
|
||||
for r in results[:50]:
|
||||
print(f" {r.get('check_id')} {r.get('path')}:{r.get('start', {}).get('line')}")
|
||||
if scanned == 0 or rule_errors:
|
||||
for e in rule_errors[:5]:
|
||||
print(f" error: {str(e.get('message', e))[:300]}")
|
||||
print("ERROR: Semgrep did not run its rules (no files scanned or invalid rule configuration).")
|
||||
sys.exit(2)
|
||||
PY
|
||||
|
||||
if [[ "${EXIT_CODE}" -ne 0 ]]; then
|
||||
if [[ "${FAIL_ON_FINDINGS}" == "true" ]]; then
|
||||
echo "ERROR: Semgrep found issues."
|
||||
echo "Review the report at: ${REPORT}"
|
||||
exit "${EXIT_CODE}"
|
||||
fi
|
||||
echo "WARNING: Semgrep found issues (warn-only mode, not failing build)."
|
||||
echo "Review the report at: ${REPORT}"
|
||||
fi
|
||||
|
||||
echo "Semgrep scan completed."
|
||||
@@ -36,13 +36,17 @@ fi
|
||||
|
||||
echo "Running Trivy filesystem scan..."
|
||||
|
||||
# --exit-code 1: without it trivy exits 0 even when it reports HIGH/CRITICAL
|
||||
# findings, so this job could never fail.
|
||||
trivy fs \
|
||||
--format json \
|
||||
--output /tmp/trivy-results.json \
|
||||
--severity HIGH,CRITICAL \
|
||||
--exit-code 1 \
|
||||
. || {
|
||||
EXIT_CODE=$?
|
||||
echo "Trivy found vulnerabilities. See /tmp/trivy-results.json"
|
||||
trivy fs --severity HIGH,CRITICAL . || true
|
||||
exit "${EXIT_CODE}"
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
# The filesystem Trivy scan and the Semgrep scan must fail when they find
|
||||
# something, and Semgrep must fail when it ran no rules. Local tool stubs; no
|
||||
# network needed.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SRC_SCRIPTS="$(cd "${SCRIPT_DIR}/../src/scripts" && pwd)"
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "${WORK}"' EXIT
|
||||
PASS=0
|
||||
FAIL=0
|
||||
pass() { echo "PASS"; PASS=$((PASS + 1)); }
|
||||
fail() { echo "FAIL"; FAIL=$((FAIL + 1)); }
|
||||
|
||||
mkdir -p "${WORK}/home/bin" "${WORK}/bin" "${WORK}/repo"
|
||||
cat > "${WORK}/home/bin/trivy" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
printf 'trivy %s\n' "$*" >> "${CALL_LOG}"
|
||||
# Real trivy exits 0 on findings unless --exit-code is given.
|
||||
for a in "$@"; do [[ "$a" == --exit-code ]] && exit "${SCAN_EXIT:-0}"; done
|
||||
exit 0
|
||||
EOF
|
||||
cat > "${WORK}/bin/semgrep" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
printf '%s\n' "${SEMGREP_FAKE_REPORT}" > "${SEMGREP_REPORT}"
|
||||
exit "${SEMGREP_FAKE_EXIT:-0}"
|
||||
EOF
|
||||
chmod +x "${WORK}/home/bin/trivy" "${WORK}/bin/semgrep"
|
||||
export PATH="${WORK}/bin:${PATH}" HOME="${WORK}/home" CALL_LOG="${WORK}/calls"
|
||||
export SEMGREP_REPORT="${WORK}/semgrep.json"
|
||||
cd "${WORK}/repo"
|
||||
|
||||
echo "=== Scan gate tests ==="
|
||||
echo -n " TEST: trivy fs fails the job on HIGH/CRITICAL findings... "
|
||||
if ! SCAN_EXIT=1 bash "${SRC_SCRIPTS}/run_trivy.sh" > "${WORK}/trivy.log" 2>&1 &&
|
||||
grep -q '^trivy fs .*--severity HIGH,CRITICAL --exit-code 1 ' "${CALL_LOG}"; then
|
||||
pass
|
||||
else
|
||||
fail
|
||||
fi
|
||||
|
||||
echo -n " TEST: trivy fs passes a clean scan... "
|
||||
if SCAN_EXIT=0 bash "${SRC_SCRIPTS}/run_trivy.sh" > "${WORK}/trivy.log" 2>&1; then
|
||||
pass
|
||||
else
|
||||
fail
|
||||
fi
|
||||
|
||||
if command -v python3 &>/dev/null; then
|
||||
CLEAN='{"results":[],"errors":[],"paths":{"scanned":["a.java","b.java"]}}'
|
||||
FOUND='{"results":[{"check_id":"java.lang.security.x","path":"a.java","start":{"line":3}}],"errors":[],"paths":{"scanned":["a.java"]}}'
|
||||
NORULES='{"results":[],"errors":[{"type":"InvalidRuleSchemaError","message":"invalid configuration file found (1 configs were invalid)"}],"paths":{"scanned":[]}}'
|
||||
|
||||
echo -n " TEST: semgrep passes a clean scan... "
|
||||
if SEMGREP_FAKE_REPORT="${CLEAN}" bash "${SRC_SCRIPTS}/run_semgrep.sh" > "${WORK}/sg.log" 2>&1 &&
|
||||
grep -q '2 files scanned, 0 findings' "${WORK}/sg.log"; then
|
||||
pass
|
||||
else
|
||||
fail
|
||||
fi
|
||||
|
||||
echo -n " TEST: semgrep fails on findings and lists them... "
|
||||
if ! SEMGREP_FAKE_REPORT="${FOUND}" SEMGREP_FAKE_EXIT=1 bash "${SRC_SCRIPTS}/run_semgrep.sh" > "${WORK}/sg.log" 2>&1 &&
|
||||
grep -q 'java.lang.security.x a.java:3' "${WORK}/sg.log"; then
|
||||
pass
|
||||
else
|
||||
fail
|
||||
fi
|
||||
|
||||
echo -n " TEST: semgrep warn-only mode passes with findings... "
|
||||
if SEMGREP_FAIL_ON_FINDINGS=false SEMGREP_FAKE_REPORT="${FOUND}" SEMGREP_FAKE_EXIT=1 \
|
||||
bash "${SRC_SCRIPTS}/run_semgrep.sh" > "${WORK}/sg.log" 2>&1; then
|
||||
pass
|
||||
else
|
||||
fail
|
||||
fi
|
||||
|
||||
echo -n " TEST: semgrep fails when no rules ran, even with exit 0 and warn-only... "
|
||||
if ! SEMGREP_FAIL_ON_FINDINGS=false SEMGREP_FAKE_REPORT="${NORULES}" SEMGREP_FAKE_EXIT=0 \
|
||||
bash "${SRC_SCRIPTS}/run_semgrep.sh" > "${WORK}/sg.log" 2>&1 &&
|
||||
grep -q 'did not run its rules' "${WORK}/sg.log"; then
|
||||
pass
|
||||
else
|
||||
fail
|
||||
fi
|
||||
else
|
||||
echo " SKIP: semgrep gate tests need python3"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Results: ${PASS} passed, ${FAIL} failed"
|
||||
[[ "${FAIL}" -eq 0 ]]
|
||||
Reference in new issue
Block a user