mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-02-05 13:15:26 +02:00
fix: makes username and password optional for http uploads (#2057)
* fix: makes username and password optional for http uploads * update upload doc
This commit is contained in:
parent
f6f448d84e
commit
89c220c4c6
@ -96,12 +96,16 @@ func CheckConfig(ctx *context.Context, upload *config.Upload, kind string) error
|
||||
return misconfigured(kind, upload, "mode must be 'binary' or 'archive'")
|
||||
}
|
||||
|
||||
if _, err := getUsername(ctx, upload, kind); err != nil {
|
||||
return err
|
||||
username := getUsername(ctx, upload, kind)
|
||||
password := getPassword(ctx, upload, kind)
|
||||
passwordEnv := fmt.Sprintf("%s_%s_SECRET", strings.ToUpper(kind), strings.ToUpper(upload.Name))
|
||||
|
||||
if password != "" && username == "" {
|
||||
return misconfigured(kind, upload, fmt.Sprintf("'username' is required when '%s' environment variable is set", passwordEnv))
|
||||
}
|
||||
|
||||
if _, err := getPassword(ctx, upload, kind); err != nil {
|
||||
return err
|
||||
if username != "" && password == "" {
|
||||
return misconfigured(kind, upload, fmt.Sprintf("environment variable '%s' is required when 'username' is set", passwordEnv))
|
||||
}
|
||||
|
||||
if upload.TrustedCerts != "" && !x509.NewCertPool().AppendCertsFromPEM([]byte(upload.TrustedCerts)) {
|
||||
@ -111,25 +115,20 @@ func CheckConfig(ctx *context.Context, upload *config.Upload, kind string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func getUsername(ctx *context.Context, upload *config.Upload, kind string) (string, error) {
|
||||
// username is optional
|
||||
func getUsername(ctx *context.Context, upload *config.Upload, kind string) string {
|
||||
if upload.Username != "" {
|
||||
return upload.Username, nil
|
||||
return upload.Username
|
||||
}
|
||||
|
||||
var key = fmt.Sprintf("%s_%s_USERNAME", strings.ToUpper(kind), strings.ToUpper(upload.Name))
|
||||
user, ok := ctx.Env[key]
|
||||
if !ok {
|
||||
return "", misconfigured(kind, upload, fmt.Sprintf("missing username or %s environment variable", key))
|
||||
}
|
||||
return user, nil
|
||||
return ctx.Env[key]
|
||||
}
|
||||
|
||||
func getPassword(ctx *context.Context, upload *config.Upload, kind string) (string, error) {
|
||||
// password is optional
|
||||
func getPassword(ctx *context.Context, upload *config.Upload, kind string) string {
|
||||
var key = fmt.Sprintf("%s_%s_SECRET", strings.ToUpper(kind), strings.ToUpper(upload.Name))
|
||||
pwd, ok := ctx.Env[key]
|
||||
if !ok {
|
||||
return "", misconfigured(kind, upload, fmt.Sprintf("missing %s environment variable", key))
|
||||
}
|
||||
return pwd, nil
|
||||
return ctx.Env[key]
|
||||
}
|
||||
|
||||
func misconfigured(kind string, upload *config.Upload, reason string) error {
|
||||
@ -204,15 +203,10 @@ func uploadWithFilter(ctx *context.Context, upload *config.Upload, filter artifa
|
||||
|
||||
// uploadAsset uploads file to target and logs all actions.
|
||||
func uploadAsset(ctx *context.Context, upload *config.Upload, artifact *artifact.Artifact, kind string, check ResponseChecker) error {
|
||||
username, err := getUsername(ctx, upload, kind)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret, err := getPassword(ctx, upload, kind)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// username and secret are optional since the server may not support/need
|
||||
// basic authentication always
|
||||
username := getUsername(ctx, upload, kind)
|
||||
secret := getPassword(ctx, upload, kind)
|
||||
|
||||
// Generate the target url
|
||||
targetURL, err := resolveTargetTemplate(ctx, upload, artifact)
|
||||
@ -268,7 +262,6 @@ func uploadAsset(ctx *context.Context, upload *config.Upload, artifact *artifact
|
||||
msg := fmt.Sprintf("%s: upload failed", kind)
|
||||
log.WithError(err).WithFields(log.Fields{
|
||||
"instance": upload.Name,
|
||||
"username": username,
|
||||
}).Error(msg)
|
||||
return fmt.Errorf("%s: %w", msg, err)
|
||||
}
|
||||
@ -301,7 +294,10 @@ func newUploadRequest(ctx *context.Context, method, target, username, secret str
|
||||
return nil, err
|
||||
}
|
||||
req.ContentLength = a.Size
|
||||
req.SetBasicAuth(username, secret)
|
||||
|
||||
if username != "" && secret != "" {
|
||||
req.SetBasicAuth(username, secret)
|
||||
}
|
||||
|
||||
for k, v := range headers {
|
||||
req.Header.Add(k, v)
|
||||
|
@ -93,6 +93,8 @@ func TestCheckConfig(t *testing.T) {
|
||||
{"secret missing", args{ctx, &config.Upload{Name: "b", Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, true},
|
||||
{"target missing", args{ctx, &config.Upload{Name: "a", Username: "pepe", Mode: ModeArchive}, "test"}, true},
|
||||
{"name missing", args{ctx, &config.Upload{Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, true},
|
||||
{"username missing", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Mode: ModeArchive}, "test"}, true},
|
||||
{"username present", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, false},
|
||||
{"mode missing", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Username: "pepe"}, "test"}, true},
|
||||
{"mode invalid", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Username: "pepe", Mode: "blabla"}, "test"}, true},
|
||||
{"cert invalid", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Username: "pepe", Mode: ModeBinary, TrustedCerts: "bad cert!"}, "test"}, true},
|
||||
@ -104,6 +106,24 @@ func TestCheckConfig(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
delete(ctx.Env, "TEST_A_SECRET")
|
||||
|
||||
tests = []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{"username missing", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Mode: ModeArchive}, "test"}, false},
|
||||
{"username present", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := CheckConfig(tt.args.ctx, tt.args.upload, tt.args.kind); (err != nil) != tt.wantErr {
|
||||
t.Errorf("CheckConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type check struct {
|
||||
|
@ -11,19 +11,18 @@ You can declare multiple `uploads` instances. All binaries generated by your
|
||||
`builds` section will be pushed to each configured upload.
|
||||
|
||||
If you have only one `uploads` instance, the configuration is as easy as adding
|
||||
the upload target and a username to your `.goreleaser.yml` file:
|
||||
the upload target and a name to your `.goreleaser.yml` file:
|
||||
|
||||
```yaml
|
||||
uploads:
|
||||
- name: production
|
||||
target: http://some.server/some/path/example-repo-local/{{ .ProjectName }}/{{ .Version }}/
|
||||
username: goreleaser
|
||||
```
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- An HTTP server accepting HTTP requests
|
||||
- A user + password with grants to upload an artifact using HTTP requests (if the server requires it)
|
||||
- A user + password with grants to upload an artifact using HTTP requests for basic authentication (only if the server requires it)
|
||||
|
||||
### Target
|
||||
|
||||
@ -60,7 +59,7 @@ generated by `nfpm` and the like.
|
||||
Your configured username needs to be valid against your HTTP server.
|
||||
|
||||
You can have the username set in the configuration file as shown above
|
||||
or you can have it read from and environment variable.
|
||||
or you can have it read from an environment variable.
|
||||
The configured name of your HTTP server will be used to build the environment
|
||||
variable name.
|
||||
This way we support auth for multiple instances.
|
||||
@ -75,9 +74,11 @@ The name will be transformed to uppercase.
|
||||
If a configured username is found in the configuration file, then the
|
||||
environment variable is not used at all.
|
||||
|
||||
This field is optional and is used only for basic http authentication.
|
||||
|
||||
### Password
|
||||
|
||||
The password will be stored in a environment variable.
|
||||
The password will be stored in an environment variable.
|
||||
The configured name of your HTTP server will be used.
|
||||
This way we support auth for multiple instances.
|
||||
This also means that the `name` per configured instance needs to be unique
|
||||
@ -88,6 +89,8 @@ If your instance is named `production`, you need to store the secret in the
|
||||
environment variable `UPLOAD_PRODUCTION_SECRET`.
|
||||
The name will be transformed to uppercase.
|
||||
|
||||
This field is optional and is used only for basic http authentication.
|
||||
|
||||
### Server authentication
|
||||
|
||||
You can authenticate your TLS server adding a trusted X.509 certificate chain
|
||||
@ -153,7 +156,7 @@ uploads:
|
||||
# target: https://some.server/some/path/example-repo-local/{{ .ArtifactName }};deb.distribution=xenial
|
||||
custom_artifact_name: true
|
||||
|
||||
# User that will be used for the deployment
|
||||
# An optional username that will be used for the deployment for basic authn
|
||||
username: deployuser
|
||||
|
||||
# An optional header you can use to tell GoReleaser to pass the artifact's
|
||||
|
Loading…
x
Reference in New Issue
Block a user