mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-07-16 12:08:04 +00:00
Merge pull request #1479 from abregar/issues-309-691
Add config key for 'gpgKeys' and allow multiple keyRefs when signing with gpg, fixing Issues #309 and #691
This commit is contained in:
@@ -79,3 +79,4 @@ List of contributors, in chronological order:
|
|||||||
* Ato Araki (https://github.com/atotto)
|
* Ato Araki (https://github.com/atotto)
|
||||||
* Roman Lebedev (https://github.com/LebedevRI)
|
* Roman Lebedev (https://github.com/LebedevRI)
|
||||||
* Brian Witt (https://github.com/bwitt)
|
* Brian Witt (https://github.com/bwitt)
|
||||||
|
* Ales Bregar (https://github.com/abregar)
|
||||||
|
|||||||
+17
-3
@@ -16,8 +16,8 @@ import (
|
|||||||
type signingParams struct {
|
type signingParams struct {
|
||||||
// Don't sign published repository
|
// Don't sign published repository
|
||||||
Skip bool ` json:"Skip" example:"false"`
|
Skip bool ` json:"Skip" example:"false"`
|
||||||
// GPG key ID to use when signing the release, if not specified default key is used
|
// GPG key ID(s) to use when signing the release, separated by comma, and if not specified, default configured key(s) are used
|
||||||
GpgKey string ` json:"GpgKey" example:"A0546A43624A8331"`
|
GpgKey string ` json:"GpgKey" example:"KEY_ID_a, KEY_ID_b"`
|
||||||
// GPG keyring to use (instead of default)
|
// GPG keyring to use (instead of default)
|
||||||
Keyring string ` json:"Keyring" example:"trustedkeys.gpg"`
|
Keyring string ` json:"Keyring" example:"trustedkeys.gpg"`
|
||||||
// GPG secret keyring to use (instead of default) Note: depreciated with gpg2
|
// GPG secret keyring to use (instead of default) Note: depreciated with gpg2
|
||||||
@@ -41,7 +41,21 @@ func getSigner(options *signingParams) (pgp.Signer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
signer := context.GetSigner()
|
signer := context.GetSigner()
|
||||||
signer.SetKey(options.GpgKey)
|
|
||||||
|
var multiGpgKeys []string
|
||||||
|
// REST params have priority over config
|
||||||
|
if options.GpgKey != "" {
|
||||||
|
for _, p := range strings.Split(options.GpgKey, ",") {
|
||||||
|
if t := strings.TrimSpace(p); t != "" {
|
||||||
|
multiGpgKeys = append(multiGpgKeys, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if len(context.Config().GpgKeys) > 0 {
|
||||||
|
multiGpgKeys = context.Config().GpgKeys
|
||||||
|
}
|
||||||
|
for _, gpgKey := range multiGpgKeys {
|
||||||
|
signer.SetKey(gpgKey)
|
||||||
|
}
|
||||||
signer.SetKeyRing(options.Keyring, options.SecretKeyring)
|
signer.SetKeyRing(options.Keyring, options.SecretKeyring)
|
||||||
signer.SetPassphrase(options.Passphrase, options.PassphraseFile)
|
signer.SetPassphrase(options.Passphrase, options.PassphraseFile)
|
||||||
|
|
||||||
|
|||||||
+33
-1
@@ -1,6 +1,8 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/aptly-dev/aptly/pgp"
|
"github.com/aptly-dev/aptly/pgp"
|
||||||
"github.com/smira/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/flag"
|
"github.com/smira/flag"
|
||||||
@@ -12,7 +14,20 @@ func getSigner(flags *flag.FlagSet) (pgp.Signer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
signer := context.GetSigner()
|
signer := context.GetSigner()
|
||||||
signer.SetKey(flags.Lookup("gpg-key").Value.String())
|
|
||||||
|
var gpgKeys []string
|
||||||
|
|
||||||
|
// CLI args have priority over config
|
||||||
|
cliKeys := flags.Lookup("gpg-key").Value.Get().([]string)
|
||||||
|
if len(cliKeys) > 0 {
|
||||||
|
gpgKeys = cliKeys
|
||||||
|
} else if len(context.Config().GpgKeys) > 0 {
|
||||||
|
gpgKeys = context.Config().GpgKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, gpgKey := range gpgKeys {
|
||||||
|
signer.SetKey(gpgKey)
|
||||||
|
}
|
||||||
signer.SetKeyRing(flags.Lookup("keyring").Value.String(), flags.Lookup("secret-keyring").Value.String())
|
signer.SetKeyRing(flags.Lookup("keyring").Value.String(), flags.Lookup("secret-keyring").Value.String())
|
||||||
signer.SetPassphrase(flags.Lookup("passphrase").Value.String(), flags.Lookup("passphrase-file").Value.String())
|
signer.SetPassphrase(flags.Lookup("passphrase").Value.String(), flags.Lookup("passphrase-file").Value.String())
|
||||||
signer.SetBatch(flags.Lookup("batch").Value.Get().(bool))
|
signer.SetBatch(flags.Lookup("batch").Value.Get().(bool))
|
||||||
@@ -26,6 +41,23 @@ func getSigner(flags *flag.FlagSet) (pgp.Signer, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type gpgKeyFlag struct {
|
||||||
|
gpgKeys []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *gpgKeyFlag) Set(value string) error {
|
||||||
|
k.gpgKeys = append(k.gpgKeys, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *gpgKeyFlag) Get() interface{} {
|
||||||
|
return k.gpgKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *gpgKeyFlag) String() string {
|
||||||
|
return strings.Join(k.gpgKeys, ",")
|
||||||
|
}
|
||||||
|
|
||||||
func makeCmdPublish() *commander.Command {
|
func makeCmdPublish() *commander.Command {
|
||||||
return &commander.Command{
|
return &commander.Command{
|
||||||
UsageLine: "publish",
|
UsageLine: "publish",
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ Example:
|
|||||||
}
|
}
|
||||||
cmd.Flag.String("distribution", "", "distribution name to publish")
|
cmd.Flag.String("distribution", "", "distribution name to publish")
|
||||||
cmd.Flag.String("component", "", "component name to publish (for multi-component publishing, separate components with commas)")
|
cmd.Flag.String("component", "", "component name to publish (for multi-component publishing, separate components with commas)")
|
||||||
cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release")
|
cmd.Flag.Var(&gpgKeyFlag{}, "gpg-key", "GPG key ID to use when signing the release (flag is repeatable, can be specified multiple times)")
|
||||||
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
|
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
|
||||||
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
|
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
|
||||||
cmd.Flag.String("passphrase", "", "GPG passphrase for the key (warning: could be insecure)")
|
cmd.Flag.String("passphrase", "", "GPG passphrase for the key (warning: could be insecure)")
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ Example:
|
|||||||
}
|
}
|
||||||
cmd.Flag.String("distribution", "", "distribution name to publish")
|
cmd.Flag.String("distribution", "", "distribution name to publish")
|
||||||
cmd.Flag.String("component", "", "component name to publish (for multi-component publishing, separate components with commas)")
|
cmd.Flag.String("component", "", "component name to publish (for multi-component publishing, separate components with commas)")
|
||||||
cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release")
|
cmd.Flag.Var(&gpgKeyFlag{}, "gpg-key", "GPG key ID to use when signing the release (flag is repeatable, can be specified multiple times)")
|
||||||
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
|
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
|
||||||
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
|
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
|
||||||
cmd.Flag.String("passphrase", "", "GPG passphrase for the key (warning: could be insecure)")
|
cmd.Flag.String("passphrase", "", "GPG passphrase for the key (warning: could be insecure)")
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ This command would switch published repository (with one component) named ppa/wh
|
|||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-publish-switch", flag.ExitOnError),
|
Flag: *flag.NewFlagSet("aptly-publish-switch", flag.ExitOnError),
|
||||||
}
|
}
|
||||||
cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release")
|
cmd.Flag.Var(&gpgKeyFlag{}, "gpg-key", "GPG key ID to use when signing the release (flag is repeatable, can be specified multiple times)")
|
||||||
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
|
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
|
||||||
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
|
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
|
||||||
cmd.Flag.String("passphrase", "", "GPG passphrase for the key (warning: could be insecure)")
|
cmd.Flag.String("passphrase", "", "GPG passphrase for the key (warning: could be insecure)")
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ Example:
|
|||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-publish-update", flag.ExitOnError),
|
Flag: *flag.NewFlagSet("aptly-publish-update", flag.ExitOnError),
|
||||||
}
|
}
|
||||||
cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release")
|
cmd.Flag.Var(&gpgKeyFlag{}, "gpg-key", "GPG key ID to use when signing the release (flag is repeatable, can be specified multiple times)")
|
||||||
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
|
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
|
||||||
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
|
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
|
||||||
cmd.Flag.String("passphrase", "", "GPG passphrase for the key (warning: could be insecure)")
|
cmd.Flag.String("passphrase", "", "GPG passphrase for the key (warning: could be insecure)")
|
||||||
|
|||||||
+20
-1
@@ -11,7 +11,26 @@ Repositories can be published to local directories, Amazon S3 buckets, Azure or
|
|||||||
|
|
||||||
GPG key is required to sign any published repository. The key pari should be generated before publishing.
|
GPG key is required to sign any published repository. The key pari should be generated before publishing.
|
||||||
|
|
||||||
Publiс part of the key should be exported from your keyring using `gpg --export --armor` and imported on the system which uses a published repository.
|
Public part of the key should be exported from your keyring using `gpg --export --armor` and imported on the system which uses a published repository.
|
||||||
|
|
||||||
|
* Multiple signing keys can be defined in aptly.conf using the gpgKeys array:
|
||||||
|
```
|
||||||
|
"gpgKeys": [
|
||||||
|
"KEY_ID_x",
|
||||||
|
"KEY_ID_y"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
* It is also possible to pass multiple keys via the CLI using the repeatable `--gpg-key` flag:
|
||||||
|
```
|
||||||
|
aptly publish repo my-repo --gpg-key=KEY_ID_a --gpg-key=KEY_ID_b
|
||||||
|
```
|
||||||
|
* When using the REST API, the `gpgKey` parameter supports a comma-separated list of key IDs:
|
||||||
|
```
|
||||||
|
"gpgKey": "KEY_ID_a,KEY_ID_b"
|
||||||
|
```
|
||||||
|
* If `--gpg-key` is specified on the command line, or `gpgKey` is provided via the REST API, it takes precedence over any gpgKeys configuration in aptly.conf.
|
||||||
|
* With multi-key support, aptly will sign all Release files (both clearsigned and detached signatures) with each provided key, ensuring a smooth key rotation process while maintaining compatibility for existing clients.
|
||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
|
|
||||||
|
|||||||
+11
-4
@@ -22,7 +22,7 @@ var (
|
|||||||
type GpgSigner struct {
|
type GpgSigner struct {
|
||||||
gpg string
|
gpg string
|
||||||
version GPGVersion
|
version GPGVersion
|
||||||
keyRef string
|
keyRefs []string
|
||||||
keyring, secretKeyring string
|
keyring, secretKeyring string
|
||||||
passphrase, passphraseFile string
|
passphrase, passphraseFile string
|
||||||
batch bool
|
batch bool
|
||||||
@@ -35,7 +35,14 @@ func (g *GpgSigner) SetBatch(batch bool) {
|
|||||||
|
|
||||||
// SetKey sets key ID to use when signing files
|
// SetKey sets key ID to use when signing files
|
||||||
func (g *GpgSigner) SetKey(keyRef string) {
|
func (g *GpgSigner) SetKey(keyRef string) {
|
||||||
g.keyRef = keyRef
|
keyRef = strings.TrimSpace(keyRef)
|
||||||
|
if keyRef != "" {
|
||||||
|
if g.keyRefs == nil {
|
||||||
|
g.keyRefs = []string{keyRef}
|
||||||
|
} else {
|
||||||
|
g.keyRefs = append(g.keyRefs, keyRef)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetKeyRing allows to set custom keyring and secretkeyring
|
// SetKeyRing allows to set custom keyring and secretkeyring
|
||||||
@@ -57,8 +64,8 @@ func (g *GpgSigner) gpgArgs() []string {
|
|||||||
args = append(args, "--secret-keyring", g.secretKeyring)
|
args = append(args, "--secret-keyring", g.secretKeyring)
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.keyRef != "" {
|
for _, k := range g.keyRefs {
|
||||||
args = append(args, "-u", g.keyRef)
|
args = append(args, "-u", k)
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.passphrase != "" || g.passphraseFile != "" {
|
if g.passphrase != "" || g.passphraseFile != "" {
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mQGiBFL7pY8RBAC5uHg/9AuGJ7EF7RYty89IDLeqvlPe710eDQpJ+itsOaA/5rr3
|
||||||
|
IV1LMlqHpM2rkZkAPpARwjrga2ByJ1ww77Zq2uPqJIO2LZYWTLXic9Zity2OVu3Z
|
||||||
|
XwtdsqagIMfT5dAgNmhe5lL7qgGUwYcFFa52s7U4qO0z2FfwHW1IQrnMpwCg5RQh
|
||||||
|
Uqs5iUKdDtoeQjX5mWgQhjEEAI1zfXUvvcOrRsDlGNKYZigZiWC6J46jeR8Nnf9C
|
||||||
|
WwhXS2fzQaJyDq9DorkvPZgWUAaLLCdfGETqLzDKajynhS1+OnfFQNzvkvEPRBSb
|
||||||
|
C5k+GOF2E1E9rGXb31+1XZTcdIprp4/F3RNLLWNUwfgPLWJx9NzHTYqgBStecHkC
|
||||||
|
ySZRA/9PNFAbeJZ27HNuzoGnAa0piZDLeAAHsM1V6cosMh7U1IZqjZcrMC9YXNxH
|
||||||
|
2D90PvoBvpufCMRzL/fOVPT1JzQGYoKIX17Nmzvdq/a4YyLWRODjvWXd94bae2Xd
|
||||||
|
Vy03DYhfp8VOVJW6HuAX9JN6MKXSNxaibgOPjU822Hxd1iCIQ7QtQXB0bHkgVGVz
|
||||||
|
dGVyIChkb24ndCB1c2UgaXQpIDx0ZXN0QGFwdGx5LmluZm8+iGIEExECACIFAlL7
|
||||||
|
pY8CGyMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJECHbuJwW2z5t2sQAoNn+
|
||||||
|
0cADZa66HZNY2qJi44Oq4hjaAJsHzj9JKAHEpdix5N7b6QvaZQZYhrkBDQRS+6WP
|
||||||
|
EAQA9BX+kbIM6VJYoyY9vUHXfAF4E2y2M7vl9knZ+jMPfMbI7dE3gRJQb3mngST5
|
||||||
|
7eZWawo1DNE6h3LbHsB4mpro9XLUXUMBgXRsOq4D5E0ygvDZ/tJhy0AwFiTOXKEs
|
||||||
|
/erzmbF7j/TWh4LVHXFI9DrnN0+EeF/mQC/wzX7WGCKe70cAAwUEAMr7959zUYNp
|
||||||
|
E3v4IquIJpD22bT/FiyQjFG8yGy36c+7mOP3VWi0lz5yFqqeR9NDFuLDSwOEi0nB
|
||||||
|
zXNmimLy+hIwMaHjbQLjLODmy/T9wKCgeAmK1ygT6YBGJJflThZ05M80T5hBtRA9
|
||||||
|
z2eoTn0wbi6MLmD/rbEt+lUPfSA4V0t2iEkEGBECAAkFAlL7pY8CGwwACgkQIdu4
|
||||||
|
nBbbPm05hgCgvYatZXRbEdZ91jJCQi1KI7lJ5Y8AnjvrHU0g84mE45QZFegZzzQo
|
||||||
|
9relmDMEZ3YCRhYJKwYBBAHaRw8BAQdAYDU0VSBcurX+uqAeR/w/XOLSZcghvOqz
|
||||||
|
Y8yWdcj3HUy0L0FwdGx5IFNlY29uZGFyeSBTaWduaW5nIEtleSA8YXB0bHlAZXhh
|
||||||
|
bXBsZS5jb20+iJYEExYKAD4WIQSu4W3wGDVPZ/5fXHK79OGUNOkeTgUCZ3YCRgIb
|
||||||
|
AwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRC79OGUNOkeTid/AP9A
|
||||||
|
kIMn2qI5TqZgzrnPt7SN16VvpMppPb2H0m0P6knQKQD8DHcLcrqAl2cjcEuntv75
|
||||||
|
gOnEvmPDAO6S1rc8UgcWdQQ=
|
||||||
|
=XPoo
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
lFgEZ3YCRhYJKwYBBAHaRw8BAQdAYDU0VSBcurX+uqAeR/w/XOLSZcghvOqzY8yW
|
||||||
|
dcj3HUwAAP9lsZgE1YQfaS9xfVOSi3f91lbq13+U9FPdwxfiET0+bBFrtC9BcHRs
|
||||||
|
eSBTZWNvbmRhcnkgU2lnbmluZyBLZXkgPGFwdGx5QGV4YW1wbGUuY29tPoiWBBMW
|
||||||
|
CgA+FiEEruFt8Bg1T2f+X1xyu/ThlDTpHk4FAmd2AkYCGwMFCQPCZwAFCwkIBwIG
|
||||||
|
FQoJCAsCBBYCAwECHgECF4AACgkQu/ThlDTpHk4nfwD/QJCDJ9qiOU6mYM65z7e0
|
||||||
|
jdelb6TKaT29h9JtD+pJ0CkA/Ax3C3K6gJdnI3BLp7b++YDpxL5jwwDukta3PFIH
|
||||||
|
FnUE
|
||||||
|
=IXTY
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
||||||
@@ -272,6 +272,9 @@ class BaseTest(object):
|
|||||||
self.run_cmd([
|
self.run_cmd([
|
||||||
self.gpgFinder.gpg2, "--import",
|
self.gpgFinder.gpg2, "--import",
|
||||||
os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files") + "/aptly.sec"], expected_code=None)
|
os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files") + "/aptly.sec"], expected_code=None)
|
||||||
|
self.run_cmd([
|
||||||
|
self.gpgFinder.gpg2, "--import",
|
||||||
|
os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files") + "/aptly3.sec"], expected_code=None)
|
||||||
|
|
||||||
if self.fixtureGpg:
|
if self.fixtureGpg:
|
||||||
self.run_cmd([self.gpgFinder.gpg, "--no-default-keyring", "--trust-model", "always", "--batch", "--keyring", "aptlytest.gpg", "--import"] +
|
self.run_cmd([self.gpgFinder.gpg, "--no-default-keyring", "--trust-model", "always", "--batch", "--keyring", "aptlytest.gpg", "--import"] +
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"gpgProvider": "gpg",
|
"gpgProvider": "gpg",
|
||||||
"gpgDisableSign": false,
|
"gpgDisableSign": false,
|
||||||
"gpgDisableVerify": false,
|
"gpgDisableVerify": false,
|
||||||
|
"gpgKeys": [],
|
||||||
"skipContentsPublishing": false,
|
"skipContentsPublishing": false,
|
||||||
"skipBz2Publishing": false,
|
"skipBz2Publishing": false,
|
||||||
"FileSystemPublishEndpoints": {},
|
"FileSystemPublishEndpoints": {},
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ download_sourcepackages: false
|
|||||||
gpg_provider: gpg
|
gpg_provider: gpg
|
||||||
gpg_disable_sign: false
|
gpg_disable_sign: false
|
||||||
gpg_disable_verify: false
|
gpg_disable_verify: false
|
||||||
|
gpg_keys: []
|
||||||
skip_contents_publishing: false
|
skip_contents_publishing: false
|
||||||
skip_bz2_publishing: false
|
skip_bz2_publishing: false
|
||||||
filesystem_publish_endpoints: {}
|
filesystem_publish_endpoints: {}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
gpg: Signature made Mon Jan 26 10:18:32 2026 UTC
|
||||||
|
gpg: using DSA key C5ACD2179B5231DFE842EE6121DBB89C16DB3E6D
|
||||||
|
gpg: checking the trustdb
|
||||||
|
gpg: no ultimately trusted keys found
|
||||||
|
gpg: Good signature from "Aptly Tester (don't use it) <test@aptly.info>" [unknown]
|
||||||
|
gpg: WARNING: This key is not certified with a trusted signature!
|
||||||
|
gpg: There is no indication that the signature belongs to the owner.
|
||||||
|
Primary key fingerprint: C5AC D217 9B52 31DF E842 EE61 21DB B89C 16DB 3E6D
|
||||||
|
gpg: Signature made Mon Jan 26 10:18:32 2026 UTC
|
||||||
|
gpg: using EDDSA key AEE16DF018354F67FE5F5C72BBF4E19434E91E4E
|
||||||
|
gpg: Good signature from "Aptly Secondary Signing Key <aptly@example.com>" [unknown]
|
||||||
|
gpg: WARNING: This key is not certified with a trusted signature!
|
||||||
|
gpg: There is no indication that the signature belongs to the owner.
|
||||||
|
Primary key fingerprint: AEE1 6DF0 1835 4F67 FE5F 5C72 BBF4 E194 34E9 1E4E
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
|
import re
|
||||||
|
|
||||||
from api_lib import TASK_SUCCEEDED, APITest
|
from api_lib import TASK_SUCCEEDED, APITest
|
||||||
|
|
||||||
@@ -1874,3 +1875,63 @@ class PublishUpdateSourcesAPITestRepo(APITest):
|
|||||||
all_repos = self.get("/api/publish")
|
all_repos = self.get("/api/publish")
|
||||||
self.check_equal(all_repos.status_code, 200)
|
self.check_equal(all_repos.status_code, 200)
|
||||||
self.check_in(repo_expected, all_repos.json())
|
self.check_in(repo_expected, all_repos.json())
|
||||||
|
|
||||||
|
|
||||||
|
class PublishAPITestDualSignature(APITest):
|
||||||
|
"""
|
||||||
|
POST /publish/:prefix (local repos), GET /publish
|
||||||
|
"""
|
||||||
|
fixtureGpg = True
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
repo_name = self.random_name()
|
||||||
|
self.check_equal(self.post(
|
||||||
|
"/api/repos", json={"Name": repo_name, "DefaultDistribution": "wheezy"}).status_code, 201)
|
||||||
|
|
||||||
|
d = self.random_name()
|
||||||
|
self.check_equal(self.upload("/api/files/" + d,
|
||||||
|
"libboost-program-options-dev_1.49.0.1_i386.deb", "pyspi_0.6.1-1.3.dsc",
|
||||||
|
"pyspi_0.6.1-1.3.diff.gz", "pyspi_0.6.1.orig.tar.gz",
|
||||||
|
"pyspi-0.6.1-1.3.stripped.dsc").status_code, 200)
|
||||||
|
|
||||||
|
task = self.post_task("/api/repos/" + repo_name + "/file/" + d)
|
||||||
|
self.check_task(task)
|
||||||
|
|
||||||
|
# publishing under prefix, default distribution
|
||||||
|
prefix = self.random_name()
|
||||||
|
task = self.post_task(
|
||||||
|
"/api/publish/" + prefix,
|
||||||
|
json={
|
||||||
|
"SourceKind": "local",
|
||||||
|
"Sources": [{"Name": repo_name}],
|
||||||
|
"Signing": {"GPGKey": "C5ACD2179B5231DFE842EE6121DBB89C16DB3E6D,AEE16DF018354F67FE5F5C72BBF4E19434E91E4E"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.check_task(task)
|
||||||
|
repo_expected = {
|
||||||
|
'AcquireByHash': False,
|
||||||
|
'Architectures': ['i386', 'source'],
|
||||||
|
'Codename': '',
|
||||||
|
'Distribution': 'wheezy',
|
||||||
|
'Label': '',
|
||||||
|
'Origin': '',
|
||||||
|
'NotAutomatic': '',
|
||||||
|
'ButAutomaticUpgrades': '',
|
||||||
|
'Path': prefix + '/' + 'wheezy',
|
||||||
|
'Prefix': prefix,
|
||||||
|
'SignedBy': '',
|
||||||
|
'SkipContents': False,
|
||||||
|
'MultiDist': False,
|
||||||
|
'SourceKind': 'local',
|
||||||
|
'Sources': [{'Component': 'main', 'Name': repo_name}],
|
||||||
|
'Storage': '',
|
||||||
|
'Suite': ''}
|
||||||
|
|
||||||
|
all_repos = self.get("/api/publish")
|
||||||
|
self.check_equal(all_repos.status_code, 200)
|
||||||
|
self.check_in(repo_expected, all_repos.json())
|
||||||
|
|
||||||
|
self.check_exists("public/" + prefix + "/dists/wheezy/Release")
|
||||||
|
path = os.path.join(os.environ["HOME"], self.aptlyDir, "public", prefix, "dists/wheezy")
|
||||||
|
self.check_cmd_output(f"gpg --verify {path}/Release.gpg {path}/Release", "Release.gpg",
|
||||||
|
match_prepare=lambda s: re.sub(r'Signature made .*', '', s))
|
||||||
|
|||||||
+5
-3
@@ -49,9 +49,10 @@ type ConfigStructure struct { // nolint: maligned
|
|||||||
DownloadSourcePackages bool `json:"downloadSourcePackages" yaml:"download_sourcepackages"`
|
DownloadSourcePackages bool `json:"downloadSourcePackages" yaml:"download_sourcepackages"`
|
||||||
|
|
||||||
// Signing
|
// Signing
|
||||||
GpgProvider string `json:"gpgProvider" yaml:"gpg_provider"`
|
GpgProvider string `json:"gpgProvider" yaml:"gpg_provider"`
|
||||||
GpgDisableSign bool `json:"gpgDisableSign" yaml:"gpg_disable_sign"`
|
GpgDisableSign bool `json:"gpgDisableSign" yaml:"gpg_disable_sign"`
|
||||||
GpgDisableVerify bool `json:"gpgDisableVerify" yaml:"gpg_disable_verify"`
|
GpgDisableVerify bool `json:"gpgDisableVerify" yaml:"gpg_disable_verify"`
|
||||||
|
GpgKeys []string `json:"gpgKeys" yaml:"gpg_keys"`
|
||||||
|
|
||||||
// Publishing
|
// Publishing
|
||||||
SkipContentsPublishing bool `json:"skipContentsPublishing" yaml:"skip_contents_publishing"`
|
SkipContentsPublishing bool `json:"skipContentsPublishing" yaml:"skip_contents_publishing"`
|
||||||
@@ -226,6 +227,7 @@ var Config = ConfigStructure{
|
|||||||
GpgProvider: "gpg",
|
GpgProvider: "gpg",
|
||||||
GpgDisableSign: false,
|
GpgDisableSign: false,
|
||||||
GpgDisableVerify: false,
|
GpgDisableVerify: false,
|
||||||
|
GpgKeys: []string{},
|
||||||
DownloadSourcePackages: false,
|
DownloadSourcePackages: false,
|
||||||
PackagePoolStorage: PackagePoolStorage{
|
PackagePoolStorage: PackagePoolStorage{
|
||||||
Local: &LocalPoolStorage{Path: ""},
|
Local: &LocalPoolStorage{Path: ""},
|
||||||
|
|||||||
+146
-143
@@ -19,8 +19,8 @@ func (s *ConfigSuite) TestLoadConfig(c *C) {
|
|||||||
_, _ = f.WriteString(configFile)
|
_, _ = f.WriteString(configFile)
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
|
|
||||||
// start with empty config
|
// start with empty config
|
||||||
s.config = ConfigStructure{}
|
s.config = ConfigStructure{}
|
||||||
|
|
||||||
err := LoadConfig(configname, &s.config)
|
err := LoadConfig(configname, &s.config)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
@@ -32,8 +32,8 @@ func (s *ConfigSuite) TestLoadConfig(c *C) {
|
|||||||
func (s *ConfigSuite) TestSaveConfig(c *C) {
|
func (s *ConfigSuite) TestSaveConfig(c *C) {
|
||||||
configname := filepath.Join(c.MkDir(), "aptly.json2")
|
configname := filepath.Join(c.MkDir(), "aptly.json2")
|
||||||
|
|
||||||
// start with empty config
|
// start with empty config
|
||||||
s.config = ConfigStructure{}
|
s.config = ConfigStructure{}
|
||||||
|
|
||||||
s.config.RootDir = "/tmp/aptly"
|
s.config.RootDir = "/tmp/aptly"
|
||||||
s.config.DownloadConcurrency = 5
|
s.config.DownloadConcurrency = 5
|
||||||
@@ -71,93 +71,94 @@ func (s *ConfigSuite) TestSaveConfig(c *C) {
|
|||||||
_, _ = f.Read(buf)
|
_, _ = f.Read(buf)
|
||||||
|
|
||||||
c.Check(string(buf), Equals, ""+
|
c.Check(string(buf), Equals, ""+
|
||||||
"{\n"+
|
"{\n" +
|
||||||
" \"rootDir\": \"/tmp/aptly\",\n"+
|
" \"rootDir\": \"/tmp/aptly\",\n" +
|
||||||
" \"logLevel\": \"info\",\n"+
|
" \"logLevel\": \"info\",\n" +
|
||||||
" \"logFormat\": \"json\",\n"+
|
" \"logFormat\": \"json\",\n" +
|
||||||
" \"databaseOpenAttempts\": 5,\n"+
|
" \"databaseOpenAttempts\": 5,\n" +
|
||||||
" \"architectures\": null,\n"+
|
" \"architectures\": null,\n" +
|
||||||
" \"skipLegacyPool\": false,\n"+
|
" \"skipLegacyPool\": false,\n" +
|
||||||
" \"dependencyFollowSuggests\": false,\n"+
|
" \"dependencyFollowSuggests\": false,\n" +
|
||||||
" \"dependencyFollowRecommends\": false,\n"+
|
" \"dependencyFollowRecommends\": false,\n" +
|
||||||
" \"dependencyFollowAllVariants\": false,\n"+
|
" \"dependencyFollowAllVariants\": false,\n" +
|
||||||
" \"dependencyFollowSource\": false,\n"+
|
" \"dependencyFollowSource\": false,\n" +
|
||||||
" \"dependencyVerboseResolve\": false,\n"+
|
" \"dependencyVerboseResolve\": false,\n" +
|
||||||
" \"ppaDistributorID\": \"\",\n"+
|
" \"ppaDistributorID\": \"\",\n" +
|
||||||
" \"ppaCodename\": \"\",\n"+
|
" \"ppaCodename\": \"\",\n" +
|
||||||
" \"serveInAPIMode\": false,\n"+
|
" \"serveInAPIMode\": false,\n" +
|
||||||
" \"enableMetricsEndpoint\": false,\n"+
|
" \"enableMetricsEndpoint\": false,\n" +
|
||||||
" \"enableSwaggerEndpoint\": false,\n"+
|
" \"enableSwaggerEndpoint\": false,\n" +
|
||||||
" \"AsyncAPI\": false,\n"+
|
" \"AsyncAPI\": false,\n" +
|
||||||
" \"databaseBackend\": {\n"+
|
" \"databaseBackend\": {\n" +
|
||||||
" \"type\": \"\",\n"+
|
" \"type\": \"\",\n" +
|
||||||
" \"dbPath\": \"\",\n"+
|
" \"dbPath\": \"\",\n" +
|
||||||
" \"url\": \"\"\n"+
|
" \"url\": \"\"\n" +
|
||||||
" },\n"+
|
" },\n" +
|
||||||
" \"downloader\": \"\",\n"+
|
" \"downloader\": \"\",\n" +
|
||||||
" \"downloadConcurrency\": 5,\n"+
|
" \"downloadConcurrency\": 5,\n" +
|
||||||
" \"downloadSpeedLimit\": 0,\n"+
|
" \"downloadSpeedLimit\": 0,\n" +
|
||||||
" \"downloadRetries\": 0,\n"+
|
" \"downloadRetries\": 0,\n" +
|
||||||
" \"downloadSourcePackages\": false,\n"+
|
" \"downloadSourcePackages\": false,\n" +
|
||||||
" \"gpgProvider\": \"gpg\",\n"+
|
" \"gpgProvider\": \"gpg\",\n" +
|
||||||
" \"gpgDisableSign\": false,\n"+
|
" \"gpgDisableSign\": false,\n" +
|
||||||
" \"gpgDisableVerify\": false,\n"+
|
" \"gpgDisableVerify\": false,\n" +
|
||||||
" \"skipContentsPublishing\": false,\n"+
|
" \"gpgKeys\": null,\n" +
|
||||||
" \"skipBz2Publishing\": false,\n"+
|
" \"skipContentsPublishing\": false,\n" +
|
||||||
" \"FileSystemPublishEndpoints\": {\n"+
|
" \"skipBz2Publishing\": false,\n" +
|
||||||
" \"test\": {\n"+
|
" \"FileSystemPublishEndpoints\": {\n" +
|
||||||
" \"rootDir\": \"/opt/aptly-publish\",\n"+
|
" \"test\": {\n" +
|
||||||
" \"linkMethod\": \"\",\n"+
|
" \"rootDir\": \"/opt/aptly-publish\",\n" +
|
||||||
" \"verifyMethod\": \"\"\n"+
|
" \"linkMethod\": \"\",\n" +
|
||||||
" }\n"+
|
" \"verifyMethod\": \"\"\n" +
|
||||||
" },\n"+
|
" }\n" +
|
||||||
" \"S3PublishEndpoints\": {\n"+
|
" },\n" +
|
||||||
" \"test\": {\n"+
|
" \"S3PublishEndpoints\": {\n" +
|
||||||
" \"region\": \"us-east-1\",\n"+
|
" \"test\": {\n" +
|
||||||
" \"bucket\": \"repo\",\n"+
|
" \"region\": \"us-east-1\",\n" +
|
||||||
" \"prefix\": \"\",\n"+
|
" \"bucket\": \"repo\",\n" +
|
||||||
" \"acl\": \"\",\n"+
|
" \"prefix\": \"\",\n" +
|
||||||
" \"awsAccessKeyID\": \"\",\n"+
|
" \"acl\": \"\",\n" +
|
||||||
" \"awsSecretAccessKey\": \"\",\n"+
|
" \"awsAccessKeyID\": \"\",\n" +
|
||||||
" \"awsSessionToken\": \"\",\n"+
|
" \"awsSecretAccessKey\": \"\",\n" +
|
||||||
" \"endpoint\": \"\",\n"+
|
" \"awsSessionToken\": \"\",\n" +
|
||||||
" \"storageClass\": \"\",\n"+
|
" \"endpoint\": \"\",\n" +
|
||||||
" \"encryptionMethod\": \"\",\n"+
|
" \"storageClass\": \"\",\n" +
|
||||||
" \"plusWorkaround\": false,\n"+
|
" \"encryptionMethod\": \"\",\n" +
|
||||||
" \"disableMultiDel\": false,\n"+
|
" \"plusWorkaround\": false,\n" +
|
||||||
" \"forceSigV2\": false,\n"+
|
" \"disableMultiDel\": false,\n" +
|
||||||
" \"forceVirtualHostedStyle\": false,\n"+
|
" \"forceSigV2\": false,\n" +
|
||||||
" \"debug\": false\n"+
|
" \"forceVirtualHostedStyle\": false,\n" +
|
||||||
" }\n"+
|
" \"debug\": false\n" +
|
||||||
" },\n"+
|
" }\n" +
|
||||||
" \"SwiftPublishEndpoints\": {\n"+
|
" },\n" +
|
||||||
" \"test\": {\n"+
|
" \"SwiftPublishEndpoints\": {\n" +
|
||||||
" \"container\": \"repo\",\n"+
|
" \"test\": {\n" +
|
||||||
" \"prefix\": \"\",\n"+
|
" \"container\": \"repo\",\n" +
|
||||||
" \"osname\": \"\",\n"+
|
" \"prefix\": \"\",\n" +
|
||||||
" \"password\": \"\",\n"+
|
" \"osname\": \"\",\n" +
|
||||||
" \"tenant\": \"\",\n"+
|
" \"password\": \"\",\n" +
|
||||||
" \"tenantid\": \"\",\n"+
|
" \"tenant\": \"\",\n" +
|
||||||
" \"domain\": \"\",\n"+
|
" \"tenantid\": \"\",\n" +
|
||||||
" \"domainid\": \"\",\n"+
|
" \"domain\": \"\",\n" +
|
||||||
" \"tenantdomain\": \"\",\n"+
|
" \"domainid\": \"\",\n" +
|
||||||
" \"tenantdomainid\": \"\",\n"+
|
" \"tenantdomain\": \"\",\n" +
|
||||||
" \"authurl\": \"\"\n"+
|
" \"tenantdomainid\": \"\",\n" +
|
||||||
" }\n"+
|
" \"authurl\": \"\"\n" +
|
||||||
" },\n"+
|
" }\n" +
|
||||||
" \"AzurePublishEndpoints\": {\n"+
|
" },\n" +
|
||||||
" \"test\": {\n"+
|
" \"AzurePublishEndpoints\": {\n" +
|
||||||
" \"container\": \"repo\",\n"+
|
" \"test\": {\n" +
|
||||||
" \"prefix\": \"\",\n"+
|
" \"container\": \"repo\",\n" +
|
||||||
" \"accountName\": \"\",\n"+
|
" \"prefix\": \"\",\n" +
|
||||||
" \"accountKey\": \"\",\n"+
|
" \"accountName\": \"\",\n" +
|
||||||
" \"endpoint\": \"\"\n"+
|
" \"accountKey\": \"\",\n" +
|
||||||
" }\n"+
|
" \"endpoint\": \"\"\n" +
|
||||||
" },\n"+
|
" }\n" +
|
||||||
" \"packagePoolStorage\": {\n"+
|
" },\n" +
|
||||||
" \"type\": \"local\",\n"+
|
" \"packagePoolStorage\": {\n" +
|
||||||
" \"path\": \"/tmp/aptly-pool\"\n"+
|
" \"type\": \"local\",\n" +
|
||||||
" }\n"+
|
" \"path\": \"/tmp/aptly-pool\"\n" +
|
||||||
|
" }\n" +
|
||||||
"}")
|
"}")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,8 +168,8 @@ func (s *ConfigSuite) TestLoadYAMLConfig(c *C) {
|
|||||||
_, _ = f.WriteString(configFileYAML)
|
_, _ = f.WriteString(configFileYAML)
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
|
|
||||||
// start with empty config
|
// start with empty config
|
||||||
s.config = ConfigStructure{}
|
s.config = ConfigStructure{}
|
||||||
|
|
||||||
err := LoadConfig(configname, &s.config)
|
err := LoadConfig(configname, &s.config)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
@@ -183,8 +184,8 @@ func (s *ConfigSuite) TestLoadYAMLErrorConfig(c *C) {
|
|||||||
_, _ = f.WriteString(configFileYAMLError)
|
_, _ = f.WriteString(configFileYAMLError)
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
|
|
||||||
// start with empty config
|
// start with empty config
|
||||||
s.config = ConfigStructure{}
|
s.config = ConfigStructure{}
|
||||||
|
|
||||||
err := LoadConfig(configname, &s.config)
|
err := LoadConfig(configname, &s.config)
|
||||||
c.Assert(err.Error(), Equals, "invalid yaml (unknown pool storage type: invalid) or json (invalid character 'p' looking for beginning of value)")
|
c.Assert(err.Error(), Equals, "invalid yaml (unknown pool storage type: invalid) or json (invalid character 'p' looking for beginning of value)")
|
||||||
@@ -196,13 +197,13 @@ func (s *ConfigSuite) TestSaveYAMLConfig(c *C) {
|
|||||||
_, _ = f.WriteString(configFileYAML)
|
_, _ = f.WriteString(configFileYAML)
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
|
|
||||||
// start with empty config
|
// start with empty config
|
||||||
s.config = ConfigStructure{}
|
s.config = ConfigStructure{}
|
||||||
|
|
||||||
err := LoadConfig(configname, &s.config)
|
err := LoadConfig(configname, &s.config)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
err = SaveConfigYAML(configname, &s.config)
|
err = SaveConfigYAML(configname, &s.config)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
f, _ = os.Open(configname)
|
f, _ = os.Open(configname)
|
||||||
@@ -218,17 +219,17 @@ func (s *ConfigSuite) TestSaveYAMLConfig(c *C) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *ConfigSuite) TestSaveYAML2Config(c *C) {
|
func (s *ConfigSuite) TestSaveYAML2Config(c *C) {
|
||||||
// start with empty config
|
// start with empty config
|
||||||
s.config = ConfigStructure{}
|
s.config = ConfigStructure{}
|
||||||
|
|
||||||
s.config.PackagePoolStorage.Local = &LocalPoolStorage{"/tmp/aptly-pool"}
|
s.config.PackagePoolStorage.Local = &LocalPoolStorage{"/tmp/aptly-pool"}
|
||||||
s.config.PackagePoolStorage.Azure = nil
|
s.config.PackagePoolStorage.Azure = nil
|
||||||
|
|
||||||
configname := filepath.Join(c.MkDir(), "aptly.yaml4")
|
configname := filepath.Join(c.MkDir(), "aptly.yaml4")
|
||||||
err := SaveConfigYAML(configname, &s.config)
|
err := SaveConfigYAML(configname, &s.config)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
f, _ := os.Open(configname)
|
f, _ := os.Open(configname)
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
}()
|
}()
|
||||||
@@ -237,44 +238,45 @@ func (s *ConfigSuite) TestSaveYAML2Config(c *C) {
|
|||||||
buf := make([]byte, st.Size())
|
buf := make([]byte, st.Size())
|
||||||
_, _ = f.Read(buf)
|
_, _ = f.Read(buf)
|
||||||
|
|
||||||
c.Check(string(buf), Equals, ""+
|
c.Check(string(buf), Equals, "" +
|
||||||
"root_dir: \"\"\n"+
|
"root_dir: \"\"\n" +
|
||||||
"log_level: \"\"\n"+
|
"log_level: \"\"\n" +
|
||||||
"log_format: \"\"\n"+
|
"log_format: \"\"\n" +
|
||||||
"database_open_attempts: 0\n"+
|
"database_open_attempts: 0\n" +
|
||||||
"architectures: []\n"+
|
"architectures: []\n" +
|
||||||
"skip_legacy_pool: false\n"+
|
"skip_legacy_pool: false\n" +
|
||||||
"dep_follow_suggests: false\n"+
|
"dep_follow_suggests: false\n" +
|
||||||
"dep_follow_recommends: false\n"+
|
"dep_follow_recommends: false\n" +
|
||||||
"dep_follow_all_variants: false\n"+
|
"dep_follow_all_variants: false\n" +
|
||||||
"dep_follow_source: false\n"+
|
"dep_follow_source: false\n" +
|
||||||
"dep_verboseresolve: false\n"+
|
"dep_verboseresolve: false\n" +
|
||||||
"ppa_distributor_id: \"\"\n"+
|
"ppa_distributor_id: \"\"\n" +
|
||||||
"ppa_codename: \"\"\n"+
|
"ppa_codename: \"\"\n" +
|
||||||
"serve_in_api_mode: false\n"+
|
"serve_in_api_mode: false\n" +
|
||||||
"enable_metrics_endpoint: false\n"+
|
"enable_metrics_endpoint: false\n" +
|
||||||
"enable_swagger_endpoint: false\n"+
|
"enable_swagger_endpoint: false\n" +
|
||||||
"async_api: false\n"+
|
"async_api: false\n" +
|
||||||
"database_backend:\n"+
|
"database_backend:\n" +
|
||||||
" type: \"\"\n"+
|
" type: \"\"\n" +
|
||||||
" db_path: \"\"\n"+
|
" db_path: \"\"\n" +
|
||||||
" url: \"\"\n"+
|
" url: \"\"\n" +
|
||||||
"downloader: \"\"\n"+
|
"downloader: \"\"\n" +
|
||||||
"download_concurrency: 0\n"+
|
"download_concurrency: 0\n" +
|
||||||
"download_limit: 0\n"+
|
"download_limit: 0\n" +
|
||||||
"download_retries: 0\n"+
|
"download_retries: 0\n" +
|
||||||
"download_sourcepackages: false\n"+
|
"download_sourcepackages: false\n" +
|
||||||
"gpg_provider: \"\"\n"+
|
"gpg_provider: \"\"\n" +
|
||||||
"gpg_disable_sign: false\n"+
|
"gpg_disable_sign: false\n" +
|
||||||
"gpg_disable_verify: false\n"+
|
"gpg_disable_verify: false\n" +
|
||||||
"skip_contents_publishing: false\n"+
|
"gpg_keys: []\n" +
|
||||||
"skip_bz2_publishing: false\n"+
|
"skip_contents_publishing: false\n" +
|
||||||
"filesystem_publish_endpoints: {}\n"+
|
"skip_bz2_publishing: false\n" +
|
||||||
"s3_publish_endpoints: {}\n"+
|
"filesystem_publish_endpoints: {}\n" +
|
||||||
"swift_publish_endpoints: {}\n"+
|
"s3_publish_endpoints: {}\n" +
|
||||||
"azure_publish_endpoints: {}\n"+
|
"swift_publish_endpoints: {}\n" +
|
||||||
"packagepool_storage:\n"+
|
"azure_publish_endpoints: {}\n" +
|
||||||
" type: local\n"+
|
"packagepool_storage:\n" +
|
||||||
|
" type: local\n" +
|
||||||
" path: /tmp/aptly-pool\n")
|
" path: /tmp/aptly-pool\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,8 +285,8 @@ func (s *ConfigSuite) TestLoadEmptyConfig(c *C) {
|
|||||||
f, _ := os.Create(configname)
|
f, _ := os.Create(configname)
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
|
|
||||||
// start with empty config
|
// start with empty config
|
||||||
s.config = ConfigStructure{}
|
s.config = ConfigStructure{}
|
||||||
|
|
||||||
err := LoadConfig(configname, &s.config)
|
err := LoadConfig(configname, &s.config)
|
||||||
c.Assert(err.Error(), Equals, "invalid yaml (EOF) or json (EOF)")
|
c.Assert(err.Error(), Equals, "invalid yaml (EOF) or json (EOF)")
|
||||||
@@ -322,6 +324,7 @@ download_sourcepackages: true
|
|||||||
gpg_provider: gpg
|
gpg_provider: gpg
|
||||||
gpg_disable_sign: true
|
gpg_disable_sign: true
|
||||||
gpg_disable_verify: true
|
gpg_disable_verify: true
|
||||||
|
gpg_keys: []
|
||||||
skip_contents_publishing: true
|
skip_contents_publishing: true
|
||||||
skip_bz2_publishing: true
|
skip_bz2_publishing: true
|
||||||
filesystem_publish_endpoints:
|
filesystem_publish_endpoints:
|
||||||
|
|||||||
Reference in New Issue
Block a user