feat: enable remote taskfiles (#2906)

This commit is contained in:
Pete Davison
2026-08-13 14:38:10 +01:00
committed by GitHub
parent 37898d9102
commit 87076b165f
18 changed files with 842 additions and 659 deletions

View File

@@ -1,4 +1,3 @@
experiments: experiments:
GENTLE_FORCE: 0 GENTLE_FORCE: 0
REMOTE_TASKFILES: 0
ENV_PRECEDENCE: 0 ENV_PRECEDENCE: 0

View File

@@ -101,20 +101,16 @@ complete -c $GO_TASK_PROGNAME -s v -l verbose -d 'verbose outp
complete -c $GO_TASK_PROGNAME -l version -d 'show version' complete -c $GO_TASK_PROGNAME -l version -d 'show version'
complete -c $GO_TASK_PROGNAME -s w -l watch -d 'watch mode, re-run on changes' complete -c $GO_TASK_PROGNAME -s w -l watch -d 'watch mode, re-run on changes'
complete -c $GO_TASK_PROGNAME -s y -l yes -d 'assume yes to all prompts' complete -c $GO_TASK_PROGNAME -s y -l yes -d 'assume yes to all prompts'
complete -c $GO_TASK_PROGNAME -l offline -d 'use only local or cached Taskfiles'
complete -c $GO_TASK_PROGNAME -l timeout -d 'timeout for remote Taskfile downloads'
complete -c $GO_TASK_PROGNAME -l expiry -d 'cache expiry duration'
complete -c $GO_TASK_PROGNAME -l remote-cache-dir -d 'directory to cache remote Taskfiles' -xa "(__fish_complete_directories)"
complete -c $GO_TASK_PROGNAME -l cacert -d 'custom CA certificate for TLS' -r
complete -c $GO_TASK_PROGNAME -l cert -d 'client certificate for mTLS' -r
complete -c $GO_TASK_PROGNAME -l cert-key -d 'client certificate private key' -r
complete -c $GO_TASK_PROGNAME -l download -d 'download remote Taskfile'
complete -c $GO_TASK_PROGNAME -l clear-cache -d 'clear remote Taskfile cache'
# Experimental flags (dynamically checked at completion time via -n condition) # Experimental flags (dynamically checked at completion time via -n condition)
# GentleForce experiment # GentleForce experiment
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled GENTLE_FORCE" -l force-all -d 'force execution of task and all dependencies' complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled GENTLE_FORCE" -l force-all -d 'force execution of task and all dependencies'
# RemoteTaskfiles experiment - Options
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 expiry -d 'cache expiry duration'
complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l remote-cache-dir -d 'directory to cache remote Taskfiles' -xa "(__fish_complete_directories)"
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-key -d 'client certificate private key' -r
# 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 clear-cache -d 'clear remote Taskfile cache'

View File

@@ -63,7 +63,16 @@ Register-ArgumentCompleter -CommandName $cmdNames -ScriptBlock {
[CompletionResult]::new('-w', '-w', [CompletionResultType]::ParameterName, 'watch mode'), [CompletionResult]::new('-w', '-w', [CompletionResultType]::ParameterName, 'watch mode'),
[CompletionResult]::new('--watch', '--watch', [CompletionResultType]::ParameterName, 'watch mode'), [CompletionResult]::new('--watch', '--watch', [CompletionResultType]::ParameterName, 'watch mode'),
[CompletionResult]::new('-y', '-y', [CompletionResultType]::ParameterName, 'assume yes'), [CompletionResult]::new('-y', '-y', [CompletionResultType]::ParameterName, 'assume yes'),
[CompletionResult]::new('--yes', '--yes', [CompletionResultType]::ParameterName, 'assume yes') [CompletionResult]::new('--yes', '--yes', [CompletionResultType]::ParameterName, 'assume yes'),
[CompletionResult]::new('--offline', '--offline', [CompletionResultType]::ParameterName, 'use cached Taskfiles'),
[CompletionResult]::new('--timeout', '--timeout', [CompletionResultType]::ParameterName, 'download timeout'),
[CompletionResult]::new('--expiry', '--expiry', [CompletionResultType]::ParameterName, 'cache expiry'),
[CompletionResult]::new('--remote-cache-dir', '--remote-cache-dir', [CompletionResultType]::ParameterName, 'cache directory'),
[CompletionResult]::new('--cacert', '--cacert', [CompletionResultType]::ParameterName, 'custom CA certificate'),
[CompletionResult]::new('--cert', '--cert', [CompletionResultType]::ParameterName, 'client certificate'),
[CompletionResult]::new('--cert-key', '--cert-key', [CompletionResultType]::ParameterName, 'client private key'),
[CompletionResult]::new('--download', '--download', [CompletionResultType]::ParameterName, 'download remote Taskfile'),
[CompletionResult]::new('--clear-cache', '--clear-cache', [CompletionResultType]::ParameterName, 'clear cache')
) )
# Experimental flags (dynamically added based on enabled experiments) # Experimental flags (dynamically added based on enabled experiments)
@@ -73,20 +82,6 @@ Register-ArgumentCompleter -CommandName $cmdNames -ScriptBlock {
$completions += [CompletionResult]::new('--force-all', '--force-all', [CompletionResultType]::ParameterName, 'force all dependencies') $completions += [CompletionResult]::new('--force-all', '--force-all', [CompletionResultType]::ParameterName, 'force all dependencies')
} }
if ($experiments -match '\* REMOTE_TASKFILES:.*on') {
# Options
$completions += [CompletionResult]::new('--offline', '--offline', [CompletionResultType]::ParameterName, 'use cached Taskfiles')
$completions += [CompletionResult]::new('--timeout', '--timeout', [CompletionResultType]::ParameterName, 'download timeout')
$completions += [CompletionResult]::new('--expiry', '--expiry', [CompletionResultType]::ParameterName, 'cache expiry')
$completions += [CompletionResult]::new('--remote-cache-dir', '--remote-cache-dir', [CompletionResultType]::ParameterName, 'cache directory')
$completions += [CompletionResult]::new('--cacert', '--cacert', [CompletionResultType]::ParameterName, 'custom CA certificate')
$completions += [CompletionResult]::new('--cert', '--cert', [CompletionResultType]::ParameterName, 'client certificate')
$completions += [CompletionResult]::new('--cert-key', '--cert-key', [CompletionResultType]::ParameterName, 'client private key')
# Operations
$completions += [CompletionResult]::new('--download', '--download', [CompletionResultType]::ParameterName, 'download remote Taskfile')
$completions += [CompletionResult]::new('--clear-cache', '--clear-cache', [CompletionResultType]::ParameterName, 'clear cache')
}
return $completions.Where{ $_.CompletionText.StartsWith($commandName) } return $completions.Where{ $_.CompletionText.StartsWith($commandName) }
} }

View File

@@ -120,16 +120,7 @@ _task() {
'(-v --verbose)'{-v,--verbose}'[verbose mode]' '(-v --verbose)'{-v,--verbose}'[verbose mode]'
'(-w --watch)'{-w,--watch}'[watch-mode for given tasks, re-run when inputs change]' '(-w --watch)'{-w,--watch}'[watch-mode for given tasks, re-run when inputs change]'
'(-y --yes)'{-y,--yes}'[assume yes to all prompts]' '(-y --yes)'{-y,--yes}'[assume yes to all prompts]'
) '(--offline --clear-cache)--download[download remote Taskfile]'
# Experimental flags (dynamically added based on enabled experiments)
# Options (modify behavior)
if __task_is_experiment_enabled "GENTLE_FORCE"; then
standard_args+=('(--force-all)--force-all[force execution of task and all dependencies]')
fi
if __task_is_experiment_enabled "REMOTE_TASKFILES"; then
standard_args+=(
'(--offline --download)--offline[use only local or cached Taskfiles]' '(--offline --download)--offline[use only local or cached Taskfiles]'
'(--timeout)--timeout[timeout for remote Taskfile downloads]:duration: ' '(--timeout)--timeout[timeout for remote Taskfile downloads]:duration: '
'(--expiry)--expiry[cache expiry duration]:duration: ' '(--expiry)--expiry[cache expiry duration]:duration: '
@@ -138,6 +129,11 @@ _task() {
'(--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'
) )
# Experimental flags (dynamically added based on enabled experiments)
# Options (modify behavior)
if __task_is_experiment_enabled "GENTLE_FORCE"; then
standard_args+=('(--force-all)--force-all[force execution of task and all dependencies]')
fi fi
operation_args=( operation_args=(
@@ -150,17 +146,8 @@ _task() {
'(*)'{-i,--init}'[create new Taskfile.yml]' '(*)'{-i,--init}'[create new Taskfile.yml]'
'(- *)'{-h,--help}'[show help]' '(- *)'{-h,--help}'[show help]'
'(- *)--version[show version and exit]' '(- *)--version[show version and exit]'
)
# Experimental operations (dynamically added based on enabled experiments)
if __task_is_experiment_enabled "REMOTE_TASKFILES"; then
standard_args+=(
'(--offline --clear-cache)--download[download remote Taskfile]'
)
operation_args+=(
'(* --download)--clear-cache[clear remote Taskfile cache]' '(* --download)--clear-cache[clear remote Taskfile cache]'
) )
fi
_arguments -S $standard_args $operation_args _arguments -S $standard_args $operation_args
} }

