@stream44.studio/dco 0.3.0-rc.3 → 0.3.0-rc.4

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.
Files changed (3) hide show
  1. package/package.json +3 -3
  2. package/test.sh +25 -2
  3. package/validate.sh +41 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream44.studio/dco",
3
- "version": "0.3.0-rc.3",
3
+ "version": "0.3.0-rc.4",
4
4
  "description": "Developer Certificate of Origin (DCO) tools for signing & verifying.",
5
5
  "private": false,
6
6
  "keywords": [
@@ -28,8 +28,8 @@
28
28
  "validate": "./validate.sh"
29
29
  },
30
30
  "dependencies": {
31
- "@stream44.studio/encapsulate": "^0.4.0-rc.3",
32
- "t44": "^0.4.0-rc.3"
31
+ "@stream44.studio/encapsulate": "^0.4.0-rc.4",
32
+ "t44": "^0.4.0-rc.4"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/bun": "^1.3.4",
package/test.sh CHANGED
@@ -389,8 +389,31 @@ fi
389
389
  echo -e "${GREEN}✓ --enforce-signature-fingerprints correctly fails on unsigned commits${NC}"
390
390
  echo
391
391
 
392
- # Test validate.sh --enforce-signature-fingerprints on the signed repo (should pass)
393
- echo -e "${BOLD}${YELLOW}Testing --enforce-signature-fingerprints on signed repo...${NC}"
392
+ # Test validate.sh --enforce-signature-fingerprints on the signed repo WITHOUT allowedSignersFile
393
+ # This simulates the GitHub Actions environment where gpg.ssh.allowedSignersFile is not configured.
394
+ # The fix extracts SSH fingerprints directly from raw commit objects instead of relying on %G?/%GK.
395
+ echo -e "${BOLD}${YELLOW}Testing --enforce-signature-fingerprints WITHOUT allowedSignersFile (GitHub Actions scenario)...${NC}"
396
+ cd "$SIGNED_REPO"
397
+
398
+ # Ensure allowedSignersFile is NOT set (simulates GitHub Actions)
399
+ git config --unset gpg.ssh.allowedSignersFile 2>/dev/null || true
400
+
401
+ VALIDATE_OUTPUT=$(./validate.sh "" HEAD --enforce-signature-fingerprints 2>&1) || {
402
+ echo -e "${RED}✗ FAIL: --enforce-signature-fingerprints should pass without allowedSignersFile${NC}"
403
+ echo "$VALIDATE_OUTPUT"
404
+ exit 1
405
+ }
406
+ echo "$VALIDATE_OUTPUT"
407
+
408
+ if ! echo "$VALIDATE_OUTPUT" | grep -q "Signature fingerprints: enforced"; then
409
+ echo -e "${RED}✗ FAIL: Output should contain 'Signature fingerprints: enforced'${NC}"
410
+ exit 1
411
+ fi
412
+ echo -e "${GREEN}✓ --enforce-signature-fingerprints passes WITHOUT allowedSignersFile (raw commit extraction)${NC}"
413
+ echo
414
+
415
+ # Test validate.sh --enforce-signature-fingerprints on the signed repo WITH allowedSignersFile
416
+ echo -e "${BOLD}${YELLOW}Testing --enforce-signature-fingerprints on signed repo (with allowedSignersFile)...${NC}"
394
417
  cd "$SIGNED_REPO"
395
418
 
396
419
  # Set up allowed signers for git to verify SSH signatures
package/validate.sh CHANGED
@@ -241,6 +241,38 @@ if [[ "$ENFORCE_SIGNATURE_FINGERPRINTS" == "1" ]]; then
241
241
  SIG_VALIDATION_FAILED=true
242
242
  fi
243
243
 
244
+ # Extract the SSH signing fingerprint directly from the raw commit object.
245
+ # This avoids depending on gpg.ssh.allowedSignersFile which is typically
246
+ # not configured on GitHub Actions runners, causing %G? to report 'N'
247
+ # even when the commit contains a valid SSH signature.
248
+ extract_ssh_fingerprint() {
249
+ local commit_hash="$1"
250
+ local raw_commit
251
+ raw_commit=$(git cat-file commit "$commit_hash" 2>/dev/null)
252
+
253
+ # Check if the commit contains an SSH signature
254
+ if ! echo "$raw_commit" | grep -q "BEGIN SSH SIGNATURE"; then
255
+ echo ""
256
+ return
257
+ fi
258
+
259
+ # Extract the signature block, decode it, and compute the public key fingerprint
260
+ local sig_pem
261
+ sig_pem=$(echo "$raw_commit" | sed -n '/-----BEGIN SSH SIGNATURE-----/,/-----END SSH SIGNATURE-----/p' | sed 's/^gpgsig //' | sed 's/^ //')
262
+
263
+ python3 -c "
264
+ import base64, hashlib, struct, sys
265
+ lines = [l for l in sys.stdin.read().strip().split('\n') if not l.startswith('-----')]
266
+ raw = base64.b64decode(''.join(lines))
267
+ # SSHSIG format: magic 'SSHSIG' (6) + version uint32 (4) + public key string
268
+ idx = 10
269
+ pk_len = struct.unpack('>I', raw[idx:idx+4])[0]
270
+ pk_blob = raw[idx+4:idx+4+pk_len]
271
+ fp = base64.b64encode(hashlib.sha256(pk_blob).digest()).decode().rstrip('=')
272
+ print(f'SHA256:{fp}')
273
+ " <<< "$sig_pem"
274
+ }
275
+
244
276
  # Verify each commit has a valid SSH signature matching the expected fingerprint
245
277
  if [[ "$SIG_VALIDATION_FAILED" == "false" ]]; then
246
278
  while IFS= read -r commit; do
@@ -248,13 +280,12 @@ if [[ "$ENFORCE_SIGNATURE_FINGERPRINTS" == "1" ]]; then
248
280
  commit_email=$(git log -1 --format='%ae' "$commit")
249
281
  commit_subject=$(git log -1 --format='%s' "$commit")
250
282
 
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)
283
+ # Extract the SSH signature fingerprint directly from the raw commit
284
+ sig_fingerprint=$(extract_ssh_fingerprint "$commit")
254
285
 
