Skip to content

Commit 7f188a9

Browse files
tonoboneolynx
authored andcommitted
Add SOURCE_DATE_EPOCH support for GPG signers
Both the external GPG signer (--faked-system-time) and internal Go OpenPGP signer (signerConfig.Time) now honor SOURCE_DATE_EPOCH, producing reproducible signatures alongside the plain Release file dates. Adds system tests for both signer backends verifying byte-identical Release, Release.gpg and InRelease across repeated publishes. The signer tests (PublishRepo3[78]Test) are using an ed25519 key because ed25519 signatures are deterministic by design. The Go openpgp library uses a random nonce for DSA/ECDSA (see signature.go Sign calls using config.Random() link below) so those signatures vary across runs even with a fixed timestamp, making byte-identical verification impossible. In addition to 49f3428 Ref: #1537 Ref: https://github.com/ProtonMail/go-crypto/blob/v1.4.0/openpgp/packet/signature.go#L945-L979
1 parent 4088a81 commit 7f188a9

9 files changed

Lines changed: 124 additions & 22 deletions

File tree

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ require (
6363
github.com/bytedance/sonic v1.9.1 // indirect
6464
github.com/cespare/xxhash/v2 v2.3.0 // indirect
6565
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
66-
github.com/cloudflare/circl v1.6.1 // indirect
66+
github.com/cloudflare/circl v1.6.2 // indirect
6767
github.com/coreos/go-semver v0.3.0 // indirect
6868
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
6969
github.com/fatih/color v1.17.0 // indirect
@@ -118,7 +118,7 @@ require (
118118
require (
119119
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0
120120
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1
121-
github.com/ProtonMail/go-crypto v1.0.0
121+
github.com/ProtonMail/go-crypto v1.4.0
122122
github.com/aws/aws-sdk-go-v2 v1.32.5
123123
github.com/aws/aws-sdk-go-v2/config v1.28.5
124124
github.com/aws/aws-sdk-go-v2/credentials v1.17.46

go.sum

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55 h1:jbG
1818
github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI=
1919
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
2020
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
21-
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
22-
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
21+
github.com/ProtonMail/go-crypto v1.4.0 h1:Zq/pbM3F5DFgJiMouxEdSVY44MVoQNEKp5d5QxIQceQ=
22+
github.com/ProtonMail/go-crypto v1.4.0/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo=
2323
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
2424
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
2525
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
@@ -64,7 +64,6 @@ github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
6464
github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
6565
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
6666
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
67-
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
6867
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
6968
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
7069
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
@@ -80,9 +79,8 @@ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583j
8079
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
8180
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
8281
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
83-
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
84-
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
85-
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
82+
github.com/cloudflare/circl v1.6.2 h1:hL7VBpHHKzrV5WTfHCaBsgx/HGbBYlgrwvNXEVDYYsQ=
83+
github.com/cloudflare/circl v1.6.2/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
8684
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
8785
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
8886
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
@@ -322,14 +320,11 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
322320
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
323321
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
324322
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
325-
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
326-
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
327323
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
328324
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
329325
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
330326
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
331327
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
332-
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
333328
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
334329
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
335330
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -344,10 +339,7 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
344339
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
345340
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
346341
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
347-
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
348-
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
349342
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
350-
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
351343
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
352344
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
353345
golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
@@ -358,7 +350,6 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
358350
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
359351
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
360352
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
361-
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
362353
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
363354
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
364355
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -383,26 +374,20 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
383374
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
384375
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
385376
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
386-
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
387-
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
388377
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
389378
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
390379
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
391380
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
392381
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
393382
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
394-
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
395383
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
396-
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
397384
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
398385
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
399386
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
400387
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
401388
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
402389
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
403-
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
404390
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
405-
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
406391
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
407392
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
408393
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
@@ -413,7 +398,6 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
413398
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
414399
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
415400
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
416-
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
417401
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
418402
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
419403
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

pgp/gnupg.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"os"
1010
"os/exec"
1111
"path/filepath"
12+
"strconv"
1213
"strings"
1314
)
1415

@@ -89,6 +90,12 @@ func (g *GpgSigner) gpgArgs() []string {
8990
}
9091
}
9192

93+
if epoch := os.Getenv("SOURCE_DATE_EPOCH"); epoch != "" {
94+
if _, err := strconv.ParseInt(epoch, 10, 64); err == nil {
95+
args = append(args, "--faked-system-time", epoch)
96+
}
97+
}
98+
9299
return args
93100
}
94101

