Repository navigation
Expand file tree
/
Copy pathcodedelta.gitlab-ci.yml
More file actions
86 lines (85 loc) · 5.83 KB
/
Copy pathcodedelta.gitlab-ci.yml
File metadata and controls
86 lines (85 loc) · 5.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# CodeDelta for GitLab CI — churn + Agent Scan on every merge request.
#
# Quick start: copy this job into your .gitlab-ci.yml (or `include:` this file).
# No licence needed during the free-trial period — the bundled trial licence is
# used (valid to 2026-12-31). To use your own: set a masked CI/CD variable
# CODEDELTA_LICENSE to the base64 of your codedelta.lic.
#
# MR comment (optional): set CODEDELTA_GITLAB_TOKEN to a Project Access Token
# (role Reporter+, scope `api`) and the job posts/updates a summary note on the MR.
# Without it you still get the full HTML/CSV/JSON reports as job artifacts.
#
# Docs: https://codedelta.app/cli.html Engine: gated by licence, download is public.
codedelta:
image: ubuntu:24.04
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
variables:
GIT_DEPTH: "0" # full history so base..head churn works
CD_MODE: "churn_agent" # churn + Agent Scan (add the ML audit with "both")
CD_THRESHOLD: "50"
script:
- apt-get update -qq && apt-get install -y -qq curl git ca-certificates jq > /dev/null
- curl -fsSL -o /tmp/cd.tar.gz "${CODEDELTA_ENGINE_URL:-https://github.com/code-delta-app/releases/releases/latest/download/codedelta-linux-full.tar.gz}"
- mkdir -p /opt/codedelta && tar -xzf /tmp/cd.tar.gz -C /opt/codedelta --strip-components=1
- |
if [ -n "$CODEDELTA_LICENSE" ]; then
echo "$CODEDELTA_LICENSE" | base64 -d > /tmp/codedelta.lic
else
echo "No licence supplied - using the built-in evaluation licence (valid to 2026-12-31)."
echo "ewogICJjb2RlZGVsdGFfdmVyc2lvbiI6ICIxLjkuNSIsCiAgImV4cGlyeSI6ICIyMDI2LTEyLTMxIiwKICAiaG9zdCI6IG51bGwsCiAgImlzc3VlZCI6ICIyMDI2LTEwLTA2IiwKICAibGljZW5zZV92ZXJzaW9uIjogIjEuMCIsCiAgIm5vdGUiOiAiIiwKICAic2VhdHMiOiAidW5saW1pdGVkIiwKICAic2lnbmF0dXJlIjogIlE4c1lIN3k3aGI1aktPN0lQVUxTbWd5SVpPVThDQzdVc0t6U3dSYlEyOFVCWTNrZStGRWk0V09WU1VIbXYveUF3L0ZmVHVFSWF2SmhhTlRON0NwSGt1VUZuTVErVUFkLzBOR1YwNUZvSDR1THl3bC9XNXdnYmpsUndGMGVDem9BQmFmTXFPSW0xV0JNL2l3R2VWR3c0M2FpVFJKcnVxL3RDYitydUVQaG1XVTNyeGhaU1o3a2M4cnBrRXdzNWxGTGZ6UWlvdGJhbXdDZWJWbkdiYmpnZkFUdU1LQ0xyTlh5eC9jdjQ2czJENkJCQk1iL21PWnhod1ltcVltdjBmZUtIbmk5SXZubkdoUlErVkp0UUoxbGhkTEdHRm5XM0g0OGtRWWk1MlArbnY5a0pOdWRvYzlzVktFcU5XSWxZbFF6SkZ5aWZQVUJLTm13dTRwT3hwR2FJa3plUjNwN1hENW1BNnJ5dXlIbmlSM2lWak5TOGNiazVDaGxLbTU5MkJjZjFVcFJwUjdNNXhvdDhTMFlRbFl0bGFvK0N2Mi9lWUJIWDlUeTVSTW9uYjYvY0lEYlc5VmZCc3pnNWxEaWMyOGluTVlVdGJlWmEzcWo3SnhLTnRCajFUaGtlUVBRMi80QmNPaWZETURHWDJtVytHdzk3b1BlUFRtd21VeUkxNE01IiwKICAidHlwZSI6ICJ0aW1lZCIKfQo=" | base64 -d > /tmp/codedelta.lic
fi
export CODEDELTA_LICENSE=/tmp/codedelta.lic
- |
# Churn needs two versions: materialise the MR diff base as a second tree.
TARGETS="."
if [ -n "$CI_MERGE_REQUEST_DIFF_BASE_SHA" ]; then
git fetch --no-tags origin "$CI_MERGE_REQUEST_DIFF_BASE_SHA" || true
if git worktree add /tmp/cd-base "$CI_MERGE_REQUEST_DIFF_BASE_SHA"; then
TARGETS=". /tmp/cd-base"
fi
fi
# codedelta-gui is the frozen CLI binary - run it directly (paths must not contain spaces)
# Reports go OUTSIDE the project, then are copied back for the artifacts: written inside it, they were scanned as
# part of the change (a false Threat Index alarm on CodeDelta's own reports, 17 Oct 2026).
/opt/codedelta/codedelta-gui scan $TARGETS --mode "$CD_MODE" --threshold "$CD_THRESHOLD" \
--out-dir /tmp/cd-out --html --json --csv --pr-comment || CD_RC=$?
mkdir -p cd-out && cp -R /tmp/cd-out/. cd-out/
# exit 3 = findings gate (only meaningful with --fail-on-new); anything else non-zero is a real error
if [ "${CD_RC:-0}" != "0" ] && [ "${CD_RC:-0}" != "3" ]; then exit "${CD_RC}"; fi
- |
# Post/update the MR summary note (needs CODEDELTA_GITLAB_TOKEN, scope api)
# A token copied from a web page often carries a trailing line break; curl then rejects the header (17 Oct 2026).
TOKEN=$(printf '%s' "${CODEDELTA_GITLAB_TOKEN:-}" | tr -d '[:space:]')
if [ -n "$TOKEN" ] && [ -n "$CI_MERGE_REQUEST_IID" ]; then
MD=$(ls cd-out/*_pr_comment.md 2>/dev/null | head -1)
if [ -n "$MD" ]; then
MARKER="<!-- codedelta -->"
BODY=$(printf '%s\n%s' "$MARKER" "$(cat "$MD")")
API="$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes"
# Only OUR earlier note: it starts with the marker AND was written by this token's account. A text search matched
# other people's notes that mention "codedelta" (GitLab Duo's) and built a broken URL (17 Oct 2026).
ME=$(curl -fsS --header "PRIVATE-TOKEN: $TOKEN" "$CI_API_V4_URL/user" 2>/dev/null | jq -r '.id // empty' 2>/dev/null || true)
EXISTING=""
if [ -n "$ME" ]; then
EXISTING=$( (curl -fsS --header "PRIVATE-TOKEN: $TOKEN" "$API?per_page=100&sort=asc" || true) \
| jq -r --arg m "$MARKER" --argjson me "$ME" '[.[] | select(.author.id == $me and (.body | startswith($m)))] | .[0].id // empty' 2>/dev/null || true)
fi
if [ -n "$EXISTING" ]; then
curl -fsS --request PUT --header "PRIVATE-TOKEN: $TOKEN" \
"$API/$EXISTING" --data-urlencode "body=$BODY" > /dev/null && echo "MR note updated" \
|| echo "WARNING: could not update the MR note (check the token's api scope) - reports are in the job artifacts"
else
curl -fsS --request POST --header "PRIVATE-TOKEN: $TOKEN" \
"$API" --data-urlencode "body=$BODY" > /dev/null && echo "MR note posted" \
|| echo "WARNING: could not post the MR note (check the token's api scope) - reports are in the job artifacts"
fi
fi
else
echo "CODEDELTA_GITLAB_TOKEN not set - skipping MR note (reports are in the job artifacts)"
fi
artifacts:
when: always
paths:
- cd-out/
expire_in: 30 days