255
- verbose_log "Commit $commit_short: sig_status=$sig_status sig_key=$sig_output email=$commit_email"
286
+ verbose_log "Commit $commit_short: sig_fingerprint=$sig_fingerprint email=$commit_email"
256
287
 
257
- if [[ -z "$sig_output" ]] || [[ "$sig_status" == "N" ]]; then
288
+ if [[ -z "$sig_fingerprint" ]]; then
258
289
  echo -e "${RED}✗ FAIL${NC} $commit_short - ${YELLOW}$commit_subject${NC}"
259
290
  echo -e " ${RED}Missing SSH signature on commit${NC}"
260
291
  SIG_VALIDATION_FAILED=true
@@ -265,26 +296,20 @@ if [[ "$ENFORCE_SIGNATURE_FINGERPRINTS" == "1" ]]; then
265
296
  expected_fp="${EXPECTED_FINGERPRINTS[$commit_email]:-}"
266
297
  if [[ -n "$expected_fp" ]]; then
267
298
  # Compare the fingerprint from the commit signature with the expected one
268
- if [[ "$sig_output" == "$expected_fp" ]]; then
299
+ if [[ "$sig_fingerprint" == "$expected_fp" ]]; then
269
300
  echo -e "${GREEN}✓ PASS${NC} $commit_short - $commit_subject"
270
- echo -e " SSH signature: ${CYAN}$sig_output${NC}"
301
+ echo -e " SSH signature: ${CYAN}$sig_fingerprint${NC}"
271
302
  else
272
303
  echo -e "${RED}✗ FAIL${NC} $commit_short - ${YELLOW}$commit_subject${NC}"
273
304
  echo -e " Expected fingerprint: ${CYAN}$expected_fp${NC}"
274
- echo -e " Actual fingerprint: ${CYAN}$sig_output${NC}"
305
+ echo -e " Actual fingerprint: ${CYAN}$sig_fingerprint${NC}"
275
306
  echo -e " ${RED}SSH signature fingerprint mismatch${NC}"
276
307
  SIG_VALIDATION_FAILED=true
277
308
  fi
278
309
  else
279
310
  # 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
311
+ echo -e "${GREEN}✓ PASS${NC} $commit_short - $commit_subject"
312
+ echo -e " SSH signature: ${CYAN}$sig_fingerprint${NC} (no fingerprint in .dco-signatures to cross-check)"
288
313
  fi
289
314
  done <<< "$COMMITS"
290
315
  fi