remove passphrase

This commit is contained in:
Valentin Maerten
2025-11-29 19:38:01 +01:00
parent 8e8eb13d69
commit fa2f6ffd4d
12 changed files with 34 additions and 144 deletions

View File

@@ -105,10 +105,9 @@ complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled GENTLE_FORCE" -l
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l offline -d 'use only local or cached Taskfiles' complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l offline -d 'use only local or cached Taskfiles'
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l timeout -d 'timeout for remote Taskfile downloads' complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l timeout -d 'timeout for remote Taskfile downloads'
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l expiry -d 'cache expiry duration' complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l expiry -d 'cache expiry duration'
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l cacert -d 'custom CA certificate for TLS' -r complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l cacert -d 'custom CA certificate for TLS' -r
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l cert -d 'client certificate for mTLS' -r complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l cert -d 'client certificate for mTLS' -r
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l cert-key -d 'client certificate private key' -r complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l cert-key -d 'client certificate private key' -r
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l cert-key-pass -d 'passphrase for private key'
# RemoteTaskfiles experiment - Operations # RemoteTaskfiles experiment - Operations
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l download -d 'download remote Taskfile' complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l download -d 'download remote Taskfile'

View File

@@ -75,7 +75,6 @@ Register-ArgumentCompleter -CommandName task -ScriptBlock {
$completions += [CompletionResult]::new('--cacert', '--cacert', [CompletionResultType]::ParameterName, 'custom CA certificate') $completions += [CompletionResult]::new('--cacert', '--cacert', [CompletionResultType]::ParameterName, 'custom CA certificate')
$completions += [CompletionResult]::new('--cert', '--cert', [CompletionResultType]::ParameterName, 'client certificate') $completions += [CompletionResult]::new('--cert', '--cert', [CompletionResultType]::ParameterName, 'client certificate')
$completions += [CompletionResult]::new('--cert-key', '--cert-key', [CompletionResultType]::ParameterName, 'client private key') $completions += [CompletionResult]::new('--cert-key', '--cert-key', [CompletionResultType]::ParameterName, 'client private key')
$completions += [CompletionResult]::new('--cert-key-pass', '--cert-key-pass', [CompletionResultType]::ParameterName, 'private key passphrase')
# Operations # Operations
$completions += [CompletionResult]::new('--download', '--download', [CompletionResultType]::ParameterName, 'download remote Taskfile') $completions += [CompletionResult]::new('--download', '--download', [CompletionResultType]::ParameterName, 'download remote Taskfile')
$completions += [CompletionResult]::new('--clear-cache', '--clear-cache', [CompletionResultType]::ParameterName, 'clear cache') $completions += [CompletionResult]::new('--clear-cache', '--clear-cache', [CompletionResultType]::ParameterName, 'clear cache')

View File

@@ -89,7 +89,6 @@ _task() {
'(--cacert)--cacert[custom CA certificate for TLS]:file:_files' '(--cacert)--cacert[custom CA certificate for TLS]:file:_files'
'(--cert)--cert[client certificate for mTLS]:file:_files' '(--cert)--cert[client certificate for mTLS]:file:_files'
'(--cert-key)--cert-key[client certificate private key]:file:_files' '(--cert-key)--cert-key[client certificate private key]:file:_files'
'(--cert-key-pass)--cert-key-pass[passphrase for private key]: '
) )
fi fi

View File

@@ -39,7 +39,6 @@ type (
CACert string CACert string
Cert string Cert string
CertKey string CertKey string
CertKeyPass string
Watch bool Watch bool
Verbose bool Verbose bool
Silent bool Silent bool
@@ -296,19 +295,6 @@ func (o *certKeyOption) ApplyToExecutor(e *Executor) {
e.CertKey = o.certKey e.CertKey = o.certKey
} }
// WithCertKeyPass sets the passphrase for the client certificate key.
func WithCertKeyPass(certKeyPass string) ExecutorOption {
return &certKeyPassOption{certKeyPass: certKeyPass}
}
type certKeyPassOption struct {
certKeyPass string
}
func (o *certKeyPassOption) ApplyToExecutor(e *Executor) {
e.CertKeyPass = o.certKeyPass
}
// WithWatch tells the [Executor] to keep running in the background and watch // WithWatch tells the [Executor] to keep running in the background and watch
// for changes to the fingerprint of the tasks that are run. When changes are // for changes to the fingerprint of the tasks that are run. When changes are
// detected, a new task run is triggered. // detected, a new task run is triggered.

