Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions eng/_util/cmd/sign/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"log"
"os"
"path/filepath"
"strconv"
"strings"
)

Expand Down Expand Up @@ -94,8 +95,22 @@ func (a *archive) latestPath() string {
return a.path
}

func (a *archive) sigPath() string {
return filepath.Join(a.workDir, a.name+".sig")
// legacySigNeeded reports whether this archive needs a legacy .sig file
// in addition to the .asc file, for backward compatibility with go1.26 and earlier.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the plan here is to break it in 1.27? Note that this breaks download tools, not only individual users' workflows. I don't think we should do this break, especially without already establishing simultaneous publishing for a while to allow for time to move.

@dagood dagood Jun 4, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear: I think that publishing both .sig and .asc makes sense. We can then use .asc in our own infra to reduce patching. I don't know if it ever makes sense to stop publishing .sig, though.

.sig is actually a more intuitive extension to slap on our download URLs to get a signature. It might actually be better to treat .asc as a "compatibility" signature, not even the main one.

Users of Go don't even necessarily know about .asc from upstream (my old note on #181):

If I knew Go provided .asc files, I would have followed the naming, but they aren't advertised on the download page. I found out about them because the official golang Dockerfiles use the .asc files to verify the download.

func (a *archive) legacySigNeeded() bool {
// Archive names look like "go1.27.linux-amd64.tar.gz" or "go1.26.3.src.tar.gz".
if after, ok := strings.CutPrefix(a.name, "go1."); ok {
if dot := strings.IndexByte(after, '.'); dot > 0 {
if minor, err := strconv.Atoi(after[:dot]); err == nil && minor <= 26 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're in microsoft/go, so we know what version we're building based on what branch we're in. It isn't necessary to parse the version, and simplifying it leaves the intent clearer.

return true
}
}
}
Comment thread
gdams marked this conversation as resolved.
return false
}

func (a *archive) ascPath() string {
return filepath.Join(a.workDir, a.name+".asc")
}

func (a *archive) macHardenPackPath() string {
Expand Down Expand Up @@ -428,18 +443,18 @@ func (a *archive) prepareArchiveSignatures(ctx context.Context) ([]*fileToSign,
if err := ctx.Err(); err != nil {
return nil, err
}
// Copy the archive file to have .sig suffix, e.g. "tar.gz" to "tar.gz.sig". The signing
// process sends the "tar.gz.sig" file to get a signature, then replaces the "tar.gz.sig"
// file's content in-place with the result. We need to preemptively make a renamed copy of the
// file so we end up with both the original file and sig on the machine.
log.Printf("Copying file for signature generation: %q -> %q", a.latestPath(), a.sigPath())
if err := copyFile(a.sigPath(), a.latestPath()); err != nil {
// Copy the archive file with an ".asc" suffix. The signing process sends this file to get a
// signature, then replaces its content in-place with the result. We need to preemptively make
// a renamed copy of the file so we end up with both the original file and signature on the
// machine.
log.Printf("Copying file for signature generation: %q -> %q", a.latestPath(), a.ascPath())
if err := copyFile(a.ascPath(), a.latestPath()); err != nil {
return nil, err
}
return []*fileToSign{
{
originalPath: a.path,
fullPath: a.sigPath(),
fullPath: a.ascPath(),
authenticode: "LinuxSignManagedLanguageCompiler",
},
}, nil
Expand All @@ -458,9 +473,15 @@ func (a *archive) copyToDestination(ctx context.Context) error {
if err := copyFile(filepath.Join(*destinationDir, a.name), a.latestPath()); err != nil {
return err
}
if err := copyFile(filepath.Join(*destinationDir, a.name+".sig"), a.sigPath()); err != nil {
if err := copyFile(filepath.Join(*destinationDir, a.name+".asc"), a.ascPath()); err != nil {
return err
}
// For go1.26 and earlier, also produce a .sig file for backward compatibility.
if a.legacySigNeeded() {
if err := copyFile(filepath.Join(*destinationDir, a.name+".sig"), a.ascPath()); err != nil {
return err
}
}
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion eng/_util/cmd/sign/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func sign(ctx context.Context, step string, files []*fileToSign) error {
if *signType == "test" {
log.Printf("Testing signing: skipping MicroBuild tooling.")
for _, f := range files {
if strings.HasSuffix(f.fullPath, ".sig") {
if strings.HasSuffix(f.fullPath, ".sig") || strings.HasSuffix(f.fullPath, ".asc") {
log.Printf("Replacing file with placeholder content to reduce size and simulate signature: %q", f.fullPath)
// Get a checksum to make the file content unique. Otherwise,
// publishing rejects the repeated file content.
Expand Down
2 changes: 1 addition & 1 deletion eng/_util/cmd/updatelinktable/updatelinktable.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func filename(version, platform, ext string) string {
const (
checksumSuffix = ".sha256"
checksumMsg = "Checksum (SHA256)"
signatureSuffix = ".sig"
signatureSuffix = ".asc"
signatureMsg = "Signature<sup>1</sup>"
)

Expand Down
Loading