Address review nits in sha256convert · Entire

Address review nits in sha256convert

f980228→main· nodo·1mo ago·1 file·+52 added/-18

Sessions

Transcript data is unavailable for this checkpoint.

Changes

1

146 unmodified lines

147
148
149
150
150
151
152
153
154
155
156
291 unmodified lines

448
449
450
448
449
450
451
452
453
454
455
456
457
458
459
460
539 unmodified lines

1000
1001
1002
996
1003
1004
1005
1006
1007
1008
998
999
1000
1009
1010
1011
49 unmodified lines

1061
1062
1063
1056
1064
1065
1066
1067
1058
1059
1060
1068
1069
1070
10 unmodified lines

1081
1082
1083
1077
1078
1079
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
41 unmodified lines

1135
1136
1137
1128
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
153 unmodified lines

1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
50 unmodified lines

1371
1372
1373
1344
1345
1374
1375
1376
1377
1378
1379
1380
1381
1382

146 unmodified lines

fmt.Sprintf("refs written: %d", r.RefsConverted),
}
if r.SignaturesStripped > 0 {
 lines = append(lines, fmt.Sprintf("warning: stripped %d GPG signature(s); they no longer match the rewritten object content", r.SignaturesStripped))
 // Mixes commit/tag signatures (GPG/SSH/X.509) and embedded
 // mergetag headers — each counts as one signed artifact whose
 // signature became invalid post-rewrite.
 lines = append(lines, fmt.Sprintf("warning: stripped %d signature(s) / mergetag header(s); they no longer match the rewritten object content", r.SignaturesStripped))
}
if r.MessageRewrites > 0 {
 lines = append(lines, fmt.Sprintf("rewrote %d SHA1 hash reference(s) in commit/tag messages", r.MessageRewrites))
291 unmodified lines

args = append(args, tagName, refName)

cmd := exec.CommandContext(ctx, gitBin, args...)
 // Inherit stdio so gpg/ssh-agent passphrase prompts work. We
 // intentionally do not capture stdout/stderr — the user needs
 // to see them when authenticating.
 // Deliberate departure from the req.Out plumbing the rest of
 // Run uses: gpg/ssh-agent and pinentry need a real TTY for
 // passphrase prompts, so we inherit the parent's stdio
 // directly. The consequence is that callers passing
 // req.Out = io.Discard (e.g. tests) still see subprocess
 // output on real stderr — that's the cost of working
 // authentication.
 cmd.Stdin = os.Stdin
 cmd.Stdout = os.Stderr // git tag -s is usually quiet on success
 cmd.Stderr = os.Stderr
539 unmodified lines

t.messageRewrites += n
}
}
if c.Signature != "" {
 // A commit can carry both Signature (SHA1 form, "gpgsig") and
 // SignatureSHA256 ("gpgsig-sha256") in a transitional dual-hash
 // repo, but they encode the same logical signature. Strip both
 // fields if present, count once.
 if c.Signature != "" || c.SignatureSHA256 != "" {
 c.Signature = ""
 t.signaturesStripped++
}
 if c.SignatureSHA256 != "" {
 c.SignatureSHA256 = ""
 t.signaturesStripped++
}
49 unmodified lines

t.messageRewrites += n
}
}
if tag.Signature != "" {
 // Same as commits: Signature and SignatureSHA256 are two encodings
 // of the same logical signature in a transitional dual-hash repo.
 if tag.Signature != "" || tag.SignatureSHA256 != "" {
 tag.Signature = ""
 t.signaturesStripped++
}
 if tag.SignatureSHA256 != "" {
 tag.SignatureSHA256 = ""
 t.signaturesStripped++
}
10 unmodified lines

return newHash, nil
}

// encodeBody runs an object's go-git Encode method into a SHA1-hasher
// MemoryObject (the hasher we use to capture bytes is irrelevant; we only
// read the body back out) and returns just the payload bytes — without the
// encodeBody runs an object's go-git Encode method into a scratch
// MemoryObject and returns just the payload bytes — without the
// "<type> <size>\x00" header. writeLoose adds the SHA256-correct header.
func encodeBody(typ plumbing.ObjectType, encode func(plumbing.EncodedObject) error) ([]byte, error) {
 scratch := plumbing.NewMemoryObject(plumbing.FromObjectFormat(formatcfg.SHA1))
 scratch.SetType(typ)
41 unmodified lines

}

var buf bytes.Buffer
 zw := zlib.NewWriter(&buf)
 // Level 1 matches git's core.looseCompression default. Loose objects
 // are short-lived (gc rolls them into packs), so optimizing for write
 // speed over size is the standard trade-off.
 zw, err := zlib.NewWriterLevel(&buf, zlib.BestSpeed)
 if err != nil {
 return plumbing.ZeroHash, fmt.Errorf("zlib writer: %w", err)
}
 if _, err := zw.Write(header); err != nil {
 return plumbing.ZeroHash, fmt.Errorf("zlib write header: %w", err)
}
153 unmodified lines

return out
}

// notesCommitTime returns the committer/author timestamp for the
// synthetic notes wrapper commit. Reads SOURCE_DATE_EPOCH (the
// reproducible-builds convention) when set, falling back to the Unix
// epoch so two runs over identical source state always produce the
// same notes-ref hash.
func notesCommitTime() time.Time {
 if raw := os.Getenv("SOURCE_DATE_EPOCH"); raw != "" {
 if secs, err := strconv.ParseInt(raw, 10, 64); err == nil {
 return time.Unix(secs, 0).UTC()
 }
 }
 return time.Unix(0, 0).UTC()
}

// writeOriginNotes writes a `git notes` ref to dst that records each
// translated commit's original SHA1, keyed by its new SHA256. Standard
// git tooling (`git log --notes=<ref>`, `git notes --ref=<ref> show
50 unmodified lines

return "", fmt.Errorf("store notes tree: %w", err)
}

now := time.Now().UTC()
 sig := object.Signature{Name: "git-sync", Email: "noreply@entire.io", When: now}
 // Honor SOURCE_DATE_EPOCH for reproducible builds; otherwise pin to
 // the Unix epoch so the notes-ref hash is identical across runs over
 // the same source state. The notes commit is bookkeeping — its
 // timestamp carries no meaningful information about when the
 // underlying SHA1 history was created.
 sig := object.Signature{Name: "git-sync", Email: "noreply@entire.io", When: notesCommitTime()}
 commit := &object.Commit{
 Author: sig,
 Committer: sig,