View File

@@ -79,7 +79,6 @@ var (
CACert string CACert string
Cert string Cert string
CertKey string CertKey string
CertKeyPass string
) )
func init() { func init() {
@@ -162,7 +161,6 @@ func init() {
pflag.StringVar(&CACert, "cacert", getConfig(config, func() *string { return config.Remote.CACert }, ""), "Path to a custom CA certificate for HTTPS connections.") pflag.StringVar(&CACert, "cacert", getConfig(config, func() *string { return config.Remote.CACert }, ""), "Path to a custom CA certificate for HTTPS connections.")
pflag.StringVar(&Cert, "cert", getConfig(config, func() *string { return config.Remote.Cert }, ""), "Path to a client certificate for HTTPS connections.") pflag.StringVar(&Cert, "cert", getConfig(config, func() *string { return config.Remote.Cert }, ""), "Path to a client certificate for HTTPS connections.")
pflag.StringVar(&CertKey, "cert-key", getConfig(config, func() *string { return config.Remote.CertKey }, ""), "Path to a client certificate key for HTTPS connections.") pflag.StringVar(&CertKey, "cert-key", getConfig(config, func() *string { return config.Remote.CertKey }, ""), "Path to a client certificate key for HTTPS connections.")
pflag.StringVar(&CertKeyPass, "cert-key-pass", getConfig(config, func() *string { return config.Remote.CertKeyPass }, ""), "Passphrase for the client certificate key.")
} }
pflag.Parse() pflag.Parse()
} }
@@ -213,10 +211,6 @@ func Validate() error {
return errors.New("task: --cert and --cert-key must be provided together") return errors.New("task: --cert and --cert-key must be provided together")
} }
if CertKeyPass != "" && Cert == "" {
return errors.New("task: --cert-key-pass requires --cert and --cert-key")
}
return nil return nil
} }
@@ -260,7 +254,6 @@ func (o *flagsOption) ApplyToExecutor(e *task.Executor) {
task.WithCACert(CACert), task.WithCACert(CACert),
task.WithCert(Cert), task.WithCert(Cert),
task.WithCertKey(CertKey), task.WithCertKey(CertKey),
task.WithCertKeyPass(CertKeyPass),
task.WithWatch(Watch), task.WithWatch(Watch),
task.WithVerbose(Verbose), task.WithVerbose(Verbose),
task.WithSilent(Silent), task.WithSilent(Silent),

View File

@@ -60,7 +60,6 @@ func (e *Executor) getRootNode() (taskfile.Node, error) {
taskfile.WithCACert(e.CACert), taskfile.WithCACert(e.CACert),
taskfile.WithCert(e.Cert), taskfile.WithCert(e.Cert),
taskfile.WithCertKey(e.CertKey), taskfile.WithCertKey(e.CertKey),
taskfile.WithCertKeyPass(e.CertKeyPass),
) )
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, errors.TaskfileNotFoundError{ return nil, errors.TaskfileNotFoundError{
@@ -94,7 +93,6 @@ func (e *Executor) readTaskfile(node taskfile.Node) error {
taskfile.WithReaderCACert(e.CACert), taskfile.WithReaderCACert(e.CACert),
taskfile.WithReaderCert(e.Cert), taskfile.WithReaderCert(e.Cert),
taskfile.WithReaderCertKey(e.CertKey), taskfile.WithReaderCertKey(e.CertKey),
taskfile.WithReaderCertKeyPass(e.CertKeyPass),
taskfile.WithDebugFunc(debugFunc), taskfile.WithDebugFunc(debugFunc),
taskfile.WithPromptFunc(promptFunc), taskfile.WithPromptFunc(promptFunc),
) )

View File

@@ -7,13 +7,12 @@ type (
// designed to be embedded in other node types so that this boilerplate code // designed to be embedded in other node types so that this boilerplate code
// does not need to be repeated. // does not need to be repeated.
baseNode struct { baseNode struct {
parent Node parent Node
dir string dir string
checksum string checksum string
caCert string caCert string
cert string cert string
certKey string certKey string
certKeyPass string
} }
) )
@@ -76,9 +75,3 @@ func WithCertKey(certKey string) NodeOption {
node.certKey = certKey node.certKey = certKey
} }
} }
func WithCertKeyPass(certKeyPass string) NodeOption {
return func(node *baseNode) {
node.certKeyPass = certKeyPass
}
}

