| 1 | #!/usr/bin/env bash |
| 2 | # Apply a verdict to one Coverity defect (high-level wrapper around update-triage.sh). |
| 3 | # |
| 4 | # Usage: |
| 5 | # finalize-defect.sh <cid> <verdict> <scope> <comment-file> [commit-sha] |
| 6 | # |
| 7 | # Verdicts: |
| 8 | # TRUE_BUG_MEMORY_CORRUPTION, TRUE_BUG_CRASH, TRUE_BUG_RESOURCE_LEAK, |
| 9 | # TRUE_BUG_LOGIC, TRUE_BUG_UB -> Bug + Fix Submitted |
| 10 | # FALSE_POSITIVE_GUARD_EXISTS, FALSE_POSITIVE_UNREACHABLE, |
| 11 | # FALSE_POSITIVE_TRUSTED_INPUT, |
| 12 | # FALSE_POSITIVE_TOOL_MODEL, |
| 13 | # IMPOSSIBLE_CONDITIONS -> False Positive + Ignore |
| 14 | # COSMETIC -> Intentional + Ignore |
| 15 | # NEEDS_HUMAN, CODE_GONE -> NO-OP (skipped, exit 0) |
| 16 | # |
| 17 | # Scope: |
| 18 | # "outstanding" default; applied unconditionally |
| 19 | # anything else ("dismissed", "fixed", "unclassified", ...) -- caller |
| 20 | # asserts the new verdict disagrees with the existing |
| 21 | # Coverity classification; the script will warn but proceed. |
| 22 | # |
| 23 | # Severity is mapped from Coverity's displayImpact field. The script reads it |
| 24 | # from .local/audits/coverity/raw/outstanding-all.json or |
| 25 | # .local/audits/coverity/raw/all-in-project-all.json (fallback). |
| 26 | # If neither file exists, severity defaults to Unspecified. |
| 27 | # |
| 28 | # If a commit SHA is given, the script appends "Fix commit: <sha>" to the |
| 29 | # comment before posting. |
| 30 | |
| 31 | set -euo pipefail |
| 32 | |
| 33 | # shellcheck source=./_lib.sh |
| 34 | # shellcheck disable=SC1091 |
| 35 | source "$(dirname "$0")/_lib.sh" |
| 36 | |
| 37 | CID="${1:?usage: $0 <cid> <verdict> <scope> <comment-file> [commit-sha]}" |
| 38 | VERDICT="${2:?usage}" |
| 39 | SCOPE="${3:?usage}" |
| 40 | COMMENT_FILE="${4:?usage}" |
| 41 | COMMIT_SHA="${5:-}" |
| 42 | |
| 43 | cov_require_numeric_cid "${CID}" |
| 44 | |
| 45 | # Verdicts that never touch the UI. |
| 46 | # Anything other than NEEDS_HUMAN / CODE_GONE falls through to the next |
| 47 | # case statement which decides classification/action; the *) here just |
| 48 | # documents that explicitly. |
| 49 | case "${VERDICT}" in |
| 50 | NEEDS_HUMAN|CODE_GONE) |
| 51 | echo -e "${COV_YELLOW}Skipping Coverity update for CID ${CID} -- verdict=${VERDICT}.${COV_NC}" >&2 |
| 52 | exit 0 |
| 53 | ;; |
| 54 | *) |
| 55 | ;; |
| 56 | esac |
| 57 | |
| 58 | # Verdict -> (classification, action). |
| 59 | case "${VERDICT}" in |
| 60 | TRUE_BUG_MEMORY_CORRUPTION|TRUE_BUG_CRASH|TRUE_BUG_RESOURCE_LEAK|TRUE_BUG_LOGIC|TRUE_BUG_UB) |
| 61 | CLASS_ID=24; ACT_ID=3 ;; |
| 62 | FALSE_POSITIVE_GUARD_EXISTS|FALSE_POSITIVE_UNREACHABLE|FALSE_POSITIVE_TRUSTED_INPUT|FALSE_POSITIVE_TOOL_MODEL|IMPOSSIBLE_CONDITIONS) |
| 63 | CLASS_ID=22; ACT_ID=5 ;; |
| 64 | COSMETIC) |
| 65 | CLASS_ID=23; ACT_ID=5 ;; |
| 66 | *) |
| 67 | echo -e "${COV_RED}Unknown verdict: ${VERDICT}${COV_NC}" >&2; exit 1 ;; |
| 68 | esac |
| 69 | |
| 70 | # Severity from displayImpact. CID is validated numeric above, so embedding |
| 71 | # it in the jq filter is safe (cov_require_numeric_cid rejects anything else). |
| 72 | audit="$(cov_audit_dir)" |
| 73 | impact="" |
| 74 | for f in "${audit}/raw/outstanding-all.json" "${audit}/raw/all-in-project-all.json"; do |
| 75 | if [[ -f "${f}" && -r "${f}" ]]; then |
| 76 | impact="$(jq -r --argjson cid "${CID}" '.[] | select(.cid==$cid) | .displayImpact' "${f}" 2>/dev/null || true)" |
| 77 | [[ -n "${impact}" && "${impact}" != "null" ]] && break |
| 78 | fi |
| 79 | done |
| 80 | |
| 81 | case "${impact}" in |
| 82 | High) SEV_ID=11 ;; |
| 83 | Medium) SEV_ID=12 ;; |
| 84 | Low) SEV_ID=13 ;; |
| 85 | *) SEV_ID=10 ;; |
| 86 | esac |
| 87 | |
| 88 | echo -e "${COV_GRAY}CID ${CID}: verdict=${VERDICT} -> class=${CLASS_ID} sev=${SEV_ID} (impact=${impact:-unknown}) act=${ACT_ID}${COV_NC}" >&2 |
| 89 | |
| 90 | # If a commit SHA is given, append it to the comment before posting. |
| 91 | if [[ -n "${COMMIT_SHA}" ]]; then |
| 92 | tmp_comment="$(mktemp "${TMPDIR:-/tmp}/cov-comment-XXXXXX.txt")" |
| 93 | trap 'rm -f "${tmp_comment}"' EXIT |
| 94 | { |
| 95 | cat "${COMMENT_FILE}" |
| 96 | printf '\nFix commit: %s\n' "${COMMIT_SHA}" |
| 97 | } > "${tmp_comment}" |
| 98 | effective="${tmp_comment}" |
| 99 | else |
| 100 | effective="${COMMENT_FILE}" |
| 101 | fi |
| 102 | |
| 103 | if [[ "${SCOPE}" != "outstanding" ]]; then |
| 104 | echo -e "${COV_YELLOW}Scope=${SCOPE}: applying ONLY because caller asserts verdict disagrees with the existing classification.${COV_NC}" >&2 |
| 105 | fi |
| 106 | |
| 107 | "$(dirname "$0")/update-triage.sh" "${CID}" "${CLASS_ID}" "${SEV_ID}" "${ACT_ID}" "${effective}" |