View File

@@ -1,6 +1,7 @@
package experiments package experiments
import ( import (
"cmp"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
@@ -25,11 +26,14 @@ func (err InvalidValueError) Error() string {
type InactiveError struct { type InactiveError struct {
Name string Name string
Reason string
} }
func (err InactiveError) Error() string { func (err InactiveError) Error() string {
reason := cmp.Or(err.Reason, "is inactive and cannot be enabled")
return fmt.Sprintf( return fmt.Sprintf(
"task: Experiment %q is inactive and cannot be enabled", "task: Experiment %q %s",
err.Name, err.Name,
reason,
) )
} }

View File

@@ -12,24 +12,51 @@ type Experiment struct {
Name string // The name of the experiment. Name string // The name of the experiment.
AllowedValues []int // The values that can enable this experiment. AllowedValues []int // The values that can enable this experiment.
Value int // The version of the experiment that is enabled. Value int // The version of the experiment that is enabled.
InactiveReason string // If not active, the reason why it is inactive.
}
func getValue(xName string, config *ast.TaskRC) int {
var value int
if config != nil {
value = config.Experiments[xName]
}
if value == 0 {
value, _ = strconv.Atoi(getEnv(xName))
}
return value
} }
// New creates a new experiment with the given name and sets the values that can // New creates a new experiment with the given name and sets the values that can
// enable it. // enable it.
func New(xName string, config *ast.TaskRC, allowedValues ...int) Experiment { func New(xName string, config *ast.TaskRC, allowedValues ...int) Experiment {
var value int
if config != nil {
value = config.Experiments[xName]
}
if value == 0 {
value, _ = strconv.Atoi(getEnv(xName))
}
x := Experiment{ x := Experiment{
Name: xName, Name: xName,
AllowedValues: allowedValues, AllowedValues: allowedValues,
Value: value, Value: getValue(xName, config),
}
xList = append(xList, x)
return x
}
// NewReleased creates a new experiment that is released and no longer needs to
// be enabled. It will always be inactive and cannot be enabled.
func NewReleased(xName string, config *ast.TaskRC) Experiment {
x := Experiment{
Name: xName,
Value: getValue(xName, config),
InactiveReason: "is released and no longer needs to be enabled",
}
xList = append(xList, x)
return x
}
// NewAbandoned creates a new experiment that has been abandoned and is no
// longer supported. It will always be inactive and cannot be enabled.
func NewAbandoned(xName string, config *ast.TaskRC) Experiment {
x := Experiment{
Name: xName,
Value: getValue(xName, config),
InactiveReason: "has been abandoned and is no longer supported",
} }
xList = append(xList, x) xList = append(xList, x)
return x return x
@@ -47,6 +74,7 @@ func (x Experiment) Valid() error {
if !x.Active() && x.Value != 0 { if !x.Active() && x.Value != 0 {
return &InactiveError{ return &InactiveError{
Name: x.Name, Name: x.Name,
Reason: x.InactiveReason,
} }
} }
if !x.Enabled() && x.Value != 0 { if !x.Enabled() && x.Value != 0 {

View File

@@ -17,7 +17,6 @@ const envPrefix = "TASK_X_"
// Active experiments. // Active experiments.
var ( var (
GentleForce Experiment GentleForce Experiment
RemoteTaskfiles Experiment
EnvPrecedence Experiment EnvPrecedence Experiment
) )
@@ -26,6 +25,7 @@ var (
var ( var (
AnyVariables Experiment AnyVariables Experiment
MapVariables Experiment MapVariables Experiment
RemoteTaskfiles Experiment
) )
// An internal list of all the initialized experiments used for iterating. // An internal list of all the initialized experiments used for iterating.
@@ -41,10 +41,11 @@ func ParseWithConfig(dir string, config *ast.TaskRC) {
readDotEnv(dir) readDotEnv(dir)
// Initialize the experiments // Initialize the experiments
GentleForce = New("GENTLE_FORCE", config, 1) GentleForce = New("GENTLE_FORCE", config, 1)
RemoteTaskfiles = New("REMOTE_TASKFILES", config, 1)
EnvPrecedence = New("ENV_PRECEDENCE", config, 1) EnvPrecedence = New("ENV_PRECEDENCE", config, 1)
AnyVariables = New("ANY_VARIABLES", config) // Inactive experiments
MapVariables = New("MAP_VARIABLES", config) AnyVariables = NewReleased("ANY_VARIABLES", config)
MapVariables = NewReleased("MAP_VARIABLES", config)
RemoteTaskfiles = NewReleased("REMOTE_TASKFILES", config)
} }
// Validate checks if any experiments have been enabled while being inactive. // Validate checks if any experiments have been enabled while being inactive.

View File

@@ -155,18 +155,7 @@ func init() {
pflag.BoolVarP(&Failfast, "failfast", "F", getConfig(config, "FAILFAST", func() *bool { return &config.Failfast }, false), "When running tasks in parallel, stop all tasks if one fails.") pflag.BoolVarP(&Failfast, "failfast", "F", getConfig(config, "FAILFAST", func() *bool { return &config.Failfast }, false), "When running tasks in parallel, stop all tasks if one fails.")
pflag.BoolVarP(&Global, "global", "g", false, "Runs global Taskfile, from $HOME/{T,t}askfile.{yml,yaml}.") pflag.BoolVarP(&Global, "global", "g", false, "Runs global Taskfile, from $HOME/{T,t}askfile.{yml,yaml}.")
pflag.BoolVar(&Experiments, "experiments", false, "Lists all the available experiments and whether or not they are enabled.") pflag.BoolVar(&Experiments, "experiments", false, "Lists all the available experiments and whether or not they are enabled.")
pflag.BoolVar(&Download, "download", false, "Forces task to download remote Taskfiles and ignore any cached versions.")
// Gentle force experiment will override the force flag and add a new force-all flag
if experiments.GentleForce.Enabled() {
pflag.BoolVarP(&Force, "force", "f", false, "Forces execution of the directly called task.")
pflag.BoolVar(&ForceAll, "force-all", false, "Forces execution of the called task and all its dependant tasks.")
} else {
pflag.BoolVarP(&ForceAll, "force", "f", false, "Forces execution even when the task is up-to-date.")
}
// Remote Taskfiles experiment will adds the "download" and "offline" flags
if experiments.RemoteTaskfiles.Enabled() {
pflag.BoolVar(&Download, "download", false, "Downloads a cached version of a remote Taskfile.")
pflag.BoolVar(&Offline, "offline", getConfig(config, "REMOTE_OFFLINE", func() *bool { return config.Remote.Offline }, false), "Forces Task to only use local or cached Taskfiles.") pflag.BoolVar(&Offline, "offline", getConfig(config, "REMOTE_OFFLINE", func() *bool { return config.Remote.Offline }, false), "Forces Task to only use local or cached Taskfiles.")
pflag.StringSliceVar(&TrustedHosts, "trusted-hosts", getConfig(config, "REMOTE_TRUSTED_HOSTS", func() *[]string { return &config.Remote.TrustedHosts }, nil), "List of trusted hosts for remote Taskfiles (comma-separated).") pflag.StringSliceVar(&TrustedHosts, "trusted-hosts", getConfig(config, "REMOTE_TRUSTED_HOSTS", func() *[]string { return &config.Remote.TrustedHosts }, nil), "List of trusted hosts for remote Taskfiles (comma-separated).")
pflag.DurationVar(&Timeout, "timeout", getConfig(config, "REMOTE_TIMEOUT", func() *time.Duration { return config.Remote.Timeout }, time.Second*10), "Timeout for downloading remote Taskfiles.") pflag.DurationVar(&Timeout, "timeout", getConfig(config, "REMOTE_TIMEOUT", func() *time.Duration { return config.Remote.Timeout }, time.Second*10), "Timeout for downloading remote Taskfiles.")
@@ -176,7 +165,15 @@ func init() {
pflag.StringVar(&CACert, "cacert", getConfig(config, "REMOTE_CACERT", func() *string { return config.Remote.CACert }, ""), "Path to a custom CA certificate for HTTPS connections.") pflag.StringVar(&CACert, "cacert", getConfig(config, "REMOTE_CACERT", func() *string { return config.Remote.CACert }, ""), "Path to a custom CA certificate for HTTPS connections.")
pflag.StringVar(&Cert, "cert", getConfig(config, "REMOTE_CERT", func() *string { return config.Remote.Cert }, ""), "Path to a client certificate for HTTPS connections.") pflag.StringVar(&Cert, "cert", getConfig(config, "REMOTE_CERT", func() *string { return config.Remote.Cert }, ""), "Path to a client certificate for HTTPS connections.")
pflag.StringVar(&CertKey, "cert-key", getConfig(config, "REMOTE_CERT_KEY", func() *string { return config.Remote.CertKey }, ""), "Path to a client certificate key for HTTPS connections.") pflag.StringVar(&CertKey, "cert-key", getConfig(config, "REMOTE_CERT_KEY", func() *string { return config.Remote.CertKey }, ""), "Path to a client certificate key for HTTPS connections.")
// Gentle force experiment will override the force flag and add a new force-all flag
if experiments.GentleForce.Enabled() {
pflag.BoolVarP(&Force, "force", "f", false, "Forces execution of the directly called task.")
pflag.BoolVar(&ForceAll, "force-all", false, "Forces execution of the called task and all its dependant tasks.")
} else {
pflag.BoolVarP(&ForceAll, "force", "f", false, "Forces execution even when the task is up-to-date.")
} }
pflag.Parse() pflag.Parse()
// Auto-detect color based on environment when not explicitly configured // Auto-detect color based on environment when not explicitly configured

View File

@@ -1194,8 +1194,6 @@ func TestIncludesMultiLevel(t *testing.T) {
} }
func TestIncludesRemote(t *testing.T) { func TestIncludesRemote(t *testing.T) {
enableExperimentForTest(t, &experiments.RemoteTaskfiles, 1)
dir := "testdata/includes_remote" dir := "testdata/includes_remote"
os.RemoveAll(filepath.Join(dir, ".task", "remote")) os.RemoveAll(filepath.Join(dir, ".task", "remote"))
@@ -1398,8 +1396,6 @@ func TestIncludesEmptyMain(t *testing.T) {
} }
func TestIncludesHttp(t *testing.T) { func TestIncludesHttp(t *testing.T) {
enableExperimentForTest(t, &experiments.RemoteTaskfiles, 1)
dir, err := filepath.Abs("testdata/includes_http") dir, err := filepath.Abs("testdata/includes_http")
require.NoError(t, err) require.NoError(t, err)

View File

@@ -8,8 +8,6 @@ import (
giturls "github.com/chainguard-dev/git-urls" giturls "github.com/chainguard-dev/git-urls"
"github.com/go-task/task/v3/errors"
"github.com/go-task/task/v3/experiments"
"github.com/go-task/task/v3/internal/fsext" "github.com/go-task/task/v3/internal/fsext"
) )
@@ -67,9 +65,6 @@ func NewNode(
default: default:
node, err = NewFileNode(entrypoint, dir, opts...) node, err = NewFileNode(entrypoint, dir, opts...)
} }
if _, isRemote := node.(RemoteNode); isRemote && !experiments.RemoteTaskfiles.Enabled() {
return nil, errors.New("task: Remote taskfiles are not enabled. You can read more about this experiment and how to enable it at https://taskfile.dev/experiments/remote-taskfiles")
}
return node, err return node, err
} }

View File

@@ -370,6 +370,10 @@ export default defineConfig({
text: 'Guide', text: 'Guide',
link: '/docs/guide' link: '/docs/guide'
}, },
{
text: 'Remote Taskfiles',
link: '/docs/remote-taskfiles'
},
{ {
text: 'Reference', text: 'Reference',
collapsed: true, collapsed: true,

View File

@@ -1,505 +1,12 @@
--- ---
title: 'Remote Taskfiles (#1317)'
description: Experimentation for using Taskfiles stored in remote locations description: Experimentation for using Taskfiles stored in remote locations
outline: deep outline: deep
--- ---
# Remote Taskfiles (#1317) # Remote Taskfiles (#1317)
::: warning The Remote Taskfiles experiment has now [been released][changelog] :tada:. To
learn more, you can read the [remote Taskfile docs][remote-taskfile-docs].
All experimental features are subject to breaking changes and/or removal _at any [changelog]: ../changelog.md#v3511---2026-05-16
time_. We strongly recommend that you do not use these features in a production [remote-taskfile-docs]: ../remote-taskfiles.md
environment. They are intended for testing and feedback only.
:::
::: info
To enable this experiment, set the environment variable:
`TASK_X_REMOTE_TASKFILES=1`. Check out
[our guide to enabling experiments](./index.md#enabling-experiments) for more
information.
:::
::: danger
Never run remote Taskfiles from sources that you do not trust.
:::
This experiment allows you to use Taskfiles which are stored in remote
locations. This applies to both the root Taskfile (aka. Entrypoint) and also
when including Taskfiles.
Task uses "nodes" to reference remote Taskfiles. There are a few different types
of node which you can use:
::: code-group
```text [HTTP/HTTPS]
https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml
```
```text [Git over HTTP]
https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
```
```text [Git over SSH]
git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
```
:::
## Node Types
### HTTP/HTTPS
`https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml`
This is the most basic type of remote node and works by downloading the file
from the specified URL. The file must be a valid Taskfile and can be of any
name. If a file is not found at the specified URL, Task will append each of the
supported file names in turn until it finds a valid file. If it still does not
find a valid Taskfile, an error is returned.
### Git over HTTP
`https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main`
This type of node works by downloading the file from a Git repository over
HTTP/HTTPS. The first part of the URL is the base URL of the Git repository.
This is the same URL that you would use to clone the repo over HTTP.
- You can optionally add the path to the Taskfile in the repository by appending
`//<path>` to the URL.
- You can also optionally specify a branch or tag to use by appending
`?ref=<ref>` to the end of the URL. If you omit a reference, the default
branch will be used.
### Git over SSH
`git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main`
This type of node works by downloading the file from a Git repository over SSH.
The first part of the URL is the user and base URL of the Git repository. This
is the same URL that you would use to clone the repo over SSH.
To use Git over SSH, you need to make sure that your SSH agent has your private
SSH keys added so that they can be used during authentication.
- You can optionally add the path to the Taskfile in the repository by appending
`//<path>` to the URL.
- You can also optionally specify a branch or tag to use by appending
`?ref=<ref>` to the end of the URL. If you omit a reference, the default
branch will be used.
Task has an example remote Taskfile in our repository that you can use for
testing and that we will use throughout this document:
```yaml
version: '3'
tasks:
default:
cmds:
- task: hello
hello:
cmds:
- echo "Hello Task!"
```
## Specifying a remote entrypoint
By default, Task will look for one of the supported file names on your local
filesystem. If you want to use a remote file instead, you can pass its URI into
the `--taskfile`/`-t` flag just like you would to specify a different local
file. For example:
::: code-group
```shell [HTTP/HTTPS]
$ task --taskfile https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml
task: [hello] echo "Hello Task!"
Hello Task!
```
```shell [Git over HTTP]
$ task --taskfile https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
task: [hello] echo "Hello Task!"
Hello Task!
```
```shell [Git over SSH]
$ task --taskfile git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
task: [hello] echo "Hello Task!"
Hello Task!
```
:::
## Including remote Taskfiles
Including a remote file works exactly the same way that including a local file
does. You just need to replace the local path with a remote URI. Any tasks in
the remote Taskfile will be available to run from your main Taskfile.
::: code-group
```yaml [HTTP/HTTPS]
version: '3'
includes:
my-remote-namespace: https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml
```
```yaml [Git over HTTP]
version: '3'
includes:
my-remote-namespace: https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
```
```yaml [Git over SSH]
version: '3'
includes:
my-remote-namespace: git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
```
:::
```shell
$ task my-remote-namespace:hello
task: [hello] echo "Hello Task!"
Hello Task!
```
### Authenticating using environment variables
The Taskfile location is processed by the templating system, so you can
reference environment variables in your URL if you need to add authentication.
For example:
```yaml
version: '3'
includes:
my-remote-namespace: https://{{.TOKEN}}@raw.githubusercontent.com/my-org/my-repo/main/Taskfile.yml
```
## Special Variables
The file-path [special variables](../reference/templating.md#file-paths) behave
differently when a Taskfile is loaded from a remote source, because there is no
local file or directory that corresponds 1:1 to the Taskfile:
| Variable | Value when loaded remotely |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `TASKFILE` / `ROOT_TASKFILE` | The original URL, unchanged |
| `TASKFILE_DIR` / `ROOT_DIR` | Empty string — a directory variable cannot point to a URL |
| `TASK_DIR` | Resolved against `USER_WORKING_DIR` (relative `dir:` → joined with `USER_WORKING_DIR`, empty `dir:` → `USER_WORKING_DIR`, absolute `dir:` → kept as-is) |
If a remote Taskfile includes a local Taskfile (or vice-versa), each variable
reflects the source of the Taskfile it refers to.
## Security
### Automatic checksums
Running commands from sources that you do not control is always a potential
security risk. For this reason, we have added some automatic checks when using
remote Taskfiles:
1. When running a task from a remote Taskfile for the first time, Task will
print a warning to the console asking you to check that you are sure that you
trust the source of the Taskfile. If you do not accept the prompt, then Task
will exit with code `104` (not trusted) and nothing will run. If you accept
the prompt, the remote Taskfile will run and further calls to the remote
Taskfile will not prompt you again.
2. Whenever you run a remote Taskfile, Task will create and store a checksum of
the file that you are running. If the checksum changes, then Task will print
another warning to the console to inform you that the contents of the remote
file has changed. If you do not accept the prompt, then Task will exit with
code `104` (not trusted) and nothing will run. If you accept the prompt, the
checksum will be updated and the remote Taskfile will run.
Sometimes you need to run Task in an environment that does not have an
interactive terminal, so you are not able to accept a prompt. In these cases you
are able to tell task to accept these prompts automatically by using the `--yes`
flag or the `--trusted-hosts` flag. The `--trusted-hosts` flag allows you to
specify trusted
hosts for remote Taskfiles, while `--yes` applies to all prompts in Task. You
can also configure trusted hosts in your [taskrc configuration](#trusted-hosts) using
`remote.trusted-hosts`. Before enabling automatic trust, you should:
1. Be sure that you trust the source and contents of the remote Taskfile.
2. Consider using a pinned version of the remote Taskfile (e.g. A link
containing a commit hash) to prevent Task from automatically accepting a
prompt that says a remote Taskfile has changed.
### Manual checksum pinning
Alternatively, if you expect the contents of your remote files to be a constant
value, you can pin the checksum of the included file instead:
```yaml
version: '3'
includes:
included:
taskfile: https://taskfile.dev
checksum: c153e97e0b3a998a7ed2e61064c6ddaddd0de0c525feefd6bba8569827d8efe9
```
This will disable the automatic checksum prompts discussed above. However, if
the checksums do not match, Task will exit immediately with an error. When
setting this up for the first time, you may not know the correct value of the
checksum. There are a couple of ways you can obtain this:
1. Add the include normally without the `checksum` key. The first time you run
the included Taskfile, a `.task/remote` temporary directory is created. Find
the correct set of files for your included Taskfile and open the file that
ends with `.checksum`. You can copy the contents of this file and paste it
into the `checksum` key of your include. This method is safest as it allows
you to inspect the downloaded Taskfile before you pin it.
2. Alternatively, add the include with a temporary random value in the
`checksum` key. When you try to run the Taskfile, you will get an error that
will report the incorrect expected checksum and the actual checksum. You can
copy the actual checksum and replace your temporary random value.
### TLS
Task currently supports both `http` and `https` URLs. However, the `http`
requests will not execute by default unless you run the task with the
`--insecure` flag. This is to protect you from accidentally running a remote
Taskfile that is downloaded via an unencrypted connection. Sources that are not
protected by TLS are vulnerable to man-in-the-middle attacks and should be
avoided unless you know what you are doing.
#### Custom Certificates
If your remote Taskfiles are hosted on a server that uses a custom CA
certificate (e.g., a corporate internal server), you can specify the CA
certificate using the `--cacert` flag:
```shell
task --taskfile https://internal.example.com/Taskfile.yml --cacert /path/to/ca.crt
```
For servers that require client certificate authentication (mTLS), you can
provide a client certificate and key:
```shell
task --taskfile https://secure.example.com/Taskfile.yml \
--cert /path/to/client.crt \
--cert-key /path/to/client.key
```
::: warning
Encrypted private keys are not currently supported. If your key is encrypted,
you must decrypt it first:
```shell
openssl rsa -in encrypted.key -out decrypted.key
```
:::
These options can also be configured in the [configuration file](#configuration).
## Caching & Running Offline
Whenever you run a remote Taskfile, the latest copy will be downloaded from the
internet and cached locally. This cached file will be used for all future
invocations of the Taskfile until the cache expires. Once it expires, Task will
download the latest copy of the file and update the cache. By default, the cache
is set to expire immediately. This means that Task will always fetch the latest
version. However, the cache expiry duration can be modified by setting the
`--expiry` flag.
If for any reason you lose access to the internet or you are running Task in
offline mode (via the `--offline` flag or `TASK_OFFLINE` environment variable),
Task will run the any available cached files _even if they are expired_. This
means that you should never be stuck without the ability to run your tasks as
long as you have downloaded a remote Taskfile at least once.
By default, Task will timeout requests to download remote files after 10 seconds
and look for a cached copy instead. This timeout can be configured by setting
the `--timeout` flag and specifying a duration. For example, `--timeout 5s` will
set the timeout to 5 seconds.
By default, the cache is stored in the Task temp directory (`.task`). You can
override the location of the cache by using the `--remote-cache-dir` flag, the
`remote.cache-dir` option in your [configuration file](#cache-dir), or the
`TASK_REMOTE_DIR` environment variable. This way, you can share the cache
between different projects.
You can force Task to ignore the cache and download the latest version by using
the `--download` flag.
You can use the `--clear-cache` flag to clear all cached remote files.
## Configuration
This experiment adds a new `remote` section to the
[configuration file](../reference/config.md).
- **Type**: `object`
- **Description**: Remote configuration settings for handling remote Taskfiles
```yaml
remote:
insecure: false
offline: false
timeout: "30s"
cache-expiry: "24h"
cache-dir: ~/.task
trusted-hosts:
- github.com
- gitlab.com
cacert: ""
cert: ""
cert-key: ""
```
#### `insecure`
- **Type**: `boolean`
- **Default**: `false`
- **Description**: Allow insecure connections when fetching remote Taskfiles
- **CLI equivalent**: `--insecure`
- **Environment variable**: `TASK_REMOTE_INSECURE`
```yaml
remote:
insecure: true
```
#### `offline`
- **Type**: `boolean`
- **Default**: `false`
- **Description**: Work in offline mode, preventing remote Taskfile fetching
- **CLI equivalent**: `--offline`
- **Environment variable**: `TASK_REMOTE_OFFLINE`
```yaml
remote:
offline: true
```
#### `timeout`
- **Type**: `string`
- **Default**: 10s
- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$`
- **Description**: Timeout duration for remote operations (e.g., '30s', '5m')
- **CLI equivalent**: `--timeout`
- **Environment variable**: `TASK_REMOTE_TIMEOUT`
```yaml
remote:
timeout: "1m"
```
#### `cache-expiry`
- **Type**: `string`
- **Default**: 0s (no cache)
- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$`
- **Description**: Cache expiry duration for remote Taskfiles (e.g., '1h',
'24h')
- **CLI equivalent**: `--expiry`
- **Environment variable**: `TASK_REMOTE_CACHE_EXPIRY`
```yaml
remote:
cache-expiry: "6h"
```
#### `cache-dir`
- **Type**: `string`
- **Default**: `.task`
- **Description**: Directory where remote Taskfiles are cached. Can be an
absolute path (e.g., `/var/cache/task`) or relative to the Taskfile directory.
- **CLI equivalent**: `--remote-cache-dir`
- **Environment variable**: `TASK_REMOTE_CACHE_DIR`
```yaml
remote:
cache-dir: ~/.task
```
#### `trusted-hosts`
- **Type**: `array of strings`
- **Default**: `[]` (empty list)
- **Description**: List of trusted hosts for remote Taskfiles. Hosts in this
list will not prompt for confirmation when downloading Taskfiles
- **CLI equivalent**: `--trusted-hosts`
- **Environment variable**: `TASK_REMOTE_TRUSTED_HOSTS` (comma-separated)
```yaml
remote:
trusted-hosts:
- github.com
- gitlab.com
- raw.githubusercontent.com
- example.com:8080
```
Hosts in the trusted hosts list will automatically be trusted without prompting for
confirmation when they are first downloaded or when their checksums change. The
host matching includes the port if specified in the URL. Use with caution and
only add hosts you fully trust.
You can also specify trusted hosts via the command line:
```shell
# Trust specific host for this execution
task --trusted-hosts github.com -t https://github.com/user/repo.git//Taskfile.yml
# Trust multiple hosts (comma-separated)
task --trusted-hosts github.com,gitlab.com -t https://github.com/user/repo.git//Taskfile.yml
# Trust a host with a specific port
task --trusted-hosts example.com:8080 -t https://example.com:8080/Taskfile.yml
```
#### `cacert`
- **Type**: `string`
- **Default**: `""`
- **Description**: Path to a custom CA certificate file for TLS verification
```yaml
remote:
cacert: "/path/to/ca.crt"
```
#### `cert`
- **Type**: `string`
- **Default**: `""`
- **Description**: Path to a client certificate file for mTLS authentication
```yaml
remote:
cert: "/path/to/client.crt"
```
#### `cert-key`
- **Type**: `string`
- **Default**: `""`
- **Description**: Path to the client certificate private key file
```yaml
remote:
cert-key: "/path/to/client.key"
```

View File

@@ -91,7 +91,7 @@ tasks:
::: :::
### Reading a Taskfile from stdin ### Running a Taskfile from stdin
Taskfile also supports reading from stdin. This is useful if you are generating Taskfile also supports reading from stdin. This is useful if you are generating
Taskfiles dynamically and don't want write them to disk. To tell task to read Taskfiles dynamically and don't want write them to disk. To tell task to read
@@ -104,6 +104,41 @@ task -t - < ./Taskfile.yml
cat ./Taskfile.yml | task -t - cat ./Taskfile.yml | task -t -
``` ```
### Running a remote Taskfile
::: danger
Never run remote Taskfiles from sources that you do not trust.
:::
It is possible to directly run a Taskfile from a remote source via HTTP(S) or
Git by using the `--taskfile`/`-t` flag. This is useful if you want to reuse a
set of tasks in multiple projects. For more information, take a look at our
[remote Taskfiles documentation](./remote-taskfiles.md).
::: code-group
```shell [HTTP/HTTPS]
$ task --taskfile https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml
task: [hello] echo "Hello Task!"
Hello Task!
```
```shell [Git over HTTP]
$ task --taskfile https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
task: [hello] echo "Hello Task!"
Hello Task!
```
```shell [Git over SSH]
$ task --taskfile git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
task: [hello] echo "Hello Task!"
Hello Task!
```
:::
## Environment variables ## Environment variables
### Task ### Task
@@ -248,6 +283,26 @@ the `DockerTasks.yml` file.
Relative paths are resolved relative to the directory containing the including Relative paths are resolved relative to the directory containing the including
Taskfile. Taskfile.
### Remote Taskfiles
::: danger
Never run remote Taskfiles from sources that you do not trust.
:::
It is possible to include a Taskfile from a remote source via HTTP(S) or Git.
This is useful if you want to reuse a set of tasks in multiple projects. For
more information, take a look at our
[remote Taskfiles documentation](./remote-taskfiles.md).
```yaml
version: '3'
includes:
my-remote-namespace: https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml
```
### OS-specific Taskfiles ### OS-specific Taskfiles
You can include OS-specific Taskfiles by using a templating function: You can include OS-specific Taskfiles by using a templating function:
@@ -955,7 +1010,8 @@ You can use `--force` or `-f` if you want to force a task to run even when
up-to-date. up-to-date.
Also, `task --status [tasks]...` will exit with a non-zero Also, `task --status [tasks]...` will exit with a non-zero
[exit code](/docs/reference/cli#exit-codes) if any of the tasks are not up-to-date. [exit code](/docs/reference/cli#exit-codes) if any of the tasks are not
up-to-date.
`status` can be combined with the `status` can be combined with the
[fingerprinting](#by-fingerprinting-locally-generated-files-and-their-sources) [fingerprinting](#by-fingerprinting-locally-generated-files-and-their-sources)
@@ -1039,8 +1095,8 @@ tasks:
The `if` attribute allows you to conditionally skip tasks or commands based on a The `if` attribute allows you to conditionally skip tasks or commands based on a
shell command's exit code. Unlike `preconditions` which fail and stop execution, shell command's exit code. Unlike `preconditions` which fail and stop execution,
`if` simply skips the task or command when the condition is not met and continues `if` simply skips the task or command when the condition is not met and
with the rest of the Taskfile. continues with the rest of the Taskfile.
#### Task-level `if` #### Task-level `if`
@@ -1076,9 +1132,9 @@ tasks:
#### Using templates in `if` conditions #### Using templates in `if` conditions
You can use Go template expressions in `if` conditions. Template expressions like You can use Go template expressions in `if` conditions. Template expressions
<span v-pre>`{{eq .VAR "value"}}`</span> evaluate to `true` or `false`, which are valid shell like <span v-pre>`{{eq .VAR "value"}}`</span> evaluate to `true` or `false`,
commands (`true` exits with 0, `false` exits with 1): which are valid shell commands (`true` exits with 0, `false` exits with 1):
```yaml ```yaml
version: '3' version: '3'
@@ -1086,7 +1142,7 @@ version: '3'
tasks: tasks:
conditional: conditional:
vars: vars:
ENABLE_FEATURE: "true" ENABLE_FEATURE: 'true'
cmds: cmds:
- cmd: echo "Feature is enabled" - cmd: echo "Feature is enabled"
if: '{{eq .ENABLE_FEATURE "true"}}' if: '{{eq .ENABLE_FEATURE "true"}}'
@@ -1096,7 +1152,8 @@ tasks:
#### Using `if` with `for` loops #### Using `if` with `for` loops
When used inside a `for` loop, the `if` condition is evaluated for each iteration: When used inside a `for` loop, the `if` condition is evaluated for each
iteration:
```yaml ```yaml
version: '3' version: '3'
@@ -1119,7 +1176,7 @@ processing c
#### `if` vs `preconditions` #### `if` vs `preconditions`
| Aspect | `if` | `preconditions` | | Aspect | `if` | `preconditions` |
|--------|------|-----------------| | ---------- | -------------------- | --------------- |
| On failure | Skips (continues) | Fails (stops) | | On failure | Skips (continues) | Fails (stops) |
| Message | Only in verbose mode | Always shown | | Message | Only in verbose mode | Always shown |
| Use case | "Run if possible" | "Must be true" | | Use case | "Run if possible" | "Must be true" |
@@ -1352,8 +1409,8 @@ $ task deploy
Deploying 1.0.0 to prod Deploying 1.0.0 to prod
``` ```
If the variable is already set (via CLI, environment, or Taskfile), no prompt If the variable is already set (via CLI, environment, or Taskfile), no prompt is
is shown: shown:
```shell ```shell
$ task deploy ENVIRONMENT=prod VERSION=1.0.0 $ task deploy ENVIRONMENT=prod VERSION=1.0.0
@@ -1653,8 +1710,8 @@ in logs, but is **not a substitute** for proper secret management practices.
- ❌ Secrets in command output (stdout/stderr) - ❌ Secrets in command output (stdout/stderr)
- ❌ Secret values copied into derived (non-secret) variables - ❌ Secret values copied into derived (non-secret) variables
Always use proper secret management tools (HashiCorp Vault, AWS Secrets Always use proper secret management tools (HashiCorp Vault, AWS Secrets Manager,
Manager, etc.) for production environments. etc.) for production environments.
::: :::
@@ -1859,8 +1916,7 @@ tasks:
matrix: matrix:
OS: ['windows', 'linux', 'darwin'] OS: ['windows', 'linux', 'darwin']
ARCH: ['amd64', 'arm64'] ARCH: ['amd64', 'arm64']
cmd: cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
``` ```
This will output: This will output:
@@ -1892,8 +1948,7 @@ tasks:
ref: .OS_VAR ref: .OS_VAR
ARCH: ARCH:
ref: .ARCH_VAR ref: .ARCH_VAR
cmd: cmd: echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
echo "{{.ITEM.OS}}/{{.ITEM.ARCH}}"
``` ```
### Looping over your task's sources or generated files ### Looping over your task's sources or generated files
@@ -1938,8 +1993,8 @@ files that match that glob.
Paths will always be returned as paths relative to the task directory. If you Paths will always be returned as paths relative to the task directory. If you
need to convert this to an absolute path, you can use the built-in `joinPath` need to convert this to an absolute path, you can use the built-in `joinPath`
function. There are some function. There are some
[special variables](/docs/reference/templating#special-variables) that you may find [special variables](/docs/reference/templating#special-variables) that you may
useful for this. find useful for this.
::: code-group ::: code-group
@@ -2216,8 +2271,9 @@ $ task start:foo:3
Starting foo with 3 replicas Starting foo with 3 replicas
``` ```
Using wildcards with aliases Using wildcards with aliases Wildcards also work with aliases. If a task has an
Wildcards also work with aliases. If a task has an alias, you can use the alias name with wildcards to capture arguments. For example: alias, you can use the alias name with wildcards to capture arguments. For
example:
```yaml ```yaml
version: '3' version: '3'
@@ -2226,11 +2282,12 @@ tasks:
start:*: start:*:
aliases: [run:*] aliases: [run:*]
vars: vars:
SERVICE: "{{index .MATCH 0}}" SERVICE: '{{index .MATCH 0}}'
cmds: cmds:
- echo "Running {{.SERVICE}}" - echo "Running {{.SERVICE}}"
``` ```
In this example, you can call the task using the alias run:*:
In this example, you can call the task using the alias run:\*:
```shell ```shell
$ task run:foo $ task run:foo
@@ -2281,8 +2338,8 @@ commands are executed in the reverse order if you schedule multiple of them.
::: :::
A special variable `.EXIT_CODE` is exposed when a command exited with a non-zero A special variable `.EXIT_CODE` is exposed when a command exited with a non-zero
[exit code](/docs/reference/cli#exit-codes). You can check its presence to know if [exit code](/docs/reference/cli#exit-codes). You can check its presence to know
the task completed successfully or not: if the task completed successfully or not:
```yaml ```yaml
version: '3' version: '3'
@@ -2483,8 +2540,8 @@ tasks:
``` ```
Warning prompts are called before executing a task. If a prompt is denied Task Warning prompts are called before executing a task. If a prompt is denied Task
will exit with [exit code](/docs/reference/cli#exit-codes) 205. If approved, Task will exit with [exit code](/docs/reference/cli#exit-codes) 205. If approved,
will continue as normal. Task will continue as normal.
```shell ```shell
task example task example
@@ -2878,8 +2935,8 @@ if called by another task, either directly or as a dependency.
The watcher can misbehave in certain scenarios, in particular for long-running The watcher can misbehave in certain scenarios, in particular for long-running
servers. There is a [known bug](https://github.com/go-task/task/issues/160) servers. There is a [known bug](https://github.com/go-task/task/issues/160)
where child processes of the running might not be killed appropriately. It's where child processes of the running might not be killed appropriately. It's
advised to avoid running commands as `go run` and prefer `go build [...] && advised to avoid running commands as `go run` and prefer
./binary` instead. `go build [...] && ./binary` instead.
If you are having issues, you might want to try tools specifically designed for If you are having issues, you might want to try tools specifically designed for
live-reloading, like [Air](https://github.com/air-verse/air/). Also, be sure to live-reloading, like [Air](https://github.com/air-verse/air/). Also, be sure to

View File

@@ -128,7 +128,8 @@ Disable fuzzy matching for task names. When enabled, Task will not suggest
similar task names when you mistype a task name. similar task names when you mistype a task name.
- **Config equivalent**: [`disable-fuzzy`](./config.md#disable-fuzzy) - **Config equivalent**: [`disable-fuzzy`](./config.md#disable-fuzzy)
- **Environment variable**: [`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy) - **Environment variable**:
[`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy)
```bash ```bash
task buidl --disable-fuzzy task buidl --disable-fuzzy
@@ -180,7 +181,8 @@ task test lint --parallel
Limit the number of concurrent tasks. Zero means unlimited. Limit the number of concurrent tasks. Zero means unlimited.
- **Config equivalent**: [`concurrency`](./config.md#concurrency) - **Config equivalent**: [`concurrency`](./config.md#concurrency)
- **Environment variable**: [`TASK_CONCURRENCY`](./environment.md#task-concurrency) - **Environment variable**:
[`TASK_CONCURRENCY`](./environment.md#task-concurrency)
```bash ```bash
task test --concurrency 4 task test --concurrency 4
@@ -248,7 +250,8 @@ task test --output group
Message template to print before grouped output. Message template to print before grouped output.
- **Environment variable**: [`TASK_OUTPUT_GROUP_BEGIN`](./environment.md#task-output-group-begin) - **Environment variable**:
[`TASK_OUTPUT_GROUP_BEGIN`](./environment.md#task-output-group-begin)
```bash ```bash
task test --output group --output-group-begin "::group::{{.TASK}}" task test --output group --output-group-begin "::group::{{.TASK}}"
@@ -258,7 +261,8 @@ task test --output group --output-group-begin "::group::{{.TASK}}"
Message template to print after grouped output. Message template to print after grouped output.
- **Environment variable**: [`TASK_OUTPUT_GROUP_END`](./environment.md#task-output-group-end) - **Environment variable**:
[`TASK_OUTPUT_GROUP_END`](./environment.md#task-output-group-end)
```bash ```bash
task test --output group --output-group-end "::endgroup::" task test --output group --output-group-end "::endgroup::"
@@ -268,7 +272,8 @@ task test --output group --output-group-end "::endgroup::"
Only show command output on non-zero exit codes. Only show command output on non-zero exit codes.
- **Environment variable**: [`TASK_OUTPUT_GROUP_ERROR_ONLY`](./environment.md#task-output-group-error-only) - **Environment variable**:
[`TASK_OUTPUT_GROUP_ERROR_ONLY`](./environment.md#task-output-group-error-only)
```bash ```bash
task test --output group --output-group-error-only task test --output group --output-group-error-only
@@ -351,7 +356,8 @@ task build --watch --interval 1s
Automatically answer "yes" to all prompts. Automatically answer "yes" to all prompts.
- **Environment variable**: [`TASK_ASSUME_YES`](./environment.md#task-assume-yes) - **Environment variable**:
[`TASK_ASSUME_YES`](./environment.md#task-assume-yes)
```bash ```bash
task deploy --yes task deploy --yes
@@ -366,12 +372,69 @@ Task automatically detects non-TTY environments (like CI pipelines) and skips
prompts. This flag can also be set in `.taskrc.yml` to enable prompts by prompts. This flag can also be set in `.taskrc.yml` to enable prompts by
default. default.
- **Environment variable**: [`TASK_INTERACTIVE`](./environment.md#task-interactive) - **Environment variable**:
[`TASK_INTERACTIVE`](./environment.md#task-interactive)
```bash ```bash
task deploy --interactive task deploy --interactive
``` ```
### Remote
The following flags are used to control the behavior of
[remote Taskfiles](../remote-taskfiles.md).
#### `--insecure`
Allow insecure connections when fetching remote Taskfiles.
#### `--offline`
Work in offline mode, preventing remote Taskfile fetching.
#### `--download`
Forces task to download remote Taskfiles and ignore any cached versions.
#### `--timeout`
Timeout duration for remote operations (e.g., '30s', '5m').
#### `--clear-cache`
Wipe the cache of remote Taskfiles and checksums.
#### `--expiry`
Cache expiry duration for remote Taskfiles (e.g., '1h', '24h').
#### `--remote-cache-dir`
Directory where remote Taskfiles are cached. Can be an absolute path (e.g.,
`/var/cache/task`) or relative to the Taskfile directory.
#### `--trusted-hosts`
List of (comma-separated) trusted hosts for remote Taskfiles. Hosts in this list
will not prompt for confirmation when downloading Taskfiles.
Hosts in the trusted hosts list will automatically be trusted without prompting
for confirmation when they are first downloaded or when their checksums change.
The host matching includes the port if specified in the URL. Use with caution
and only add hosts you fully trust.
#### `--cacert`
Path to a custom CA certificate file for TLS verification.
#### `--cert`
Path to a client certificate file for mTLS authentication.
#### `--cert-key`
Path to the client certificate private key file.
## Exit Codes ## Exit Codes
Task uses specific exit codes to indicate different types of errors: Task uses specific exit codes to indicate different types of errors:

View File

@@ -108,7 +108,8 @@ silent: true
- **Type**: `boolean` - **Type**: `boolean`
- **Default**: `true` - **Default**: `true`
- **Description**: Enable colored output. Colors are automatically enabled in CI environments (`CI=true`). - **Description**: Enable colored output. Colors are automatically enabled in CI
environments (`CI=true`).
- **CLI equivalent**: [`-c, --color`](./cli.md#-c---color) - **CLI equivalent**: [`-c, --color`](./cli.md#-c---color)
- **Environment variable**: [`TASK_COLOR`](./environment.md#task-color) - **Environment variable**: [`TASK_COLOR`](./environment.md#task-color)
@@ -120,9 +121,11 @@ color: false
- **Type**: `boolean` - **Type**: `boolean`
- **Default**: `false` - **Default**: `false`
- **Description**: Disable fuzzy matching for task names. When enabled, Task will not suggest similar task names when you mistype a task name. - **Description**: Disable fuzzy matching for task names. When enabled, Task
will not suggest similar task names when you mistype a task name.
- **CLI equivalent**: [`--disable-fuzzy`](./cli.md#--disable-fuzzy) - **CLI equivalent**: [`--disable-fuzzy`](./cli.md#--disable-fuzzy)
- **Environment variable**: [`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy) - **Environment variable**:
[`TASK_DISABLE_FUZZY`](./environment.md#task-disable-fuzzy)
```yaml ```yaml
disable-fuzzy: true disable-fuzzy: true
@@ -134,7 +137,8 @@ disable-fuzzy: true
- **Minimum**: `1` - **Minimum**: `1`
- **Description**: Number of concurrent tasks to run - **Description**: Number of concurrent tasks to run
- **CLI equivalent**: [`-C, --concurrency`](./cli.md#-c---concurrency-number) - **CLI equivalent**: [`-C, --concurrency`](./cli.md#-c---concurrency-number)
- **Environment variable**: [`TASK_CONCURRENCY`](./environment.md#task-concurrency) - **Environment variable**:
[`TASK_CONCURRENCY`](./environment.md#task-concurrency)
```yaml ```yaml
concurrency: 4 concurrency: 4
@@ -158,8 +162,8 @@ failfast: true
- **Default**: `false` - **Default**: `false`
- **Description**: Prompt for missing required variables instead of failing. - **Description**: Prompt for missing required variables instead of failing.
When enabled, Task will display an interactive prompt for any missing required When enabled, Task will display an interactive prompt for any missing required
variable. Requires a TTY. Task automatically detects non-TTY environments variable. Requires a TTY. Task automatically detects non-TTY environments (CI
(CI pipelines, etc.) and skips prompts. pipelines, etc.) and skips prompts.
- **CLI equivalent**: [`--interactive`](./cli.md#--interactive) - **CLI equivalent**: [`--interactive`](./cli.md#--interactive)
```yaml ```yaml
@@ -178,6 +182,157 @@ interactive: true
temp-dir: .task temp-dir: .task
``` ```
### `remote`
- **Type**: `object`
- **Description**: Remote configuration settings for handling
[remote Taskfiles](../remote-taskfiles.md).
#### `remote.insecure`
- **Type**: `boolean`
- **Default**: `false`
- **Description**: Allow insecure connections when fetching remote Taskfiles
- **CLI equivalent**: `--insecure`
- **Environment variable**:
[`TASK_REMOTE_INSECURE`](./environment.md#task-remote-insecure)
```yaml
remote:
insecure: true
```
#### `remote.offline`
- **Type**: `boolean`
- **Default**: `false`
- **Description**: Work in offline mode, preventing remote Taskfile fetching
- **CLI equivalent**: `--offline`
- **Environment variable**:
[`TASK_REMOTE_OFFLINE`](./environment.md#task-remote-offline)
```yaml
remote:
offline: true
```
#### `remote.timeout`
- **Type**: `string`
- **Default**: 10s
- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$`
- **Description**: Timeout duration for remote operations (e.g., '30s', '5m')
- **CLI equivalent**: `--timeout`
- **Environment variable**:
[`TASK_REMOTE_TIMEOUT`](./environment.md#task-remote-timeout)
```yaml
remote:
timeout: '1m'
```
#### `remote.cache-expiry`
- **Type**: `string`
- **Default**: 0s (no cache)
- **Pattern**: `^[0-9]+(ns|us|µs|ms|s|m|h)$`
- **Description**: Cache expiry duration for remote Taskfiles (e.g., '1h',
'24h')
- **CLI equivalent**: `--expiry`
- **Environment variable**:
[`TASK_REMOTE_CACHE_EXPIRY`](./environment.md#task-remote-cache-expiry)
```yaml
remote:
cache-expiry: '6h'
```
#### `remote.cache-dir`
- **Type**: `string`
- **Default**: `.task`
- **Description**: Directory where remote Taskfiles are cached. Can be an
absolute path (e.g., `/var/cache/task`) or relative to the Taskfile directory.
- **CLI equivalent**: `--remote-cache-dir`
- **Environment variable**:
[`TASK_REMOTE_CACHE_DIR`](./environment.md#task-remote-cache-dir)
```yaml
remote:
cache-dir: ~/.task
```
#### `remote.trusted-hosts`
- **Type**: `array of strings`
- **Default**: `[]` (empty list)
- **Description**: List of trusted hosts for remote Taskfiles. Hosts in this
list will not prompt for confirmation when downloading Taskfiles
- **CLI equivalent**: `--trusted-hosts`
- **Environment variable**:
[`TASK_REMOTE_TRUSTED_HOSTS`](./environment.md#task-remote-trusted-hosts)
(comma-separated)
```yaml
remote:
trusted-hosts:
- github.com
- gitlab.com
- raw.githubusercontent.com
- example.com:8080
```
Hosts in the trusted hosts list will automatically be trusted without prompting
for confirmation when they are first downloaded or when their checksums change.
The host matching includes the port if specified in the URL. Use with caution
and only add hosts you fully trust.
You can also specify trusted hosts via the command line:
```shell
# Trust specific host for this execution
task --trusted-hosts github.com -t https://github.com/user/repo.git//Taskfile.yml
# Trust multiple hosts (comma-separated)
task --trusted-hosts github.com,gitlab.com -t https://github.com/user/repo.git//Taskfile.yml
# Trust a host with a specific port
task --trusted-hosts example.com:8080 -t https://example.com:8080/Taskfile.yml
```
#### `remote.cacert`
- **Type**: `string`
- **Default**: `""`
- **Description**: Path to a custom CA certificate file for TLS verification
```yaml
remote:
cacert: '/path/to/ca.crt'
```
#### `remote.cert`
- **Type**: `string`
- **Default**: `""`
- **Description**: Path to a client certificate file for mTLS authentication
```yaml
remote:
cert: '/path/to/client.crt'
```
#### `remote.cert-key`
- **Type**: `string`
- **Default**: `""`
- **Description**: Path to the client certificate private key file
```yaml
remote:
cert-key: '/path/to/client.key'
```
## Example Configuration ## Example Configuration
Here's a complete example of a `.taskrc.yml` file with all available options: Here's a complete example of a `.taskrc.yml` file with all available options:
@@ -190,8 +345,20 @@ color: true
disable-fuzzy: false disable-fuzzy: false
concurrency: 2 concurrency: 2
temp-dir: .task temp-dir: .task
remote:
insecure: false
offline: false
timeout: '30s'
cache-expiry: '24h'
cache-dir: ~/.task
trusted-hosts:
- github.com
- gitlab.com
cacert: ''
cert: ''
cert-key: ''
# Enable experimental features # Enable experimental features
experiments: experiments:
REMOTE_TASKFILES: 1 GENTLE_FORCE: 1
``` ```

View File

@@ -20,7 +20,8 @@ their configuration file equivalents.
## Variables ## Variables
All [configuration file options](./config.md) can also be set via environment All [configuration file options](./config.md) can also be set via environment
variables. The priority order is: CLI flags > environment variables > config files > defaults. variables. The priority order is: CLI flags > environment variables > config
files > defaults.
### `TASK_VERBOSE` ### `TASK_VERBOSE`
@@ -67,7 +68,8 @@ variables. The priority order is: CLI flags > environment variables > config fil
- **Type**: `boolean` (`true`, `false`, `1`, `0`) - **Type**: `boolean` (`true`, `false`, `1`, `0`)
- **Default**: `false` - **Default**: `false`
- **Description**: Compiles and prints tasks in the order that they would be run, without executing them - **Description**: Compiles and prints tasks in the order that they would be
run, without executing them
### `TASK_ASSUME_YES` ### `TASK_ASSUME_YES`
@@ -92,14 +94,16 @@ variables. The priority order is: CLI flags > environment variables > config fil
- **Type**: `string` - **Type**: `string`
- **Description**: Message template to print before a task's grouped output. - **Description**: Message template to print before a task's grouped output.
Only applies when the output style is `group`. Only applies when the output style is `group`.
- **CLI equivalent**: [`--output-group-begin`](./cli.md#--output-group-begin-template) - **CLI equivalent**:
[`--output-group-begin`](./cli.md#--output-group-begin-template)
### `TASK_OUTPUT_GROUP_END` ### `TASK_OUTPUT_GROUP_END`
- **Type**: `string` - **Type**: `string`
- **Description**: Message template to print after a task's grouped output. - **Description**: Message template to print after a task's grouped output. Only
Only applies when the output style is `group`. applies when the output style is `group`.
- **CLI equivalent**: [`--output-group-end`](./cli.md#--output-group-end-template) - **CLI equivalent**:
[`--output-group-end`](./cli.md#--output-group-end-template)
### `TASK_OUTPUT_GROUP_ERROR_ONLY` ### `TASK_OUTPUT_GROUP_ERROR_ONLY`
@@ -107,7 +111,8 @@ variables. The priority order is: CLI flags > environment variables > config fil
- **Default**: `false` - **Default**: `false`
- **Description**: Swallow output from successful tasks. Only applies when the - **Description**: Swallow output from successful tasks. Only applies when the
output style is `group`. output style is `group`.
- **CLI equivalent**: [`--output-group-error-only`](./cli.md#--output-group-error-only) - **CLI equivalent**:
[`--output-group-error-only`](./cli.md#--output-group-error-only)
### `TASK_TEMP_DIR` ### `TASK_TEMP_DIR`
@@ -118,16 +123,64 @@ Taskfile, not the working directory. Defaults to: `./.task`.
### `TASK_CORE_UTILS` ### `TASK_CORE_UTILS`
This env controls whether the Bash interpreter will use its own This env controls whether the Bash interpreter will use its own core utilities
core utilities implemented in Go, or the ones available in the system. implemented in Go, or the ones available in the system. Valid values are `true`
Valid values are `true` (`1`) or `false` (`0`). By default, this is `true` on (`1`) or `false` (`0`). By default, this is `true` on Windows and `false` on
Windows and `false` on other operating systems. We might consider making this other operating systems. We might consider making this enabled by default on all
enabled by default on all platforms in the future. platforms in the future.
### `FORCE_COLOR` ### `FORCE_COLOR`
Force color output usage. Force color output usage.
## Remote Taskfile Variables
The following variables are used to control the behavior of
[remote Taskfiles](../remote-taskfiles.md).
### `TASK_REMOTE_INSECURE`
Allow insecure connections when fetching remote Taskfiles.
### `TASK_REMOTE_OFFLINE`
Work in offline mode, preventing remote Taskfile fetching.
### `TASK_REMOTE_TIMEOUT`
Timeout duration for remote operations (e.g., '30s', '5m').
### `TASK_REMOTE_CACHE_EXPIRY`
Cache expiry duration for remote Taskfiles (e.g., '1h', '24h').
### `TASK_REMOTE_CACHE_DIR`
Directory where remote Taskfiles are cached. Can be an absolute path (e.g.,
`/var/cache/task`) or relative to the Taskfile directory.
### `TASK_REMOTE_TRUSTED_HOSTS`
List of (comma-separated) trusted hosts for remote Taskfiles. Hosts in this list
will not prompt for confirmation when downloading Taskfiles.
Hosts in the trusted hosts list will automatically be trusted without prompting
for confirmation when they are first downloaded or when their checksums change.
The host matching includes the port if specified in the URL. Use with caution
and only add hosts you fully trust.
### `TASK_REMOTE_CACERT`
Path to a custom CA certificate file for TLS verification.
### `TASK_REMOTE_CERT`
Path to a client certificate file for mTLS authentication.
### `TASK_REMOTE_CERT_KEY`
Path to the client certificate private key file.
### Custom Colors ### Custom Colors
All color variables are [ANSI color codes][ansi]. You can specify multiple codes All color variables are [ANSI color codes][ansi]. You can specify multiple codes

View File

@@ -0,0 +1,338 @@
---
outline: deep
---
# Remote Taskfiles
::: danger
Never run remote Taskfiles from sources that you do not trust.
:::
Task allows you to use Taskfiles which are stored in remote locations. This
applies to both the root Taskfile (aka. Entrypoint) and also when including
Taskfiles.
Task uses "nodes" to reference remote Taskfiles. There are a few different types
of node which you can use:
::: code-group
```text [HTTP/HTTPS]
https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml
```
```text [Git over HTTP]
https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
```
```text [Git over SSH]
git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
```
:::
## Node Types
### HTTP/HTTPS
`https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml`
This is the most basic type of remote node and works by downloading the file
from the specified URL. The file must be a valid Taskfile and can be of any
name. If a file is not found at the specified URL, Task will append each of the
supported file names in turn until it finds a valid file. If it still does not
find a valid Taskfile, an error is returned.
### Git over HTTP
`https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main`
This type of node works by downloading the file from a Git repository over
HTTP/HTTPS. The first part of the URL is the base URL of the Git repository.
This is the same URL that you would use to clone the repo over HTTP.
- You can optionally add the path to the Taskfile in the repository by appending
`//<path>` to the URL.
- You can also optionally specify a branch or tag to use by appending
`?ref=<ref>` to the end of the URL. If you omit a reference, the default
branch will be used.
### Git over SSH
`git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main`
This type of node works by downloading the file from a Git repository over SSH.
The first part of the URL is the user and base URL of the Git repository. This
is the same URL that you would use to clone the repo over SSH.
To use Git over SSH, you need to make sure that your SSH agent has your private
SSH keys added so that they can be used during authentication.
- You can optionally add the path to the Taskfile in the repository by appending
`//<path>` to the URL.
- You can also optionally specify a branch or tag to use by appending
`?ref=<ref>` to the end of the URL. If you omit a reference, the default
branch will be used.
Task has an example remote Taskfile in our repository that you can use for
testing and that we will use throughout this document:
```yaml
version: '3'
tasks:
default:
cmds:
- task: hello
hello:
cmds:
- echo "Hello Task!"
```
## Specifying a remote entrypoint
By default, Task will look for one of the supported file names on your local
filesystem. If you want to use a remote file instead, you can pass its URI into
the `--taskfile`/`-t` flag just like you would to specify a different local
file. For example:
::: code-group
```shell [HTTP/HTTPS]
$ task --taskfile https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml
task: [hello] echo "Hello Task!"
Hello Task!
```
```shell [Git over HTTP]
$ task --taskfile https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
task: [hello] echo "Hello Task!"
Hello Task!
```
```shell [Git over SSH]
$ task --taskfile git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
task: [hello] echo "Hello Task!"
Hello Task!
```
:::
## Including remote Taskfiles
Including a remote file works exactly the same way that including a local file
does. You just need to replace the local path with a remote URI. Any tasks in
the remote Taskfile will be available to run from your main Taskfile.
::: code-group
```yaml [HTTP/HTTPS]
version: '3'
includes:
my-remote-namespace: https://raw.githubusercontent.com/go-task/task/main/website/src/public/Taskfile.yml
```
```yaml [Git over HTTP]
version: '3'
includes:
my-remote-namespace: https://github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
```
```yaml [Git over SSH]
version: '3'
includes:
my-remote-namespace: git@github.com/go-task/task.git//website/src/public/Taskfile.yml?ref=main
```
:::
```shell
$ task my-remote-namespace:hello
task: [hello] echo "Hello Task!"
Hello Task!
```
### Authenticating using environment variables
The Taskfile location is processed by the templating system, so you can
reference environment variables in your URL if you need to add authentication.
For example:
```yaml
version: '3'
includes:
my-remote-namespace: https://{{.TOKEN}}@raw.githubusercontent.com/my-org/my-repo/main/Taskfile.yml
```
## Special Variables
The file-path [special variables](../docs/reference/templating.md#file-paths)
behave differently when a Taskfile is loaded from a remote source, because there
is no local file or directory that corresponds 1:1 to the Taskfile:
| Variable | Value when loaded remotely |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TASKFILE` / `ROOT_TASKFILE` | The original URL, unchanged |
| `TASKFILE_DIR` / `ROOT_DIR` | Empty string — a directory variable cannot point to a URL |
| `TASK_DIR` | Resolved against `USER_WORKING_DIR` (relative `dir:` → joined with `USER_WORKING_DIR`, empty `dir:` → `USER_WORKING_DIR`, absolute `dir:` → kept as-is) |
If a remote Taskfile includes a local Taskfile (or vice-versa), each variable
reflects the source of the Taskfile it refers to.
## Security
### Automatic checksums
Running commands from sources that you do not control is always a potential
security risk. For this reason, we have added some automatic checks when using
remote Taskfiles:
1. When running a task from a remote Taskfile for the first time, Task will
print a warning to the console asking you to check that you are sure that you
trust the source of the Taskfile. If you do not accept the prompt, then Task
will exit with code `104` (not trusted) and nothing will run. If you accept
the prompt, the remote Taskfile will run and further calls to the remote
Taskfile will not prompt you again.
2. Whenever you run a remote Taskfile, Task will create and store a checksum of
the file that you are running. If the checksum changes, then Task will print
another warning to the console to inform you that the contents of the remote
file has changed. If you do not accept the prompt, then Task will exit with
code `104` (not trusted) and nothing will run. If you accept the prompt, the
checksum will be updated and the remote Taskfile will run.
Sometimes you need to run Task in an environment that does not have an
interactive terminal, so you are not able to accept a prompt. In these cases you
are able to tell task to accept these prompts automatically by using the `--yes`
flag or the `--trusted-hosts` flag. The `--trusted-hosts` flag allows you to
specify trusted hosts for remote Taskfiles, while `--yes` applies to all prompts
in Task. You can also configure trusted hosts in your
[taskrc configuration](./reference/config.md#remote-trusted-hosts) using
`remote.trusted-hosts`. Before enabling automatic trust, you should:
1. Be sure that you trust the source and contents of the remote Taskfile.
2. Consider using a pinned version of the remote Taskfile (e.g. A link
containing a commit hash) to prevent Task from automatically accepting a
prompt that says a remote Taskfile has changed.
### Manual checksum pinning
Alternatively, if you expect the contents of your remote files to be a constant
value, you can pin the checksum of the included file instead:
```yaml
version: '3'
includes:
included:
taskfile: https://taskfile.dev
checksum: c153e97e0b3a998a7ed2e61064c6ddaddd0de0c525feefd6bba8569827d8efe9
```
This will disable the automatic checksum prompts discussed above. However, if
the checksums do not match, Task will exit immediately with an error. When
setting this up for the first time, you may not know the correct value of the
checksum. There are a couple of ways you can obtain this:
1. Add the include normally without the `checksum` key. The first time you run
the included Taskfile, a `.task/remote` temporary directory is created. Find
the correct set of files for your included Taskfile and open the file that
ends with `.checksum`. You can copy the contents of this file and paste it
into the `checksum` key of your include. This method is safest as it allows
you to inspect the downloaded Taskfile before you pin it.
2. Alternatively, add the include with a temporary random value in the
`checksum` key. When you try to run the Taskfile, you will get an error that
will report the incorrect expected checksum and the actual checksum. You can
copy the actual checksum and replace your temporary random value.
### TLS
Task currently supports both `http` and `https` URLs. However, the `http`
requests will not execute by default unless you run the task with the
`--insecure` flag. This is to protect you from accidentally running a remote
Taskfile that is downloaded via an unencrypted connection. Sources that are not
protected by TLS are vulnerable to man-in-the-middle attacks and should be
avoided unless you know what you are doing.
#### Custom Certificates
If your remote Taskfiles are hosted on a server that uses a custom CA
certificate (e.g., a corporate internal server), you can specify the CA
certificate using the `--cacert` flag:
```shell
task --taskfile https://internal.example.com/Taskfile.yml --cacert /path/to/ca.crt
```
For servers that require client certificate authentication (mTLS), you can
provide a client certificate and key:
```shell
task --taskfile https://secure.example.com/Taskfile.yml \
--cert /path/to/client.crt \
--cert-key /path/to/client.key
```
::: warning
Encrypted private keys are not currently supported. If your key is encrypted,
you must decrypt it first:
```shell
openssl rsa -in encrypted.key -out decrypted.key
```
:::
These options can also be configured in the
[configuration file](#configuration).
## Caching & Running Offline
Whenever you run a remote Taskfile, the latest copy will be downloaded from the
internet and cached locally. This cached file will be used for all future
invocations of the Taskfile until the cache expires. Once it expires, Task will
download the latest copy of the file and update the cache. By default, the cache
is set to expire immediately. This means that Task will always fetch the latest
version. However, the cache expiry duration can be modified by setting the
`--expiry` flag.
If for any reason you lose access to the internet or you are running Task in
offline mode (via the `--offline` flag or `TASK_REMOTE_OFFLINE` environment
variable), Task will run any available cached files _even if they are expired_.
This means that you should never be stuck without the ability to run your tasks
as long as you have downloaded a remote Taskfile at least once.
By default, Task will timeout requests to download remote files after 10 seconds
and look for a cached copy instead. This timeout can be configured by setting
the `--timeout` flag and specifying a duration. For example, `--timeout 5s` will
set the timeout to 5 seconds.
By default, the cache is stored in the Task temp directory (`.task`). You can
override the location of the cache by using the `--remote-cache-dir` flag, the
`remote.cache-dir` option in your
[configuration file](./reference/config.md#remote-cache-dir), or the
`TASK_REMOTE_CACHE_DIR` environment variable. This way, you can share the cache
between different projects.
You can force Task to ignore the cache and download the latest version by using
the `--download` flag.
You can use the `--clear-cache` flag to clear all cached remote files.
## Configuration
It is possible to configure the default behavior of remote Taskfiles using
configuration. Check out the following references for more information on how to
set up this configuration using flags, environment variables or a configuration
file:
- [CLI flags](./reference/cli.md#remote)
- [Environment Variables](./reference/environment.md#remote-taskfile-variables)
- [Config File](./reference/config.md#remote)

View File

@@ -11,10 +11,6 @@
"type": "number", "type": "number",
"enum": [0, 1] "enum": [0, 1]
}, },
"REMOTE_TASKFILES": {
"type": "number",
"enum": [0, 1]
},
"GENTLE_FORCE": { "GENTLE_FORCE": {
"type": "number", "type": "number",
"enum": [0, 1] "enum": [0, 1]