pgp/internal.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"path/filepath"
99
"sort"
10+
"strconv"
1011
"strings"
1112
"syscall"
1213
"time"
@@ -74,6 +75,14 @@ func (g *GoSigner) Init() error {
7475
},
7576
}
7677

78+
if epoch := os.Getenv("SOURCE_DATE_EPOCH"); epoch != "" {
79+
if sec, err := strconv.ParseInt(epoch, 10, 64); err == nil {
80+
t := time.Unix(sec, 0).UTC()
81+
g.signerConfig.Time = func() time.Time { return t }
82+
g.signerConfig.NonDeterministicSignaturesViaNotation = packet.BoolPointer(false)
83+
}
84+
}
85+
7786
if g.passphraseFile != "" {
7887
passF, err := os.Open(g.passphraseFile)
7988
if err != nil {

system/files/aptly-dual-binary.pub

1.14 KB
Binary file not shown.

system/files/aptly3-binary.sec

291 Bytes
Binary file not shown.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Loading packages...
2+
Generating metadata files and linking package files...
3+
Finalizing metadata files...
4+
Signing file 'Release' with gpg, please enter your passphrase when prompted:
5+
Clearsigning file 'Release' with gpg, please enter your passphrase when prompted:
6+
7+
Local repo local-repo has been successfully published.
8+
Please setup your webserver to serve directory '${HOME}/.aptly/public' with autoindexing.
9+
Now you can add following line to apt sources:
10+
deb http://your-server/ maverick main
11+
deb-src http://your-server/ maverick main
12+
Don't forget to add your GPG key to apt with apt-key.
13+
14+
You can also use `aptly serve` to publish your repositories over HTTP quickly.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Loading packages...
2+
Generating metadata files and linking package files...
3+
Finalizing metadata files...
4+
openpgp: signing file 'Release'...
5+
openpgp: clearsigning file 'Release'...
6+
7+
Local repo local-repo has been successfully published.
8+
Please setup your webserver to serve directory '${HOME}/.aptly/public' with autoindexing.
9+
Now you can add following line to apt sources:
10+
deb http://your-server/ maverick main
11+
deb-src http://your-server/ maverick main
12+
Don't forget to add your GPG key to apt with apt-key.
13+
14+
You can also use `aptly serve` to publish your repositories over HTTP quickly.

system/t06_publish/repo.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,3 +1005,77 @@ def check(self):
10051005
# verify byte-identical output
10061006
second_release = self.read_file('public/dists/maverick/Release')
10071007
self.check_equal(first_release, second_release)
1008+
1009+
1010+
class PublishRepo37Test(BaseTest):
1011+
"""
1012+
publish repo: SOURCE_DATE_EPOCH produces reproducible GPG signatures (external gpg)
1013+
"""
1014+
fixtureCmds = [
1015+
"aptly repo create local-repo",
1016+
"aptly repo add local-repo ${files}",
1017+
]
1018+
runCmd = "aptly publish repo -gpg-provider=gpg -gpg-key=21DBB89C16DB3E6D -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=maverick local-repo"
1019+
gold_processor = BaseTest.expand_environ
1020+
outputMatchPrepare = staticmethod(lambda s: "\n".join(l for l in s.split("\n") if not l.startswith("gpg:")))
1021+
environmentOverride = {"SOURCE_DATE_EPOCH": "1750000000"}
1022+
1023+
def check(self):
1024+
super(PublishRepo37Test, self).check()
1025+
1026+
# verify Release file date matches SOURCE_DATE_EPOCH
1027+
release = self.read_file('public/dists/maverick/Release')
1028+
date_line = [l for l in release.split("\n") if l.startswith("Date:")]
1029+
if date_line[0] != "Date: Sun, 15 Jun 2025 15:06:40 UTC":
1030+
raise Exception("expected Date from SOURCE_DATE_EPOCH, got: %s" % date_line[0])
1031+
1032+
# save all release artifacts from first publish
1033+
first_release = self.read_file('public/dists/maverick/Release')
1034+
first_release_gpg = self.read_file('public/dists/maverick/Release.gpg')
1035+
first_inrelease = self.read_file('public/dists/maverick/InRelease')
1036+
1037+
# drop and republish with same SOURCE_DATE_EPOCH
1038+
self.run_cmd("aptly publish drop maverick")
1039+
self.run_cmd("aptly publish repo -gpg-provider=gpg -gpg-key=21DBB89C16DB3E6D -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=maverick local-repo")
1040+
1041+
# verify byte-identical output for all release artifacts
1042+
self.check_equal(first_release, self.read_file('public/dists/maverick/Release'))
1043+
self.check_equal(first_release_gpg, self.read_file('public/dists/maverick/Release.gpg'))
1044+
self.check_equal(first_inrelease, self.read_file('public/dists/maverick/InRelease'))
1045+
1046+
1047+
class PublishRepo38Test(BaseTest):
1048+
"""
1049+
publish repo: SOURCE_DATE_EPOCH produces reproducible GPG signatures (internal signer, ed25519)
1050+
"""
1051+
fixtureCmds = [
1052+
"aptly repo create local-repo",
1053+
"aptly repo add local-repo ${files}",
1054+
]
1055+
runCmd = "aptly publish repo -gpg-key=BBF4E19434E91E4E -keyring=${files}/aptly-dual-binary.pub -secret-keyring=${files}/aptly3-binary.sec -distribution=maverick local-repo"
1056+
gold_processor = BaseTest.expand_environ
1057+
configOverride = {"gpgProvider": "internal"}
1058+
environmentOverride = {"SOURCE_DATE_EPOCH": "1750000000"}
1059+
1060+
def check(self):
1061+
super(PublishRepo38Test, self).check()
1062+
1063+
# verify Release file date matches SOURCE_DATE_EPOCH
1064+
release = self.read_file('public/dists/maverick/Release')
1065+
date_line = [l for l in release.split("\n") if l.startswith("Date:")]
1066+
if date_line[0] != "Date: Sun, 15 Jun 2025 15:06:40 UTC":
1067+
raise Exception("expected Date from SOURCE_DATE_EPOCH, got: %s" % date_line[0])
1068+
1069+
# save all release artifacts from first publish
1070+
first_release = self.read_file('public/dists/maverick/Release')
1071+
first_release_gpg = self.read_file('public/dists/maverick/Release.gpg')
1072+
first_inrelease = self.read_file('public/dists/maverick/InRelease')
1073+
1074+
# drop and republish with same SOURCE_DATE_EPOCH
1075+
self.run_cmd("aptly publish drop maverick")
1076+
self.run_cmd("aptly publish repo -gpg-key=BBF4E19434E91E4E -keyring=${files}/aptly-dual-binary.pub -secret-keyring=${files}/aptly3-binary.sec -distribution=maverick local-repo")
1077+
1078+
# verify byte-identical output for all release artifacts
1079+
self.check_equal(first_release, self.read_file('public/dists/maverick/Release'))
1080+
self.check_equal(first_release_gpg, self.read_file('public/dists/maverick/Release.gpg'))
1081+
self.check_equal(first_inrelease, self.read_file('public/dists/maverick/InRelease'))

0 commit comments

Comments
 (0)