@cxi-lmai/ci-agent-platform 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -5
- package/package.json +2 -2
- package/payload/INSTALL.md +14 -5
- package/payload/agents/agent-architect.md +1 -1
- package/payload/agents/code-reviewer.md +1 -1
- package/payload/agents/codebase-auditor.md +1 -1
- package/payload/agents/coder.md +3 -3
- package/payload/agents/decomposer.md +1 -1
- package/payload/agents/docs-sync.md +1 -1
- package/payload/agents/e2e-test-writer.md +1 -1
- package/payload/agents/performance-reviewer.md +1 -1
- package/payload/agents/release-mr.md +1 -1
- package/payload/agents/security-reviewer.md +1 -1
- package/payload/agents/test-fix.md +4 -4
- package/payload/agents/test-writer.md +3 -3
- package/payload/agents-omp/agent-architect.md +101 -0
- package/payload/agents-omp/code-reviewer.md +86 -0
- package/payload/agents-omp/codebase-auditor.md +73 -0
- package/payload/agents-omp/coder.md +57 -0
- package/payload/agents-omp/decomposer.md +70 -0
- package/payload/agents-omp/docs-sync.md +114 -0
- package/payload/agents-omp/e2e-test-writer.md +47 -0
- package/payload/agents-omp/migration-reviewer.md +99 -0
- package/payload/agents-omp/orchestrator.md +50 -0
- package/payload/agents-omp/performance-reviewer.md +81 -0
- package/payload/agents-omp/postmortem.md +82 -0
- package/payload/agents-omp/release-mr.md +274 -0
- package/payload/agents-omp/security-reviewer.md +121 -0
- package/payload/agents-omp/test-fix.md +33 -0
- package/payload/agents-omp/test-writer.md +39 -0
- package/payload/ci-templates/claude-pipeline.gitlab-ci.yml +220 -7
- package/payload/ci-templates/github/claude-issue-pipeline.yml +1 -1
- package/payload/ci-templates/github/claude-pipeline.yml +2 -2
- package/payload/ci-templates/github/claude-test-fix.yml +1 -1
- package/payload/ci-templates/scripts/agent-architect.sh +233 -0
- package/payload/ci-templates/scripts/code.sh +35 -35
- package/payload/ci-templates/scripts/codebase-audit.sh +252 -0
- package/payload/ci-templates/scripts/coverage-ratchet.sh +77 -0
- package/payload/ci-templates/scripts/cve-fix.sh +246 -0
- package/payload/ci-templates/scripts/docs-sync.sh +225 -0
- package/payload/ci-templates/scripts/e2e-test-gen.sh +201 -0
- package/payload/ci-templates/scripts/lib/failure-notice.sh +104 -0
- package/payload/ci-templates/scripts/lib/issue-loop.sh +155 -40
- package/payload/ci-templates/scripts/lib/pipeline-common.sh +233 -31
- package/payload/ci-templates/scripts/lib/platform.sh +270 -13
- package/payload/ci-templates/scripts/lib/usage-capture-omp.sh +123 -0
- package/payload/ci-templates/scripts/lib/usage-capture.sh +7 -1
- package/payload/ci-templates/scripts/metrics-snapshot.sh +377 -0
- package/payload/ci-templates/scripts/orchestrate.sh +56 -38
- package/payload/ci-templates/scripts/postmortem.sh +11 -1
- package/payload/ci-templates/scripts/review-fix.sh +23 -12
- package/payload/ci-templates/scripts/review.sh +12 -8
- package/payload/ci-templates/scripts/test-fix.sh +8 -1
- package/payload/skills/agent-architect/SKILL.md +45 -0
- package/payload/skills/codebase-audit/SKILL.md +84 -0
- package/payload/skills/cve-fix/SKILL.md +98 -0
- package/payload/skills/docs-sync/SKILL.md +74 -0
- package/payload/skills/e2e-test-gen/SKILL.md +65 -0
- package/payload/skills/fix-review-findings/SKILL.md +3 -3
- package/payload/skills/fix-tests/SKILL.md +4 -4
- package/payload/skills/implement-issue/SKILL.md +1 -1
- package/payload/skills/init-pipeline-config/SKILL.md +4 -4
- package/payload/skills/postmortem-mr/SKILL.md +1 -1
- package/payload/skills/review-mr/SKILL.md +1 -1
- package/payload/skills/triage-issue/SKILL.md +2 -2
- package/payload/templates/memory-index.template.md +34 -0
- package/payload/templates/pipeline-config.template.md +11 -1
- package/payload/templates/review_suppressions.template.md +55 -0
- package/payload/templates/spec-issue.template.md +39 -7
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Runner for the opt-in `codebase-audit` job (periodic convention-drift scan).
|
|
3
|
+
# Fetches merged MRs/PRs since the last audit, runs the `/codebase-audit` skill
|
|
4
|
+
# in `audit` mode (delegates to the codebase-auditor agent), files the findings
|
|
5
|
+
# as an issue, and — when a push-capable identity is configured and the report
|
|
6
|
+
# suggests documentation updates — runs the skill again in `apply-docs` mode
|
|
7
|
+
# (delegates to the coder agent), then pushes the branch and opens the MR/PR.
|
|
8
|
+
# All reasoning is in the skill; this script does token, API and git work.
|
|
9
|
+
#
|
|
10
|
+
# Generalized from a single-project original: the last-audited-MR lookup, the
|
|
11
|
+
# MR/PR summary, and the doc-suggestion extraction moved into the skill/runner
|
|
12
|
+
# split, platform calls go through lib/platform.sh and lib/issue-loop.sh, and
|
|
13
|
+
# the codebase-auditor/coder agents run via pipe_run_agent.
|
|
14
|
+
set -e
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
16
|
+
# shellcheck source=lib/pipeline-common.sh
|
|
17
|
+
source "$SCRIPT_DIR/lib/pipeline-common.sh"
|
|
18
|
+
# shellcheck source=lib/issue-loop.sh
|
|
19
|
+
source "$SCRIPT_DIR/lib/issue-loop.sh"
|
|
20
|
+
pipe_defaults
|
|
21
|
+
|
|
22
|
+
CONTEXT_FILE="$PIPE_CONTEXT_DIR/audit-context.md"
|
|
23
|
+
REPORT_FILE="$PIPE_CONTEXT_DIR/audit-report.md"
|
|
24
|
+
SUGGESTIONS_FILE="$PIPE_CONTEXT_DIR/audit-doc-suggestions.md"
|
|
25
|
+
AUDIT_ENV="$PIPE_CONTEXT_DIR/audit.env"
|
|
26
|
+
|
|
27
|
+
# --- 1. Last-audited MR/PR IID, parsed from the most recent audit issue -----
|
|
28
|
+
# The most recent codebase-audit-labeled issue regardless of state: a closed
|
|
29
|
+
# one still marks how far the previous audit got. A genuine fetch failure
|
|
30
|
+
# must not be mistaken for "no prior audit issue" (which legitimately yields
|
|
31
|
+
# an empty array and keeps LAST_AUDITED_IID at 0): capture the helper's own
|
|
32
|
+
# exit status explicitly instead of piping it straight into jq.
|
|
33
|
+
LAST_AUDITED_IID=0
|
|
34
|
+
LAST_AUDIT_ISSUES=$(issues_by_label_created "$PIPE_LABEL_AUDIT" all 1) || {
|
|
35
|
+
pipe_log "ERROR: failed to fetch the most recent $PIPE_LABEL_AUDIT-labeled issue"
|
|
36
|
+
exit 1
|
|
37
|
+
}
|
|
38
|
+
LAST_AUDIT_DESC=$(jq -r '.[0].description // ""' <<< "$LAST_AUDIT_ISSUES" 2>/dev/null || echo "")
|
|
39
|
+
if [ -n "$LAST_AUDIT_DESC" ]; then
|
|
40
|
+
PARSED_IID=$(printf '%s' "$LAST_AUDIT_DESC" | grep -oE 'audited-up-to-mr-iid: [0-9]+' | grep -oE '[0-9]+$' || echo "")
|
|
41
|
+
[ -n "$PARSED_IID" ] && LAST_AUDITED_IID="$PARSED_IID"
|
|
42
|
+
fi
|
|
43
|
+
pipe_log "Last audited MR/PR IID: $LAST_AUDITED_IID"
|
|
44
|
+
|
|
45
|
+
# --- 2. Merged MRs/PRs since then, with a changed-file summary --------------
|
|
46
|
+
MRS=$(platform_merged_mrs "$PIPE_TARGET_BRANCH" "$LAST_AUDITED_IID" 50) || {
|
|
47
|
+
pipe_log "ERROR: failed to fetch merged MRs/PRs"
|
|
48
|
+
exit 1
|
|
49
|
+
}
|
|
50
|
+
MR_COUNT=$(echo "$MRS" | jq 'length' 2>/dev/null || echo "")
|
|
51
|
+
if ! [[ "$MR_COUNT" =~ ^[0-9]+$ ]]; then
|
|
52
|
+
pipe_log "ERROR: unexpected API response while counting merged MRs/PRs"
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
pipe_log "Analyzing $MR_COUNT recently merged MR/PR(s) (since IID $LAST_AUDITED_IID)"
|
|
56
|
+
[ "$MR_COUNT" = "0" ] && { pipe_log "No new MRs/PRs since last audit — skipping"; exit 0; }
|
|
57
|
+
MAX_AUDITED_IID=$(echo "$MRS" | jq '[.[].iid] | max // 0' 2>/dev/null || echo "")
|
|
58
|
+
if ! [[ "$MAX_AUDITED_IID" =~ ^[0-9]+$ ]]; then
|
|
59
|
+
pipe_log "ERROR: could not determine the max merged MR/PR IID from the API response"
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
MR_SUMMARY=""
|
|
64
|
+
while IFS= read -r IID; do
|
|
65
|
+
TITLE=$(echo "$MRS" | jq -r --argjson i "$IID" '.[] | select(.iid == $i) | .title')
|
|
66
|
+
# A single MR's changed-file fetch failing is an acceptable degradation (an
|
|
67
|
+
# empty file list in its summary line), not grounds to abort the whole audit.
|
|
68
|
+
FILES=$(platform_mr_changes "$IID" 10 | paste -sd, -) || true
|
|
69
|
+
MR_SUMMARY="${MR_SUMMARY}MR/PR !${IID} ${TITLE} -- Files ${FILES}; "
|
|
70
|
+
done < <(echo "$MRS" | jq -r '.[].iid')
|
|
71
|
+
|
|
72
|
+
# --- 3. Open audit issues, as dedup context for the auditor ------------------
|
|
73
|
+
OPEN_AUDIT_CONTEXT=""
|
|
74
|
+
# Dedup context only tells the auditor which findings are already filed; a
|
|
75
|
+
# transient fetch failure here must not abort the whole scheduled audit
|
|
76
|
+
# (unlike step 1's watermark read, which is load-bearing). Degrade to an
|
|
77
|
+
# empty result and continue, analogous to a single MR's changes-fetch
|
|
78
|
+
# degradation in step 2.
|
|
79
|
+
OPEN_AUDITS=$(issues_by_label_created "$PIPE_LABEL_AUDIT" opened 5) || {
|
|
80
|
+
pipe_log "WARNING: failed to fetch open $PIPE_LABEL_AUDIT-labeled issues for dedup context — continuing without it"
|
|
81
|
+
OPEN_AUDITS="[]"
|
|
82
|
+
}
|
|
83
|
+
OPEN_COUNT=$(echo "$OPEN_AUDITS" | jq 'length' 2>/dev/null || echo 0)
|
|
84
|
+
if [ "$OPEN_COUNT" != "0" ] && [ "$OPEN_COUNT" != "null" ]; then
|
|
85
|
+
OPEN_AUDIT_CONTEXT=$(echo "$OPEN_AUDITS" | jq -r '.[] | "Issue #\(.iid) (\(.created_at[0:10])): \(.title)\n\(.description[0:800])\n---"' 2>/dev/null | head -c 8000 || echo "")
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# --- 4. Run the /codebase-audit skill in audit mode --------------------------
|
|
89
|
+
# Write the context file the skill and the codebase-auditor agent read.
|
|
90
|
+
# Unbounded text stays out of argv/env; this content is already bounded above.
|
|
91
|
+
rm -f "$AUDIT_ENV" "$REPORT_FILE" "$SUGGESTIONS_FILE"
|
|
92
|
+
{
|
|
93
|
+
echo "# Codebase audit context"
|
|
94
|
+
echo
|
|
95
|
+
echo "Mode: audit"
|
|
96
|
+
echo
|
|
97
|
+
echo "## Recently merged MRs/PRs"
|
|
98
|
+
echo
|
|
99
|
+
printf '%s\n' "$MR_SUMMARY"
|
|
100
|
+
if [ -n "$OPEN_AUDIT_CONTEXT" ]; then
|
|
101
|
+
echo
|
|
102
|
+
echo "## Already-open ${PIPE_LABEL_AUDIT}-labeled issues (skip findings already covered here)"
|
|
103
|
+
echo
|
|
104
|
+
printf '%s\n' "$OPEN_AUDIT_CONTEXT"
|
|
105
|
+
fi
|
|
106
|
+
} > "$CONTEXT_FILE"
|
|
107
|
+
|
|
108
|
+
pipe_run_agent codebase-audit "/codebase-audit" "Agent,Read,Write,Edit,Glob,Grep,Bash" "$PIPE_MODEL_TRIAGE" < /dev/null
|
|
109
|
+
|
|
110
|
+
AUDIT_STATUS=$(pipe_get_env "$AUDIT_ENV" AUDIT_STATUS)
|
|
111
|
+
AUDIT_FINDINGS_TOTAL=$(pipe_get_env "$AUDIT_ENV" AUDIT_FINDINGS_TOTAL); AUDIT_FINDINGS_TOTAL=${AUDIT_FINDINGS_TOTAL:-0}
|
|
112
|
+
# pipe_get_env does no shell expansion: a marker that copies the sample line
|
|
113
|
+
# literally (e.g. `AUDIT_REPORT_PATH=$PIPE_CONTEXT_DIR/audit-report.md`
|
|
114
|
+
# unexpanded) or otherwise points at a path that doesn't exist must not
|
|
115
|
+
# discard a perfectly good report at the runner's own default path (review
|
|
116
|
+
# round 2 finding).
|
|
117
|
+
AUDIT_REPORT_PATH=$(pipe_get_env "$AUDIT_ENV" AUDIT_REPORT_PATH)
|
|
118
|
+
if [ ! -s "$AUDIT_REPORT_PATH" ] && [ -s "$REPORT_FILE" ]; then
|
|
119
|
+
AUDIT_REPORT_PATH="$REPORT_FILE"
|
|
120
|
+
fi
|
|
121
|
+
AUDIT_REPORT_PATH=${AUDIT_REPORT_PATH:-$REPORT_FILE}
|
|
122
|
+
|
|
123
|
+
# --- 5. Empty output, or a missing/empty report file: log-only notice -------
|
|
124
|
+
# (no issue exists yet to post to). A model-authored marker claiming ok/
|
|
125
|
+
# no_findings with no actual report on disk is a reachable contract failure,
|
|
126
|
+
# not just a literal no_output status; guard the file the same way
|
|
127
|
+
# docs-sync.sh guards its own agent output before touching it.
|
|
128
|
+
if [ -z "$AUDIT_STATUS" ] || [ "$AUDIT_STATUS" = "no_output" ] || [ ! -s "$AUDIT_REPORT_PATH" ]; then
|
|
129
|
+
pipe_failure_log_notice_files "the periodic codebase audit" \
|
|
130
|
+
"audit recent MRs/PRs by hand for convention violations, or re-run this job after topping up" \
|
|
131
|
+
"$PIPE_AGENT_STDERR" "$AUDIT_REPORT_PATH" | while IFS= read -r line; do pipe_log "$line"; done
|
|
132
|
+
exit 0
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
# --- 6. No findings above threshold: nothing to file --------------------------
|
|
136
|
+
if [ "$AUDIT_STATUS" = "no_findings" ]; then
|
|
137
|
+
pipe_log "No findings above threshold in either section — skipping issue creation"
|
|
138
|
+
exit 0
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# --- 7. File the findings as an issue -----------------------------------------
|
|
142
|
+
issue_ensure_label "$PIPE_LABEL_AUDIT" "#6F42C1" "Periodic convention-drift audit findings"
|
|
143
|
+
ISSUE_BODY_FILE="$PIPE_CONTEXT_DIR/audit-issue-body.md"
|
|
144
|
+
{
|
|
145
|
+
printf '<!-- audited-up-to-mr-iid: %s -->\n' "$MAX_AUDITED_IID"
|
|
146
|
+
head -c 20000 "$AUDIT_REPORT_PATH"
|
|
147
|
+
} > "$ISSUE_BODY_FILE"
|
|
148
|
+
ISSUE_IID=$(issue_create_file "Codebase Audit — $(date +%Y-%m-%d)" "$ISSUE_BODY_FILE" "$PIPE_LABEL_AUDIT")
|
|
149
|
+
if [ -z "$ISSUE_IID" ]; then
|
|
150
|
+
pipe_log "ERROR: failed to create the audit findings issue"
|
|
151
|
+
exit 0
|
|
152
|
+
fi
|
|
153
|
+
pipe_log "Filed audit findings as #$ISSUE_IID"
|
|
154
|
+
# The runner is the one that knows the IID: append it now so the marker
|
|
155
|
+
# artifact is complete when the job finishes (see the skill's own contract).
|
|
156
|
+
printf 'AUDIT_ISSUE_IID=%s\n' "$ISSUE_IID" >> "$AUDIT_ENV"
|
|
157
|
+
|
|
158
|
+
pipe_metric_event codebase-audit audit_filed \
|
|
159
|
+
"$(jq -n --argjson i "$ISSUE_IID" --argjson f "$AUDIT_FINDINGS_TOTAL" '{issue_iid: $i, findings_total: $f}')"
|
|
160
|
+
|
|
161
|
+
# --- 8. No push-capable identity: audit-only run, stop here -----------------
|
|
162
|
+
PUSH_TOKEN=""
|
|
163
|
+
case "$PIPE_PLATFORM" in
|
|
164
|
+
gitlab) PUSH_TOKEN="${PIPE_TOKEN:-}" ;;
|
|
165
|
+
github) PUSH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN:-}}" ;;
|
|
166
|
+
esac
|
|
167
|
+
if [ -z "$PUSH_TOKEN" ]; then
|
|
168
|
+
pipe_log "No push-capable identity configured — skipping auto-fix phase"
|
|
169
|
+
exit 0
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# --- 9. No doc-update suggestions: nothing for the coder to apply -----------
|
|
173
|
+
if [ ! -s "$SUGGESTIONS_FILE" ]; then
|
|
174
|
+
pipe_log "No documentation update suggestions — skipping auto-fix phase"
|
|
175
|
+
exit 0
|
|
176
|
+
fi
|
|
177
|
+
pipe_log "Doc suggestions found — spawning the coder agent"
|
|
178
|
+
|
|
179
|
+
# --- 10. Branch, then run the skill again in apply-docs mode -----------------
|
|
180
|
+
pipe_git_identity
|
|
181
|
+
git fetch origin "$PIPE_TARGET_BRANCH"
|
|
182
|
+
BRANCH="audit-$(date +%Y-%m-%d)"
|
|
183
|
+
# A same-day retry (transient failure, manual re-trigger) can find this
|
|
184
|
+
# branch already on the remote from an earlier attempt. Fetch it so the
|
|
185
|
+
# --force-with-lease push below has a known expected state instead of
|
|
186
|
+
# refusing for lack of a remote-tracking ref.
|
|
187
|
+
git fetch origin "$BRANCH" 2>/dev/null || true
|
|
188
|
+
git checkout -B "$BRANCH" "origin/$PIPE_TARGET_BRANCH"
|
|
189
|
+
|
|
190
|
+
APPLY_ENV="$PIPE_CONTEXT_DIR/audit-apply.env"
|
|
191
|
+
rm -f "$APPLY_ENV"
|
|
192
|
+
{
|
|
193
|
+
echo "# Codebase audit apply-docs context"
|
|
194
|
+
echo
|
|
195
|
+
echo "Mode: apply-docs"
|
|
196
|
+
echo
|
|
197
|
+
echo "Issue: #$ISSUE_IID"
|
|
198
|
+
echo "Documentation roots: $PIPE_DOCS_ROOTS"
|
|
199
|
+
echo "Commit subject: $PIPE_COMMIT_AUDIT"
|
|
200
|
+
echo "Doc suggestions file: $SUGGESTIONS_FILE"
|
|
201
|
+
echo "Full audit report: $AUDIT_REPORT_PATH"
|
|
202
|
+
} > "$CONTEXT_FILE"
|
|
203
|
+
|
|
204
|
+
pipe_run_agent codebase-audit-apply "/codebase-audit" "Agent,Read,Write,Edit,Glob,Grep,Bash" "$PIPE_MODEL_CODE" < /dev/null
|
|
205
|
+
|
|
206
|
+
# --- 11. Authoritative commit count (the runner owns the push decision) ------
|
|
207
|
+
AHEAD=$(git rev-list "origin/$PIPE_TARGET_BRANCH..HEAD" --count 2>/dev/null || echo 0)
|
|
208
|
+
if [ "${AHEAD:-0}" = "0" ]; then
|
|
209
|
+
pipe_log "Coder made no commits — skipping MR/PR"
|
|
210
|
+
# "No commits" reads as "nothing needed fixing", but a credit outage produces
|
|
211
|
+
# the same silence. Issue #$ISSUE_IID already holds the findings, so on a
|
|
212
|
+
# credit outage tell its readers the apply step never ran rather than
|
|
213
|
+
# leaving them to assume it found nothing.
|
|
214
|
+
pipe_failure_log_notice_files "the audit apply step" \
|
|
215
|
+
"apply the findings in this issue by hand" \
|
|
216
|
+
"$PIPE_AGENT_STDERR" "$APPLY_ENV" | while IFS= read -r line; do pipe_log "$line"; done
|
|
217
|
+
if pipe_is_credit_exhaustion_files "$PIPE_AGENT_STDERR" "$APPLY_ENV"; then
|
|
218
|
+
NOTICE_FILE="$PIPE_CONTEXT_DIR/audit-apply-credit-notice.md"
|
|
219
|
+
pipe_failure_notice_files "application of these audit findings" \
|
|
220
|
+
"apply the findings above by hand, or re-run the audit job after topping up" \
|
|
221
|
+
"$PIPE_AGENT_STDERR" "$APPLY_ENV" > "$NOTICE_FILE"
|
|
222
|
+
issue_comment_file "$ISSUE_IID" "$NOTICE_FILE"
|
|
223
|
+
pipe_log "Posted credit-exhaustion notice to issue #$ISSUE_IID"
|
|
224
|
+
fi
|
|
225
|
+
git checkout "$PIPE_TARGET_BRANCH" 2>/dev/null || true
|
|
226
|
+
git branch -D "$BRANCH" 2>/dev/null || true
|
|
227
|
+
exit 0
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
pipe_metric_event codebase-audit audit_apply_committed \
|
|
231
|
+
"$(jq -n --argjson i "$ISSUE_IID" --argjson c "$AHEAD" '{issue_iid: $i, commits: $c}')"
|
|
232
|
+
|
|
233
|
+
# --- 12. Push and open the MR/PR ---------------------------------------------
|
|
234
|
+
# --force-with-lease: this is a dedicated bot branch reset fresh from the
|
|
235
|
+
# target branch every run, so a same-day retry intentionally replaces
|
|
236
|
+
# whatever an earlier attempt left on the remote. --force-with-lease (rather
|
|
237
|
+
# than a bare --force) still refuses if the branch changed unexpectedly
|
|
238
|
+
# between the fetch above and now.
|
|
239
|
+
git push --force-with-lease -u origin "$BRANCH"
|
|
240
|
+
|
|
241
|
+
MR_DESC_FILE="$PIPE_CONTEXT_DIR/audit-mr-description.md"
|
|
242
|
+
{
|
|
243
|
+
printf 'Automated documentation updates from the periodic convention audit.\n\nCloses #%s\n\n---\n\n' "$ISSUE_IID"
|
|
244
|
+
head -c 10000 "$AUDIT_REPORT_PATH"
|
|
245
|
+
} > "$MR_DESC_FILE"
|
|
246
|
+
|
|
247
|
+
MR_URL=$(mr_create_file "$BRANCH" "$PIPE_TARGET_BRANCH" "docs: codebase audit updates ($(date +%Y-%m-%d))" "$MR_DESC_FILE" "$PIPE_LABEL_AUDIT")
|
|
248
|
+
if [ -n "$MR_URL" ]; then
|
|
249
|
+
pipe_log "Opened MR/PR: $MR_URL"
|
|
250
|
+
else
|
|
251
|
+
pipe_log "WARNING: MR/PR creation returned no URL (it may already exist for this branch)"
|
|
252
|
+
fi
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Opt-in coverage gate. Reads the configured coverage report, compares it with
|
|
3
|
+
# the target branch's latest successful pipeline, and sends coverage drops on
|
|
4
|
+
# wip merge requests into the existing test-fix loop.
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
# shellcheck source=lib/pipeline-common.sh
|
|
9
|
+
source "$SCRIPT_DIR/lib/pipeline-common.sh"
|
|
10
|
+
pipe_defaults
|
|
11
|
+
|
|
12
|
+
coverage_from_jacoco() {
|
|
13
|
+
local covered missed
|
|
14
|
+
if ! covered=$(xmllint --xpath 'string(//report/counter[@type="INSTRUCTION"]/@covered)' \
|
|
15
|
+
"$PIPE_COVERAGE_REPORT" 2>/dev/null) ||
|
|
16
|
+
! missed=$(xmllint --xpath 'string(//report/counter[@type="INSTRUCTION"]/@missed)' \
|
|
17
|
+
"$PIPE_COVERAGE_REPORT" 2>/dev/null); then
|
|
18
|
+
echo "ERROR: unable to parse JaCoCo instruction coverage from: $PIPE_COVERAGE_REPORT" >&2
|
|
19
|
+
return 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
if [[ "$covered" =~ ^[0-9]+$ ]] && [[ "$missed" =~ ^[0-9]+$ ]] && \
|
|
23
|
+
[ "$((covered + missed))" -gt 0 ]; then
|
|
24
|
+
printf '%s\n' "$((covered * 100 / (covered + missed)))"
|
|
25
|
+
else
|
|
26
|
+
echo "ERROR: unable to parse JaCoCo instruction coverage from: $PIPE_COVERAGE_REPORT" >&2
|
|
27
|
+
return 1
|
|
28
|
+
fi
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
case "$PIPE_COVERAGE_REPORT_KIND" in
|
|
32
|
+
jacoco) ;;
|
|
33
|
+
*) echo "ERROR: unsupported coverage report kind: $PIPE_COVERAGE_REPORT_KIND" >&2; exit 1 ;;
|
|
34
|
+
esac
|
|
35
|
+
|
|
36
|
+
[ -z "${PIPE_MR_IID:-}" ] && exit 0
|
|
37
|
+
|
|
38
|
+
if [ -z "$PIPE_COVERAGE_REPORT" ] || [ ! -f "$PIPE_COVERAGE_REPORT" ]; then
|
|
39
|
+
echo "Coverage ratchet inactive: coverage report is not available: ${PIPE_COVERAGE_REPORT:-<unset>}"
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
command -v xmllint >/dev/null 2>&1 || {
|
|
44
|
+
echo "ERROR: xmllint is required to parse PIPE_COVERAGE_REPORT" >&2
|
|
45
|
+
exit 1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
CURRENT_COV=$(coverage_from_jacoco)
|
|
49
|
+
|
|
50
|
+
if [ "$PIPE_COVERAGE_RATCHET" = "1" ] && [ -z "$PIPE_COVERAGE_SIGNAL" ]; then
|
|
51
|
+
echo "ERROR: PIPE_COVERAGE_SIGNAL must be set when PIPE_COVERAGE_RATCHET=1" >&2
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
BASELINE=$(platform_latest_success_coverage "$PIPE_TARGET_BRANCH" 2>/dev/null || true)
|
|
56
|
+
BASELINE=${BASELINE%%.*}
|
|
57
|
+
[[ "$BASELINE" =~ ^[0-9]+$ ]] || BASELINE=0
|
|
58
|
+
|
|
59
|
+
echo "Total coverage: ${CURRENT_COV}%"
|
|
60
|
+
echo "Coverage: current=${CURRENT_COV}% baseline=${BASELINE}%"
|
|
61
|
+
|
|
62
|
+
if [ "$CURRENT_COV" -lt "$BASELINE" ]; then
|
|
63
|
+
echo "WARNING: Coverage dropped from ${BASELINE}% to ${CURRENT_COV}%"
|
|
64
|
+
COMMENT_FILE="$PIPE_CONTEXT_DIR/coverage-ratchet.md"
|
|
65
|
+
printf '**Coverage dropped** from %s%% to %s%%. Please check whether new code is missing tests.\n' \
|
|
66
|
+
"$BASELINE" "$CURRENT_COV" > "$COMMENT_FILE"
|
|
67
|
+
platform_post_comment_file "$COMMENT_FILE" || true
|
|
68
|
+
|
|
69
|
+
LABELS=$(platform_mr_labels)
|
|
70
|
+
case ",$LABELS," in
|
|
71
|
+
*",$PIPE_LABEL_WIP,"*)
|
|
72
|
+
printf 'COVERAGE_DROP:%s:%s\n' "$BASELINE" "$CURRENT_COV" > "$PIPE_COVERAGE_SIGNAL"
|
|
73
|
+
echo "Coverage dropped on $PIPE_LABEL_WIP MR/PR — exiting 1 to trigger test-fix"
|
|
74
|
+
exit 1
|
|
75
|
+
;;
|
|
76
|
+
esac
|
|
77
|
+
fi
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Runner for the opt-in CVE remediation job. A project-local scanner supplies
|
|
3
|
+
# HIGH/CRITICAL identifiers in PIPE_CVE_LIST; this runner scopes the coder,
|
|
4
|
+
# verifies its commit and compile result, and alone owns rebase/push/comments.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
# shellcheck source=lib/pipeline-common.sh
|
|
9
|
+
source "$SCRIPT_DIR/lib/pipeline-common.sh"
|
|
10
|
+
pipe_defaults
|
|
11
|
+
|
|
12
|
+
CONTEXT_FILE="$PIPE_CONTEXT_DIR/cve-fix-context.md"
|
|
13
|
+
CVE_LIST_FILE="$PIPE_CONTEXT_DIR/cve-fix-list.txt"
|
|
14
|
+
MANIFEST_FILE="$PIPE_CONTEXT_DIR/cve-fix-manifest.txt"
|
|
15
|
+
CVE_ENV="$PIPE_CONTEXT_DIR/cve-fix.env"
|
|
16
|
+
COMMENT_FILE="$PIPE_CONTEXT_DIR/cve-fix-comment.md"
|
|
17
|
+
|
|
18
|
+
# The scanner controls both selection and severity filtering. Bound its output
|
|
19
|
+
# before it reaches a context or comment, and never forward it in argv/env.
|
|
20
|
+
head -c 8000 <<< "${PIPE_CVE_LIST:-}" > "$CVE_LIST_FILE"
|
|
21
|
+
# A cap can cut the final list entry mid-line. Add only a record terminator
|
|
22
|
+
# before filtering/counting; the caller-provided content remains bounded.
|
|
23
|
+
printf '\n' >> "$CVE_LIST_FILE"
|
|
24
|
+
sed -i '/^[[:space:]]*$/d' "$CVE_LIST_FILE"
|
|
25
|
+
CVE_COUNT=$(awk 'NF { count++ } END { print count + 0 }' "$CVE_LIST_FILE")
|
|
26
|
+
|
|
27
|
+
write_marker() {
|
|
28
|
+
# Marker values are canonical runner output. Never source model-written data.
|
|
29
|
+
printf 'CVE_FIX_APPLIED=%s\nCVE_COMPILED=%s\nCVE_COUNT=%s\nCVE_MANUAL_REQUIRED=%s\n' \
|
|
30
|
+
"$1" "$2" "$CVE_COUNT" "$3" > "$CVE_ENV"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
post_comment() {
|
|
34
|
+
# Posts the complete, bounded body already written to $COMMENT_FILE.
|
|
35
|
+
platform_post_comment_file "$COMMENT_FILE" || pipe_log "Could not post CVE remediation comment"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
post_manual_comment() {
|
|
39
|
+
# $1 is the short manual-action explanation. The list is bounded above.
|
|
40
|
+
{
|
|
41
|
+
printf '**Automated CVE remediation requires manual action.**\n\n%s\n' "$1"
|
|
42
|
+
if [ -s "$CVE_LIST_FILE" ]; then
|
|
43
|
+
printf '\nAffected HIGH/CRITICAL vulnerability identifiers:\n'
|
|
44
|
+
sed 's/^/- /' "$CVE_LIST_FILE"
|
|
45
|
+
fi
|
|
46
|
+
} > "$COMMENT_FILE"
|
|
47
|
+
post_comment
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
count_matching_commits() {
|
|
51
|
+
local count=0 subject
|
|
52
|
+
while IFS= read -r subject; do
|
|
53
|
+
[ "$subject" = "$PIPE_COMMIT_CVEFIX" ] && count=$((count + 1))
|
|
54
|
+
done < <(git log "origin/$PIPE_TARGET_BRANCH..HEAD" --format='%s' 2>/dev/null)
|
|
55
|
+
printf '%s\n' "$count"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
marker_is_valid() {
|
|
59
|
+
local line applied=0 compiled=0 count=0 manual=0
|
|
60
|
+
[ -f "$CVE_ENV" ] || return 1
|
|
61
|
+
while IFS= read -r line || [ -n "$line" ]; do
|
|
62
|
+
case "$line" in
|
|
63
|
+
CVE_FIX_APPLIED=0|CVE_FIX_APPLIED=1) applied=$((applied + 1)) ;;
|
|
64
|
+
CVE_COMPILED=0|CVE_COMPILED=1) compiled=$((compiled + 1)) ;;
|
|
65
|
+
CVE_MANUAL_REQUIRED=0|CVE_MANUAL_REQUIRED=1) manual=$((manual + 1)) ;;
|
|
66
|
+
CVE_COUNT=*)
|
|
67
|
+
[[ "$line" =~ ^CVE_COUNT=[0-9]+$ ]] || return 1
|
|
68
|
+
count=$((count + 1))
|
|
69
|
+
;;
|
|
70
|
+
*) return 1 ;;
|
|
71
|
+
esac
|
|
72
|
+
done < "$CVE_ENV"
|
|
73
|
+
[ "$applied" -eq 1 ] && [ "$compiled" -eq 1 ] && [ "$count" -eq 1 ] && [ "$manual" -eq 1 ]
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
marker_value() {
|
|
77
|
+
# marker_is_valid has already limited this to a literal 0, 1, or decimal.
|
|
78
|
+
pipe_get_env "$CVE_ENV" "$1"
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# This job has no purpose outside a merge/pull-request pipeline. Do not attempt
|
|
82
|
+
# a forge lookup that can accidentally turn a branch pipeline into a comment.
|
|
83
|
+
if [ -z "${PIPE_MR_IID:-}" ]; then
|
|
84
|
+
pipe_log "No merge request/pull request context; CVE remediation is inactive"
|
|
85
|
+
exit 0
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Empty scanner output is normal and must remain silent. Check it before any
|
|
89
|
+
# metadata/WIP gate so enabling the optional job does not spam ordinary MRs.
|
|
90
|
+
if [ "$CVE_COUNT" = "0" ]; then
|
|
91
|
+
pipe_log "No vulnerability identifiers supplied; CVE remediation is inactive"
|
|
92
|
+
write_marker 0 0 1
|
|
93
|
+
exit 0
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# The list was supplied by the caller and can be arbitrarily large. The only
|
|
97
|
+
# bounded copy is the context file above; do not let the dispatcher inherit it.
|
|
98
|
+
unset PIPE_CVE_LIST
|
|
99
|
+
|
|
100
|
+
META=$(platform_mr_meta 2>/dev/null || true)
|
|
101
|
+
MR_LABELS=$(jq -r '.labels // ""' <<< "$META" 2>/dev/null || true)
|
|
102
|
+
META_SOURCE_BRANCH=$(jq -r '.source_branch // ""' <<< "$META" 2>/dev/null || true)
|
|
103
|
+
if [ -n "$META_SOURCE_BRANCH" ]; then
|
|
104
|
+
PIPE_SOURCE_BRANCH="$META_SOURCE_BRANCH"
|
|
105
|
+
export PIPE_SOURCE_BRANCH
|
|
106
|
+
fi
|
|
107
|
+
if [ -z "${PIPE_SOURCE_BRANCH:-}" ]; then
|
|
108
|
+
pipe_log "MR/PR metadata has no source branch"
|
|
109
|
+
post_manual_comment "The source branch metadata is unavailable; update the dependencies manually."
|
|
110
|
+
write_marker 0 0 1
|
|
111
|
+
exit 0
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
if ! grep -qF "$PIPE_LABEL_WIP" <<< "$MR_LABELS"; then
|
|
115
|
+
pipe_log "MR/PR is not labeled $PIPE_LABEL_WIP; requesting a manual dependency update"
|
|
116
|
+
post_manual_comment "This MR/PR is not marked for autonomous changes; update the dependencies manually."
|
|
117
|
+
write_marker 0 0 1
|
|
118
|
+
exit 0
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
# A dependency manifest is project-relative by contract. Reject paths that
|
|
122
|
+
# could point outside this checkout before using them in git or file commands.
|
|
123
|
+
case "$PIPE_DEPENDENCY_MANIFEST" in
|
|
124
|
+
''|/*|..|../*|*/..|*/../*)
|
|
125
|
+
pipe_log "Invalid project-relative dependency manifest path: $PIPE_DEPENDENCY_MANIFEST"
|
|
126
|
+
post_manual_comment "The configured dependency manifest path is invalid; update the dependencies manually."
|
|
127
|
+
write_marker 0 0 1
|
|
128
|
+
exit 0
|
|
129
|
+
;;
|
|
130
|
+
esac
|
|
131
|
+
|
|
132
|
+
pipe_git_identity
|
|
133
|
+
pipe_checkout_source
|
|
134
|
+
if ! git rev-parse --verify "origin/$PIPE_SOURCE_BRANCH" >/dev/null 2>&1 \
|
|
135
|
+
|| [ "$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)" != "$PIPE_SOURCE_BRANCH" ]; then
|
|
136
|
+
pipe_log "Unable to check out source branch safely: $PIPE_SOURCE_BRANCH"
|
|
137
|
+
post_manual_comment "The source branch could not be checked out safely; update the dependencies manually."
|
|
138
|
+
write_marker 0 0 1
|
|
139
|
+
exit 0
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
EXISTING_FIXES=$(count_matching_commits)
|
|
143
|
+
if [ "$EXISTING_FIXES" -ge "$PIPE_FIX_LOOP_CAP" ]; then
|
|
144
|
+
pipe_log "CVE remediation reached its commit budget ($EXISTING_FIXES/$PIPE_FIX_LOOP_CAP)"
|
|
145
|
+
post_manual_comment "The CVE remediation commit budget is exhausted; update the dependencies manually."
|
|
146
|
+
write_marker 0 0 1
|
|
147
|
+
exit 0
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
if [ ! -f "$PIPE_DEPENDENCY_MANIFEST" ]; then
|
|
151
|
+
pipe_log "Dependency manifest is missing: $PIPE_DEPENDENCY_MANIFEST"
|
|
152
|
+
post_manual_comment "Dependency manifest is missing: \`$PIPE_DEPENDENCY_MANIFEST\`. Update the dependencies manually."
|
|
153
|
+
write_marker 0 0 1
|
|
154
|
+
exit 0
|
|
155
|
+
fi
|
|
156
|
+
head -c 8000 "$PIPE_DEPENDENCY_MANIFEST" > "$MANIFEST_FILE"
|
|
157
|
+
REMAINING_BUDGET=$((PIPE_FIX_LOOP_CAP - EXISTING_FIXES))
|
|
158
|
+
rm -f "$CVE_ENV"
|
|
159
|
+
{
|
|
160
|
+
printf '# CVE remediation context\n\n'
|
|
161
|
+
printf 'Mode: apply\n'
|
|
162
|
+
printf 'Vulnerability List File: %s\n' "$CVE_LIST_FILE"
|
|
163
|
+
printf 'Dependency Manifest Path: %s\n' "$PIPE_DEPENDENCY_MANIFEST"
|
|
164
|
+
printf 'Dependency Manifest Content File: %s\n' "$MANIFEST_FILE"
|
|
165
|
+
printf 'Compile Command: %s\n' "$PIPE_COMPILE_CMD"
|
|
166
|
+
printf 'Commit Subject: %s\n' "$PIPE_COMMIT_CVEFIX"
|
|
167
|
+
printf 'Source Branch: %s\n' "$PIPE_SOURCE_BRANCH"
|
|
168
|
+
printf 'Target Branch: %s\n' "$PIPE_TARGET_BRANCH"
|
|
169
|
+
printf 'Suppression Path: %s\n' "$PIPE_CVE_SUPPRESSIONS"
|
|
170
|
+
printf 'Remaining Commit Budget: %s\n' "$REMAINING_BUDGET"
|
|
171
|
+
printf 'Marker File: %s\n' "$CVE_ENV"
|
|
172
|
+
} > "$CONTEXT_FILE"
|
|
173
|
+
|
|
174
|
+
# The skill decides dependency versions. This is the same code-writing policy
|
|
175
|
+
# as other runners; it receives no shell-built remediation prompt.
|
|
176
|
+
PRE_AGENT_SHA=$(git rev-parse HEAD)
|
|
177
|
+
pipe_run_agent cve-fix "/cve-fix" "Agent,Read,Write,Edit,Glob,Grep,Bash" "$PIPE_MODEL_CODE" < /dev/null
|
|
178
|
+
POST_AGENT_SHA=$(git rev-parse HEAD)
|
|
179
|
+
NEW_FIXES=$(count_matching_commits)
|
|
180
|
+
RANGE_COMMITS=$(git rev-list --count "$PRE_AGENT_SHA..$POST_AGENT_SHA" 2>/dev/null || echo 0)
|
|
181
|
+
RANGE_HAS_DIFF=false
|
|
182
|
+
if ! git diff --quiet "$PRE_AGENT_SHA..$POST_AGENT_SHA" 2>/dev/null; then
|
|
183
|
+
RANGE_HAS_DIFF=true
|
|
184
|
+
fi
|
|
185
|
+
RANGE_MANIFEST_ONLY=true
|
|
186
|
+
while IFS= read -r path; do
|
|
187
|
+
[ "$path" = "$PIPE_DEPENDENCY_MANIFEST" ] || { RANGE_MANIFEST_ONLY=false; break; }
|
|
188
|
+
done < <(git diff --name-only "$PRE_AGENT_SHA..$POST_AGENT_SHA" 2>/dev/null)
|
|
189
|
+
|
|
190
|
+
if ! marker_is_valid || [ "$(marker_value CVE_FIX_APPLIED)" != "1" ] \
|
|
191
|
+
|| [ "$(marker_value CVE_COMPILED)" != "1" ] || [ "$(marker_value CVE_MANUAL_REQUIRED)" != "0" ] \
|
|
192
|
+
|| [ "$NEW_FIXES" -ne $((EXISTING_FIXES + 1)) ] || [ "$RANGE_COMMITS" != "1" ] \
|
|
193
|
+
|| [ "$(git log -1 --format='%s' 2>/dev/null)" != "$PIPE_COMMIT_CVEFIX" ] \
|
|
194
|
+
|| [ "$RANGE_HAS_DIFF" != true ] || [ "$RANGE_MANIFEST_ONLY" != true ]; then
|
|
195
|
+
# This range and its dirty tracked files belong to the agent. Restore the
|
|
196
|
+
# checked-out remote tip; do not carry unverified work into a later rebase.
|
|
197
|
+
git reset --hard "$PRE_AGENT_SHA" >/dev/null 2>&1 || git checkout -- . || true
|
|
198
|
+
pipe_failure_log_notice_files "CVE remediation" "update the listed dependencies manually" "$PIPE_AGENT_STDERR" >&2
|
|
199
|
+
{
|
|
200
|
+
pipe_failure_notice_files "CVE remediation" "update the listed dependencies manually" "$PIPE_AGENT_STDERR"
|
|
201
|
+
printf '\n'
|
|
202
|
+
if [ -s "$CVE_LIST_FILE" ]; then
|
|
203
|
+
printf 'Affected HIGH/CRITICAL vulnerability identifiers:\n'
|
|
204
|
+
sed 's/^/- /' "$CVE_LIST_FILE"
|
|
205
|
+
fi
|
|
206
|
+
printf '\nThe coder made no verified remediation commit, so manual dependency update is required.\n'
|
|
207
|
+
} > "$COMMENT_FILE"
|
|
208
|
+
post_comment
|
|
209
|
+
write_marker 0 0 1
|
|
210
|
+
exit 0
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
# The accepted commit is authoritative. Reset index and worktree to it so
|
|
214
|
+
# compile/rebase see exactly what the runner will push; context artifacts stay
|
|
215
|
+
# untracked and are therefore preserved.
|
|
216
|
+
git reset --hard HEAD
|
|
217
|
+
|
|
218
|
+
if [ -z "$PIPE_COMPILE_CMD" ]; then
|
|
219
|
+
pipe_log "Configured compile command is empty; refusing to push an unverified CVE remediation"
|
|
220
|
+
post_manual_comment "The configured compile command is empty, so the automated dependency update cannot be verified."
|
|
221
|
+
write_marker 1 0 1
|
|
222
|
+
exit 1
|
|
223
|
+
fi
|
|
224
|
+
if ! bash -c "$PIPE_COMPILE_CMD"; then
|
|
225
|
+
pipe_log "CVE remediation compile command failed; refusing to push"
|
|
226
|
+
post_manual_comment "The automated dependency update was committed locally but the compile command failed; manual review is required."
|
|
227
|
+
write_marker 1 0 1
|
|
228
|
+
exit 1
|
|
229
|
+
fi
|
|
230
|
+
|
|
231
|
+
if ! pipe_rebase_and_push; then
|
|
232
|
+
pipe_log "CVE remediation rebase/push failed; human work was not overwritten"
|
|
233
|
+
post_manual_comment "The automated dependency update could not be rebased and pushed safely; resolve the branch changes manually."
|
|
234
|
+
write_marker 1 1 1
|
|
235
|
+
exit 1
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
{
|
|
239
|
+
printf '**Automated CVE remediation succeeded.**\n\n'
|
|
240
|
+
printf 'The configured dependency manifest was updated, compiled, rebased, and pushed.\n\n'
|
|
241
|
+
printf 'Remediated HIGH/CRITICAL vulnerability identifiers:\n'
|
|
242
|
+
sed 's/^/- /' "$CVE_LIST_FILE"
|
|
243
|
+
} > "$COMMENT_FILE"
|
|
244
|
+
post_comment
|
|
245
|
+
write_marker 1 1 0
|
|
246
|
+
pipe_log "Pushed verified CVE remediation commit"
|