View File

@@ -26,7 +26,7 @@ type HTTPNode struct {
// buildHTTPClient creates an HTTP client with optional TLS configuration. // buildHTTPClient creates an HTTP client with optional TLS configuration.
// If no certificate options are provided, it returns http.DefaultClient. // If no certificate options are provided, it returns http.DefaultClient.
func buildHTTPClient(insecure bool, caCert, cert, certKey, certKeyPass string) (*http.Client, error) { func buildHTTPClient(insecure bool, caCert, cert, certKey string) (*http.Client, error) {
// Validate that cert and certKey are provided together // Validate that cert and certKey are provided together
if (cert != "" && certKey == "") || (cert == "" && certKey != "") { if (cert != "" && certKey == "") || (cert == "" && certKey != "") {
return nil, fmt.Errorf("both --cert and --cert-key must be provided together") return nil, fmt.Errorf("both --cert and --cert-key must be provided together")
@@ -56,15 +56,7 @@ func buildHTTPClient(insecure bool, caCert, cert, certKey, certKeyPass string) (
// Load client certificate and key if provided // Load client certificate and key if provided
if cert != "" && certKey != "" { if cert != "" && certKey != "" {
var clientCert tls.Certificate clientCert, err := tls.LoadX509KeyPair(cert, certKey)
var err error
if certKeyPass != "" {
// Load encrypted private key
clientCert, err = loadCertWithEncryptedKey(cert, certKey, certKeyPass)
} else {
clientCert, err = tls.LoadX509KeyPair(cert, certKey)
}
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load client certificate: %w", err) return nil, fmt.Errorf("failed to load client certificate: %w", err)
} }
@@ -78,46 +70,6 @@ func buildHTTPClient(insecure bool, caCert, cert, certKey, certKeyPass string) (
}, nil }, nil
} }
// loadCertWithEncryptedKey loads a certificate with an encrypted private key.
func loadCertWithEncryptedKey(certFile, keyFile, passphrase string) (tls.Certificate, error) {
certPEM, err := os.ReadFile(certFile)
if err != nil {
return tls.Certificate{}, fmt.Errorf("failed to read certificate file: %w", err)
}
keyPEM, err := os.ReadFile(keyFile)
if err != nil {
return tls.Certificate{}, fmt.Errorf("failed to read key file: %w", err)
}
// Try to decrypt the private key
decryptedKey, err := decryptPEMKey(keyPEM, passphrase)
if err != nil {
return tls.Certificate{}, fmt.Errorf("failed to decrypt private key: %w", err)
}
return tls.X509KeyPair(certPEM, decryptedKey)
}
// decryptPEMKey attempts to decrypt a PEM-encoded private key.
func decryptPEMKey(keyPEM []byte, passphrase string) ([]byte, error) {
// For PKCS#8 encrypted keys, we need to parse and decrypt them
// The standard library doesn't directly support encrypted PKCS#8,
// so we try to parse it as-is first (in case it's not actually encrypted)
// For now, we support unencrypted keys and return an error for encrypted ones
// that require external libraries to decrypt.
// Try to parse as unencrypted first
_, err := tls.X509KeyPair([]byte("-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----"), keyPEM)
if err == nil {
return keyPEM, nil
}
// TODO: Add support for encrypted PKCS#8 keys using x/crypto/pkcs8
// This would require adding a dependency on golang.org/x/crypto
return nil, fmt.Errorf("encrypted private keys require the key to be decrypted externally, or use an unencrypted key")
}
func NewHTTPNode( func NewHTTPNode(
entrypoint string, entrypoint string,
dir string, dir string,
@@ -134,7 +86,7 @@ func NewHTTPNode(
} }
// Build HTTP client with TLS configuration from node options // Build HTTP client with TLS configuration from node options
client, err := buildHTTPClient(insecure, base.caCert, base.cert, base.certKey, base.certKeyPass) client, err := buildHTTPClient(insecure, base.caCert, base.cert, base.certKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -63,7 +63,7 @@ func TestBuildHTTPClient_Default(t *testing.T) {
t.Parallel() t.Parallel()
// When no TLS customization is needed, should return http.DefaultClient // When no TLS customization is needed, should return http.DefaultClient
client, err := buildHTTPClient(false, "", "", "", "") client, err := buildHTTPClient(false, "", "", "")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, http.DefaultClient, client) assert.Equal(t, http.DefaultClient, client)
} }
@@ -71,7 +71,7 @@ func TestBuildHTTPClient_Default(t *testing.T) {
func TestBuildHTTPClient_Insecure(t *testing.T) { func TestBuildHTTPClient_Insecure(t *testing.T) {
t.Parallel() t.Parallel()
client, err := buildHTTPClient(true, "", "", "", "") client, err := buildHTTPClient(true, "", "", "")
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, client) require.NotNil(t, client)
assert.NotEqual(t, http.DefaultClient, client) assert.NotEqual(t, http.DefaultClient, client)
@@ -92,10 +92,10 @@ func TestBuildHTTPClient_CACert(t *testing.T) {
// Generate a valid CA certificate // Generate a valid CA certificate
caCertPEM := generateTestCACert(t) caCertPEM := generateTestCACert(t)
err := os.WriteFile(caCertPath, caCertPEM, 0600) err := os.WriteFile(caCertPath, caCertPEM, 0o600)
require.NoError(t, err) require.NoError(t, err)
client, err := buildHTTPClient(false, caCertPath, "", "", "") client, err := buildHTTPClient(false, caCertPath, "", "")
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, client) require.NotNil(t, client)
assert.NotEqual(t, http.DefaultClient, client) assert.NotEqual(t, http.DefaultClient, client)
@@ -110,7 +110,7 @@ func TestBuildHTTPClient_CACert(t *testing.T) {
func TestBuildHTTPClient_CACertNotFound(t *testing.T) { func TestBuildHTTPClient_CACertNotFound(t *testing.T) {
t.Parallel() t.Parallel()
client, err := buildHTTPClient(false, "/nonexistent/ca.crt", "", "", "") client, err := buildHTTPClient(false, "/nonexistent/ca.crt", "", "")
assert.Error(t, err) assert.Error(t, err)
assert.Nil(t, client) assert.Nil(t, client)
assert.Contains(t, err.Error(), "failed to read CA certificate") assert.Contains(t, err.Error(), "failed to read CA certificate")
@@ -122,10 +122,10 @@ func TestBuildHTTPClient_CACertInvalid(t *testing.T) {
// Create a temporary file with invalid content // Create a temporary file with invalid content
tempDir := t.TempDir() tempDir := t.TempDir()
caCertPath := filepath.Join(tempDir, "invalid.crt") caCertPath := filepath.Join(tempDir, "invalid.crt")
err := os.WriteFile(caCertPath, []byte("not a valid certificate"), 0600) err := os.WriteFile(caCertPath, []byte("not a valid certificate"), 0o600)
require.NoError(t, err) require.NoError(t, err)
client, err := buildHTTPClient(false, caCertPath, "", "", "") client, err := buildHTTPClient(false, caCertPath, "", "")
assert.Error(t, err) assert.Error(t, err)
assert.Nil(t, client) assert.Nil(t, client)
assert.Contains(t, err.Error(), "failed to parse CA certificate") assert.Contains(t, err.Error(), "failed to parse CA certificate")
@@ -134,7 +134,7 @@ func TestBuildHTTPClient_CACertInvalid(t *testing.T) {
func TestBuildHTTPClient_CertWithoutKey(t *testing.T) { func TestBuildHTTPClient_CertWithoutKey(t *testing.T) {
t.Parallel() t.Parallel()
client, err := buildHTTPClient(false, "", "/path/to/cert.crt", "", "") client, err := buildHTTPClient(false, "", "/path/to/cert.crt", "")
assert.Error(t, err) assert.Error(t, err)
assert.Nil(t, client) assert.Nil(t, client)
assert.Contains(t, err.Error(), "both --cert and --cert-key must be provided together") assert.Contains(t, err.Error(), "both --cert and --cert-key must be provided together")
@@ -143,7 +143,7 @@ func TestBuildHTTPClient_CertWithoutKey(t *testing.T) {
func TestBuildHTTPClient_KeyWithoutCert(t *testing.T) { func TestBuildHTTPClient_KeyWithoutCert(t *testing.T) {
t.Parallel() t.Parallel()
client, err := buildHTTPClient(false, "", "", "/path/to/key.pem", "") client, err := buildHTTPClient(false, "", "", "/path/to/key.pem")
assert.Error(t, err) assert.Error(t, err)
assert.Nil(t, client) assert.Nil(t, client)
assert.Contains(t, err.Error(), "both --cert and --cert-key must be provided together") assert.Contains(t, err.Error(), "both --cert and --cert-key must be provided together")
@@ -159,12 +159,12 @@ func TestBuildHTTPClient_CertAndKey(t *testing.T) {
// Generate a self-signed certificate and key for testing // Generate a self-signed certificate and key for testing
cert, key := generateTestCertAndKey(t) cert, key := generateTestCertAndKey(t)
err := os.WriteFile(certPath, cert, 0600) err := os.WriteFile(certPath, cert, 0o600)
require.NoError(t, err) require.NoError(t, err)
err = os.WriteFile(keyPath, key, 0600) err = os.WriteFile(keyPath, key, 0o600)
require.NoError(t, err) require.NoError(t, err)
client, err := buildHTTPClient(false, "", certPath, keyPath, "") client, err := buildHTTPClient(false, "", certPath, keyPath)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, client) require.NotNil(t, client)
assert.NotEqual(t, http.DefaultClient, client) assert.NotEqual(t, http.DefaultClient, client)
@@ -179,7 +179,7 @@ func TestBuildHTTPClient_CertAndKey(t *testing.T) {
func TestBuildHTTPClient_CertNotFound(t *testing.T) { func TestBuildHTTPClient_CertNotFound(t *testing.T) {
t.Parallel() t.Parallel()
client, err := buildHTTPClient(false, "", "/nonexistent/cert.crt", "/nonexistent/key.pem", "") client, err := buildHTTPClient(false, "", "/nonexistent/cert.crt", "/nonexistent/key.pem")
assert.Error(t, err) assert.Error(t, err)
assert.Nil(t, client) assert.Nil(t, client)
assert.Contains(t, err.Error(), "failed to load client certificate") assert.Contains(t, err.Error(), "failed to load client certificate")
@@ -194,11 +194,11 @@ func TestBuildHTTPClient_InsecureWithCACert(t *testing.T) {
// Generate a valid CA certificate // Generate a valid CA certificate
caCertPEM := generateTestCACert(t) caCertPEM := generateTestCACert(t)
err := os.WriteFile(caCertPath, caCertPEM, 0600) err := os.WriteFile(caCertPath, caCertPEM, 0o600)
require.NoError(t, err) require.NoError(t, err)
// Both insecure and CA cert can be set together // Both insecure and CA cert can be set together
client, err := buildHTTPClient(true, caCertPath, "", "", "") client, err := buildHTTPClient(true, caCertPath, "", "")
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, client) require.NotNil(t, client)

View File

@@ -48,7 +48,6 @@ type (
caCert string caCert string
cert string cert string
certKey string certKey string
certKeyPass string
debugFunc DebugFunc debugFunc DebugFunc
promptFunc PromptFunc promptFunc PromptFunc
promptMutex sync.Mutex promptMutex sync.Mutex
@@ -225,19 +224,6 @@ func (o *readerCertKeyOption) ApplyToReader(r *Reader) {
r.certKey = o.certKey r.certKey = o.certKey
} }
// WithReaderCertKeyPass sets the passphrase for the client certificate key.
func WithReaderCertKeyPass(certKeyPass string) ReaderOption {
return &readerCertKeyPassOption{certKeyPass: certKeyPass}
}
type readerCertKeyPassOption struct {
certKeyPass string
}
func (o *readerCertKeyPassOption) ApplyToReader(r *Reader) {
r.certKeyPass = o.certKeyPass
}
// Read will read the Taskfile defined by the [Reader]'s [Node] and recurse // Read will read the Taskfile defined by the [Reader]'s [Node] and recurse
// through any [ast.Includes] it finds, reading each included Taskfile and // through any [ast.Includes] it finds, reading each included Taskfile and
// building an [ast.TaskfileGraph] as it goes. If any errors occur, they will be // building an [ast.TaskfileGraph] as it goes. If any errors occur, they will be
@@ -328,7 +314,6 @@ func (r *Reader) include(ctx context.Context, node Node) error {
WithCACert(r.caCert), WithCACert(r.caCert),
WithCert(r.cert), WithCert(r.cert),
WithCertKey(r.certKey), WithCertKey(r.certKey),
WithCertKeyPass(r.certKeyPass),
) )
if err != nil { if err != nil {
if include.Optional { if include.Optional {

View File

@@ -24,7 +24,6 @@ type Remote struct {
CACert *string `yaml:"cacert"` CACert *string `yaml:"cacert"`
Cert *string `yaml:"cert"` Cert *string `yaml:"cert"`
CertKey *string `yaml:"cert-key"` CertKey *string `yaml:"cert-key"`
CertKeyPass *string `yaml:"cert-key-pass"`
} }
// Merge combines the current TaskRC with another TaskRC, prioritizing non-nil fields from the other TaskRC. // Merge combines the current TaskRC with another TaskRC, prioritizing non-nil fields from the other TaskRC.
@@ -49,7 +48,6 @@ func (t *TaskRC) Merge(other *TaskRC) {
t.Remote.CACert = cmp.Or(other.Remote.CACert, t.Remote.CACert) t.Remote.CACert = cmp.Or(other.Remote.CACert, t.Remote.CACert)
t.Remote.Cert = cmp.Or(other.Remote.Cert, t.Remote.Cert) t.Remote.Cert = cmp.Or(other.Remote.Cert, t.Remote.Cert)
t.Remote.CertKey = cmp.Or(other.Remote.CertKey, t.Remote.CertKey) t.Remote.CertKey = cmp.Or(other.Remote.CertKey, t.Remote.CertKey)
t.Remote.CertKeyPass = cmp.Or(other.Remote.CertKeyPass, t.Remote.CertKeyPass)
t.Verbose = cmp.Or(other.Verbose, t.Verbose) t.Verbose = cmp.Or(other.Verbose, t.Verbose)
t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency) t.Concurrency = cmp.Or(other.Concurrency, t.Concurrency)

View File

@@ -279,16 +279,17 @@ task --taskfile https://secure.example.com/Taskfile.yml \
--cert-key /path/to/client.key --cert-key /path/to/client.key
``` ```
If your private key is encrypted with a passphrase, you can provide it using ::: warning
the `--cert-key-pass` flag:
Encrypted private keys are not currently supported. If your key is encrypted,
you must decrypt it first:
```shell ```shell
task --taskfile https://secure.example.com/Taskfile.yml \ openssl rsa -in encrypted.key -out decrypted.key
--cert /path/to/client.crt \
--cert-key /path/to/client.key \
--cert-key-pass "your-passphrase"
``` ```
:::
These options can also be configured in the [configuration file](#configuration). These options can also be configured in the [configuration file](#configuration).
## Caching & Running Offline ## Caching & Running Offline
@@ -339,7 +340,6 @@ remote:
cacert: "" cacert: ""
cert: "" cert: ""
cert-key: "" cert-key: ""
cert-key-pass: ""
``` ```
#### `insecure` #### `insecure`
@@ -421,15 +421,3 @@ remote:
remote: remote:
cert-key: "/path/to/client.key" cert-key: "/path/to/client.key"
``` ```
#### `cert-key-pass`
- **Type**: `string`
- **Default**: `""`
- **Description**: Passphrase for the client certificate private key (if
encrypted)
```yaml
remote:
cert-key-pass: "your-passphrase"
```