@stream44.studio/dco 0.3.0-rc.2
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/.dco-signatures +9 -0
- package/.github/workflows/dco.yml +12 -0
- package/.o/GordianOpenIntegrity-CurrentLifehash.svg +1026 -0
- package/.o/GordianOpenIntegrity-InceptionLifehash.svg +1026 -0
- package/.o/GordianOpenIntegrity.yaml +25 -0
- package/DCO.md +34 -0
- package/README.md +122 -0
- package/action.yml +32 -0
- package/caps/Dco.test.ts +288 -0
- package/caps/Dco.ts +269 -0
- package/commit.sh +468 -0
- package/dco.sh +49 -0
- package/examples/01-Lifecycle/main.test.ts +223 -0
- package/package.json +39 -0
- package/test.sh +422 -0
- package/tsconfig.json +28 -0
- package/validate.sh +353 -0
package/tsconfig.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.paths.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "es2021",
|
|
5
|
+
"module": "esnext",
|
|
6
|
+
"lib": [
|
|
7
|
+
"ES2021",
|
|
8
|
+
"DOM"
|
|
9
|
+
],
|
|
10
|
+
"types": [
|
|
11
|
+
"bun",
|
|
12
|
+
"node"
|
|
13
|
+
],
|
|
14
|
+
"moduleResolution": "bundler",
|
|
15
|
+
"strict": true,
|
|
16
|
+
"esModuleInterop": true,
|
|
17
|
+
"skipLibCheck": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true,
|
|
19
|
+
"resolveJsonModule": true,
|
|
20
|
+
"allowSyntheticDefaultImports": true
|
|
21
|
+
},
|
|
22
|
+
"include": [
|
|
23
|
+
"**/*.ts"
|
|
24
|
+
],
|
|
25
|
+
"exclude": [
|
|
26
|
+
"node_modules"
|
|
27
|
+
]
|
|
28
|
+
}
|
package/validate.sh
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# DCO Signature Validator for GitHub Actions
|
|
4
|
+
# ===========================================
|
|
5
|
+
# This script validates that all commits in a PR have proper DCO sign-offs.
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
set -e
|
|
9
|
+
|
|
10
|
+
# Color codes for output
|
|
11
|
+
readonly RED='\033[0;31m'
|
|
12
|
+
readonly GREEN='\033[0;32m'
|
|
13
|
+
readonly YELLOW='\033[1;33m'
|
|
14
|
+
readonly BLUE='\033[0;34m'
|
|
15
|
+
readonly CYAN='\033[0;36m'
|
|
16
|
+
readonly NC='\033[0m' # No Color
|
|
17
|
+
readonly BOLD='\033[1m'
|
|
18
|
+
|
|
19
|
+
# Verbose mode: set VERBOSE=1 or pass --verbose
|
|
20
|
+
VERBOSE="${VERBOSE:-0}"
|
|
21
|
+
ENFORCE_SIGNATURE_FINGERPRINTS=0
|
|
22
|
+
for arg in "$@"; do
|
|
23
|
+
[[ "$arg" == "--verbose" ]] && VERBOSE=1
|
|
24
|
+
[[ "$arg" == "--enforce-signature-fingerprints" ]] && ENFORCE_SIGNATURE_FINGERPRINTS=1
|
|
25
|
+
done
|
|
26
|
+
|
|
27
|
+
verbose_log() {
|
|
28
|
+
if [[ "$VERBOSE" == "1" ]]; then
|
|
29
|
+
echo -e "${YELLOW}[VERBOSE] $*${NC}"
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Determine base and head refs
|
|
34
|
+
# If called from GitHub Actions, use environment variables
|
|
35
|
+
# Otherwise use command line arguments
|
|
36
|
+
if [[ -n "${GITHUB_EVENT_NAME:-}" ]]; then
|
|
37
|
+
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
|
|
38
|
+
BASE_BRANCH="origin/${GITHUB_BASE_REF}"
|
|
39
|
+
HEAD_REF="${GITHUB_HEAD_SHA}"
|
|
40
|
+
else
|
|
41
|
+
# Push event
|
|
42
|
+
if [[ "${GITHUB_BEFORE}" != "0000000000000000000000000000000000000000" ]]; then
|
|
43
|
+
BASE_BRANCH="${GITHUB_BEFORE}"
|
|
44
|
+
HEAD_REF="${GITHUB_SHA}"
|
|
45
|
+
else
|
|
46
|
+
# New branch/repo — validate all commits
|
|
47
|
+
BASE_BRANCH=""
|
|
48
|
+
HEAD_REF="${GITHUB_SHA}"
|
|
49
|
+
fi
|
|
50
|
+
fi
|
|
51
|
+
else
|
|
52
|
+
# Manual invocation
|
|
53
|
+
BASE_BRANCH="${1:-origin/main}"
|
|
54
|
+
HEAD_REF="${2:-HEAD}"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
echo -e "${BOLD}${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
58
|
+
echo -e "${BOLD}${CYAN} DCO Signature Validation${NC}"
|
|
59
|
+
echo -e "${BOLD}${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
60
|
+
echo
|
|
61
|
+
|
|
62
|
+
verbose_log "GITHUB_EVENT_NAME=${GITHUB_EVENT_NAME:-}"
|
|
63
|
+
verbose_log "GITHUB_BASE_REF=${GITHUB_BASE_REF:-}"
|
|
64
|
+
verbose_log "GITHUB_HEAD_SHA=${GITHUB_HEAD_SHA:-}"
|
|
65
|
+
verbose_log "GITHUB_BEFORE=${GITHUB_BEFORE:-}"
|
|
66
|
+
verbose_log "GITHUB_SHA=${GITHUB_SHA:-}"
|
|
67
|
+
verbose_log "BASE_BRANCH=$BASE_BRANCH"
|
|
68
|
+
verbose_log "HEAD_REF=$HEAD_REF"
|
|
69
|
+
verbose_log "Git log (last 10):"
|
|
70
|
+
if [[ "$VERBOSE" == "1" ]]; then
|
|
71
|
+
git log --oneline -10 2>&1 | while IFS= read -r l; do verbose_log " $l"; done
|
|
72
|
+
echo
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# Check if we're in a git repository
|
|
76
|
+
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
|
77
|
+
echo -e "${RED}Error: Not in a git repository${NC}" >&2
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Get list of commits to check
|
|
82
|
+
echo -e "${BLUE}Checking commits between ${BOLD}$BASE_BRANCH${NC}${BLUE} and ${BOLD}$HEAD_REF${NC}"
|
|
83
|
+
echo
|
|
84
|
+
|
|
85
|
+
# Get the commit range
|
|
86
|
+
if [[ -n "$BASE_BRANCH" ]]; then
|
|
87
|
+
COMMITS=$(git rev-list "$BASE_BRANCH..$HEAD_REF" 2>/dev/null || git rev-list "$HEAD_REF")
|
|
88
|
+
else
|
|
89
|
+
# No base branch (new repo/branch) — validate all commits
|
|
90
|
+
COMMITS=$(git rev-list "$HEAD_REF")
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
if [[ -z "$COMMITS" ]]; then
|
|
94
|
+
echo -e "${GREEN}✓ No commits to validate${NC}"
|
|
95
|
+
exit 0
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
COMMIT_COUNT=$(echo "$COMMITS" | wc -l | tr -d ' ')
|
|
99
|
+
echo -e "${BLUE}Found ${BOLD}$COMMIT_COUNT${NC}${BLUE} commit(s) to validate${NC}"
|
|
100
|
+
echo
|
|
101
|
+
|
|
102
|
+
# Track validation status
|
|
103
|
+
FAILED_COMMITS=()
|
|
104
|
+
VALID_COMMITS=0
|
|
105
|
+
|
|
106
|
+
# Validate each commit
|
|
107
|
+
while IFS= read -r commit; do
|
|
108
|
+
# Get commit info
|
|
109
|
+
commit_short=$(git rev-parse --short "$commit")
|
|
110
|
+
commit_author=$(git log -1 --format='%an' "$commit")
|
|
111
|
+
commit_email=$(git log -1 --format='%ae' "$commit")
|
|
112
|
+
commit_subject=$(git log -1 --format='%s' "$commit")
|
|
113
|
+
commit_body=$(git log -1 --format='%b' "$commit")
|
|
114
|
+
|
|
115
|
+
# Check for Signed-off-by trailer
|
|
116
|
+
signoff_line=$(echo "$commit_body" | grep -i "^Signed-off-by:" | head -1 || true)
|
|
117
|
+
|
|
118
|
+
if [[ -z "$signoff_line" ]]; then
|
|
119
|
+
# No sign-off found
|
|
120
|
+
FAILED_COMMITS+=("$commit")
|
|
121
|
+
echo -e "${RED}✗ FAIL${NC} $commit_short - ${YELLOW}$commit_subject${NC}"
|
|
122
|
+
echo -e " Author: $commit_author <$commit_email>"
|
|
123
|
+
echo -e " ${RED}Missing: Signed-off-by trailer${NC}"
|
|
124
|
+
echo
|
|
125
|
+
else
|
|
126
|
+
# Validate that the sign-off matches the author
|
|
127
|
+
signoff_name=$(echo "$signoff_line" | sed 's/^Signed-off-by: //' | sed 's/ <.*//')
|
|
128
|
+
signoff_email=$(echo "$signoff_line" | sed 's/.*<\(.*\)>/\1/')
|
|
129
|
+
|
|
130
|
+
if [[ "$signoff_name" != "$commit_author" ]] || [[ "$signoff_email" != "$commit_email" ]]; then
|
|
131
|
+
# Sign-off doesn't match author
|
|
132
|
+
FAILED_COMMITS+=("$commit")
|
|
133
|
+
echo -e "${RED}✗ FAIL${NC} $commit_short - ${YELLOW}$commit_subject${NC}"
|
|
134
|
+
echo -e " Author: $commit_author <$commit_email>"
|
|
135
|
+
echo -e " Signed-off: $signoff_name <$signoff_email>"
|
|
136
|
+
echo -e " ${RED}Mismatch: Sign-off must match commit author${NC}"
|
|
137
|
+
echo
|
|
138
|
+
else
|
|
139
|
+
# Valid sign-off
|
|
140
|
+
((VALID_COMMITS++)) || true
|
|
141
|
+
echo -e "${GREEN}✓ PASS${NC} $commit_short - $commit_subject"
|
|
142
|
+
echo -e " Signed-off-by: $signoff_name <$signoff_email>"
|
|
143
|
+
echo
|
|
144
|
+
fi
|
|
145
|
+
fi
|
|
146
|
+
done <<< "$COMMITS"
|
|
147
|
+
|
|
148
|
+
# Print summary
|
|
149
|
+
echo -e "${BOLD}${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
150
|
+
echo -e "${BOLD}${CYAN} Validation Summary${NC}"
|
|
151
|
+
echo -e "${BOLD}${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
152
|
+
echo
|
|
153
|
+
|
|
154
|
+
# Validate .dco-signatures entries
|
|
155
|
+
SIG_FILE_VALID=true
|
|
156
|
+
GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
|
157
|
+
SIG_FILE="$GIT_ROOT/.dco-signatures"
|
|
158
|
+
|
|
159
|
+
if [[ -f "$SIG_FILE" ]]; then
|
|
160
|
+
echo
|
|
161
|
+
echo -e "${BOLD}${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
162
|
+
echo -e "${BOLD}${CYAN} DCO Signature File Validation${NC}"
|
|
163
|
+
echo -e "${BOLD}${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
164
|
+
echo
|
|
165
|
+
|
|
166
|
+
while IFS= read -r line; do
|
|
167
|
+
# Skip empty lines, comments, headers, and separator
|
|
168
|
+
[[ -z "$line" ]] && continue
|
|
169
|
+
[[ "$line" =~ ^# ]] && continue
|
|
170
|
+
[[ "$line" =~ ^--- ]] && continue
|
|
171
|
+
[[ "$line" == "This "* ]] && continue
|
|
172
|
+
[[ "$line" == "Each "* ]] && continue
|
|
173
|
+
[[ "$line" == "Format:"* ]] && continue
|
|
174
|
+
|
|
175
|
+
# Parse signature line: name <email> | signed: <date> | agreement: <commit> (<dco_change_date>)
|
|
176
|
+
sig_identity=$(echo "$line" | sed 's/ | signed:.*//')
|
|
177
|
+
sig_agreement_commit=$(echo "$line" | sed -n 's/.*| agreement: \([a-f0-9]*\).*/\1/p')
|
|
178
|
+
|
|
179
|
+
if [[ -z "$sig_agreement_commit" ]]; then
|
|
180
|
+
echo -e "${RED}✗ FAIL${NC} $sig_identity"
|
|
181
|
+
echo -e " ${RED}Missing agreement commit reference in signature${NC}"
|
|
182
|
+
SIG_FILE_VALID=false
|
|
183
|
+
continue
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# Verify the commit exists
|
|
187
|
+
if ! git cat-file -e "$sig_agreement_commit" 2>/dev/null; then
|
|
188
|
+
echo -e "${RED}✗ FAIL${NC} $sig_identity"
|
|
189
|
+
echo -e " ${RED}Agreement commit $sig_agreement_commit does not exist${NC}"
|
|
190
|
+
SIG_FILE_VALID=false
|
|
191
|
+
continue
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
# Verify DCO.md was present in that commit
|
|
195
|
+
if ! git show "$sig_agreement_commit:DCO.md" >/dev/null 2>&1; then
|
|
196
|
+
echo -e "${RED}✗ FAIL${NC} $sig_identity"
|
|
197
|
+
echo -e " ${RED}DCO.md not found in commit $sig_agreement_commit${NC}"
|
|
198
|
+
SIG_FILE_VALID=false
|
|
199
|
+
continue
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
echo -e "${GREEN}✓ PASS${NC} $sig_identity"
|
|
203
|
+
echo -e " Agreement commit: ${CYAN}$(git rev-parse --short "$sig_agreement_commit")${NC}"
|
|
204
|
+
done < "$SIG_FILE"
|
|
205
|
+
echo
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
# ── SSH Signature Fingerprint Enforcement (--enforce-signature-fingerprints) ──
|
|
209
|
+
SIG_VALIDATION_FAILED=false
|
|
210
|
+
if [[ "$ENFORCE_SIGNATURE_FINGERPRINTS" == "1" ]]; then
|
|
211
|
+
echo
|
|
212
|
+
echo -e "${BOLD}${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
213
|
+
echo -e "${BOLD}${CYAN} Enforce Signature Fingerprints${NC}"
|
|
214
|
+
echo -e "${BOLD}${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
215
|
+
echo
|
|
216
|
+
|
|
217
|
+
# Build a map of contributor email → expected fingerprint from .dco-signatures
|
|
218
|
+
declare -A EXPECTED_FINGERPRINTS
|
|
219
|
+
if [[ -f "$SIG_FILE" ]]; then
|
|
220
|
+
while IFS= read -r line; do
|
|
221
|
+
[[ -z "$line" ]] && continue
|
|
222
|
+
[[ "$line" =~ ^# ]] && continue
|
|
223
|
+
[[ "$line" =~ ^--- ]] && continue
|
|
224
|
+
[[ "$line" == "This "* ]] && continue
|
|
225
|
+
[[ "$line" == "Each "* ]] && continue
|
|
226
|
+
[[ "$line" == "Format:"* ]] && continue
|
|
227
|
+
|
|
228
|
+
# Extract email and fingerprint
|
|
229
|
+
local_email=$(echo "$line" | sed -n 's/.*<\(.*\)>.*/\1/p')
|
|
230
|
+
local_fp=$(echo "$line" | sed -n 's/.*| signature: \([^ ]*\).*/\1/p')
|
|
231
|
+
if [[ -n "$local_email" ]] && [[ -n "$local_fp" ]]; then
|
|
232
|
+
EXPECTED_FINGERPRINTS["$local_email"]="$local_fp"
|
|
233
|
+
verbose_log "Expected fingerprint for $local_email: $local_fp"
|
|
234
|
+
elif [[ -n "$local_email" ]]; then
|
|
235
|
+
echo -e "${RED}✗ FAIL${NC} Contributor $local_email has no signature fingerprint in .dco-signatures"
|
|
236
|
+
SIG_VALIDATION_FAILED=true
|
|
237
|
+
fi
|
|
238
|
+
done < "$SIG_FILE"
|
|
239
|
+
else
|
|
240
|
+
echo -e "${RED}✗ FAIL${NC} --enforce-signature-fingerprints specified but .dco-signatures file not found"
|
|
241
|
+
SIG_VALIDATION_FAILED=true
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
# Verify each commit has a valid SSH signature matching the expected fingerprint
|
|
245
|
+
if [[ "$SIG_VALIDATION_FAILED" == "false" ]]; then
|
|
246
|
+
while IFS= read -r commit; do
|
|
247
|
+
commit_short=$(git rev-parse --short "$commit")
|
|
248
|
+
commit_email=$(git log -1 --format='%ae' "$commit")
|
|
249
|
+
commit_subject=$(git log -1 --format='%s' "$commit")
|
|
250
|
+
|
|
251
|
+
# Get the SSH signature fingerprint from the commit
|
|
252
|
+
sig_output=$(git log -1 --format='%GK' "$commit" 2>/dev/null || true)
|
|
253
|
+
sig_status=$(git log -1 --format='%G?' "$commit" 2>/dev/null || true)
|
|
254
|
+
|
|
255
|
+
verbose_log "Commit $commit_short: sig_status=$sig_status sig_key=$sig_output email=$commit_email"
|
|
256
|
+
|
|
257
|
+
if [[ -z "$sig_output" ]] || [[ "$sig_status" == "N" ]]; then
|
|
258
|
+
echo -e "${RED}✗ FAIL${NC} $commit_short - ${YELLOW}$commit_subject${NC}"
|
|
259
|
+
echo -e " ${RED}Missing SSH signature on commit${NC}"
|
|
260
|
+
SIG_VALIDATION_FAILED=true
|
|
261
|
+
continue
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
# Check if we have an expected fingerprint for this contributor
|
|
265
|
+
expected_fp="${EXPECTED_FINGERPRINTS[$commit_email]:-}"
|
|
266
|
+
if [[ -n "$expected_fp" ]]; then
|
|
267
|
+
# Compare the fingerprint from the commit signature with the expected one
|
|
268
|
+
if [[ "$sig_output" == "$expected_fp" ]]; then
|
|
269
|
+
echo -e "${GREEN}✓ PASS${NC} $commit_short - $commit_subject"
|
|
270
|
+
echo -e " SSH signature: ${CYAN}$sig_output${NC}"
|
|
271
|
+
else
|
|
272
|
+
echo -e "${RED}✗ FAIL${NC} $commit_short - ${YELLOW}$commit_subject${NC}"
|
|
273
|
+
echo -e " Expected fingerprint: ${CYAN}$expected_fp${NC}"
|
|
274
|
+
echo -e " Actual fingerprint: ${CYAN}$sig_output${NC}"
|
|
275
|
+
echo -e " ${RED}SSH signature fingerprint mismatch${NC}"
|
|
276
|
+
SIG_VALIDATION_FAILED=true
|
|
277
|
+
fi
|
|
278
|
+
else
|
|
279
|
+
# No expected fingerprint for this email — just verify it has a signature
|
|
280
|
+
if [[ "$sig_status" == "G" ]] || [[ "$sig_status" == "U" ]]; then
|
|
281
|
+
echo -e "${GREEN}✓ PASS${NC} $commit_short - $commit_subject"
|
|
282
|
+
echo -e " SSH signature: ${CYAN}$sig_output${NC} (no fingerprint in .dco-signatures to cross-check)"
|
|
283
|
+
else
|
|
284
|
+
echo -e "${RED}✗ FAIL${NC} $commit_short - ${YELLOW}$commit_subject${NC}"
|
|
285
|
+
echo -e " ${RED}Invalid SSH signature (status: $sig_status)${NC}"
|
|
286
|
+
SIG_VALIDATION_FAILED=true
|
|
287
|
+
fi
|
|
288
|
+
fi
|
|
289
|
+
done <<< "$COMMITS"
|
|
290
|
+
fi
|
|
291
|
+
echo
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
if [[ ${#FAILED_COMMITS[@]} -eq 0 ]] && [[ "$SIG_FILE_VALID" == "true" ]] && [[ "$SIG_VALIDATION_FAILED" == "false" ]]; then
|
|
295
|
+
echo -e "${GREEN}${BOLD}✓ All commits are properly signed!${NC}"
|
|
296
|
+
echo -e "${GREEN} Valid commits: $VALID_COMMITS/$COMMIT_COUNT${NC}"
|
|
297
|
+
if [[ "$ENFORCE_SIGNATURE_FINGERPRINTS" == "1" ]]; then
|
|
298
|
+
echo -e "${GREEN} Signature fingerprints: enforced${NC}"
|
|
299
|
+
fi
|
|
300
|
+
echo
|
|
301
|
+
exit 0
|
|
302
|
+
else
|
|
303
|
+
echo -e "${RED}${BOLD}✗ DCO validation failed!${NC}"
|
|
304
|
+
echo -e "${RED} Valid commits: $VALID_COMMITS/$COMMIT_COUNT${NC}"
|
|
305
|
+
echo -e "${RED} Invalid commits: ${#FAILED_COMMITS[@]}/$COMMIT_COUNT${NC}"
|
|
306
|
+
echo
|
|
307
|
+
echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
308
|
+
echo -e "${YELLOW} How to Fix${NC}"
|
|
309
|
+
echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
310
|
+
echo
|
|
311
|
+
echo -e "${BLUE}Step 1: Revert the last commit and restore changes to working copy${NC}"
|
|
312
|
+
echo -e " ${BOLD}git reset HEAD~1${NC}"
|
|
313
|
+
echo -e " (This undoes the commit and unstages your changes)"
|
|
314
|
+
echo
|
|
315
|
+
echo -e "${BLUE}Step 2: Choose one of the following options:${NC}"
|
|
316
|
+
echo
|
|
317
|
+
echo -e "${BLUE}Option A: Use the commit wrapper script (recommended)${NC}"
|
|
318
|
+
echo -e " 1. Stage your changes:"
|
|
319
|
+
echo -e " ${BOLD}git add .${NC} (or stage specific files)"
|
|
320
|
+
echo
|
|
321
|
+
echo -e " 2. Commit with the wrapper script:"
|
|
322
|
+
echo -e " ${BOLD}./commit.sh -m \"Your commit message\"${NC}"
|
|
323
|
+
echo
|
|
324
|
+
echo -e " This will:"
|
|
325
|
+
echo -e " • Automatically add the sign-off to your commit"
|
|
326
|
+
echo -e " • Update the .dco-signatures file (if first time)"
|
|
327
|
+
echo -e " • Create a DCO signature commit"
|
|
328
|
+
echo
|
|
329
|
+
echo -e "${BLUE}Option B: Add sign-off manually${NC}"
|
|
330
|
+
echo -e " 1. Update .dco-signatures file manually:"
|
|
331
|
+
echo -e " Add this entry to ${BOLD}.dco-signatures${NC}:"
|
|
332
|
+
echo -e " ${CYAN}**Your Name** <your@email.com>${NC}"
|
|
333
|
+
echo -e " ${CYAN}Signed: $(date -u +"%Y-%m-%d %H:%M:%S UTC")${NC}"
|
|
334
|
+
echo
|
|
335
|
+
echo -e " 2. Stage ONLY the signatures file:"
|
|
336
|
+
echo -e " ${BOLD}git add .dco-signatures${NC}"
|
|
337
|
+
echo
|
|
338
|
+
echo -e " 3. Commit the signature record with sign-off:"
|
|
339
|
+
echo -e " ${BOLD}git commit -s -m \"DCO: Add signature for Your Name <your@email.com>\"${NC}"
|
|
340
|
+
echo
|
|
341
|
+
echo -e " 4. Stage your original changes:"
|
|
342
|
+
echo -e " ${BOLD}git add .${NC} (or stage specific files)"
|
|
343
|
+
echo
|
|
344
|
+
echo -e " 5. Commit your original changes with sign-off:"
|
|
345
|
+
echo -e " ${BOLD}git commit -s -m \"Your original commit message\"${NC}"
|
|
346
|
+
echo
|
|
347
|
+
echo -e "${BLUE}What is a DCO signature?${NC}"
|
|
348
|
+
echo -e " A DCO (Developer Certificate of Origin) is your certification that you"
|
|
349
|
+
echo -e " have the right to submit your contribution under the project's license."
|
|
350
|
+
echo -e " See: ${CYAN}https://developercertificate.org/${NC}"
|
|
351
|
+
echo
|
|
352
|
+
exit 1
|
|
353
|
+
fi
|