master
sh 107 lines 3.95 KB
Raw
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}"