Compare commits

..

5 Commits

Author SHA1 Message Date
Valentin Maerten
22ff746965 feat(website): improve adopters carousel SEO and accessibility
Promotes the carousel label from <p> to <h2>, links the section to the
heading via aria-labelledby, adds an accessible label per chip, and
turns the opaque logo <img> tags into proper lazy-loaded assets with
explicit dimensions.

Adds a subline naming seven brands (Docker, Microsoft, HashiCorp,
Vercel, Google Cloud, AWS, Anthropic) so the homepage now has
indexable text referencing actual adopters — previously the brand
information only lived inside animated chips.

Emits a schema.org ItemList of Organization entities (JSON-LD) on the
homepage, which none of the comparable OSS sites (Vite, Biome, Astro,
Nx, Turborepo) currently expose — cheap differentiator for rich
search results.
2026-04-19 14:55:17 +02:00
Valentin Maerten
bc755b8391 refactor(website): drop /adopters page and move discovery tool out of repo
Drops the dedicated /adopters page, its Vue component, the navbar entry,
the sidebar hack, and the contributing-guide section. The homepage
carousel already carries the social-proof signal — a separate page
attracted virtually no traffic on comparable OSS sites and added
maintenance surface without a clear payoff.

Also removes the "See all" CTA from the carousel header now that there
is nowhere to send visitors to, and centers the remaining label.

The find-adopters Go tool moves out of the repo (to ../find-adopters/)
— it was always a one-off analysis helper, not code that ships with
Task. The adopters.ts file remains the submission surface for anyone
motivated enough to PR a new entry.
2026-04-19 14:09:21 +02:00
Valentin Maerten
4bee0c6d66 feat(website): expand adopters list after full scan, harden discovery tool
Runs the refreshed find-adopters tool against every public Taskfile on
GitHub (1190 unique repos, 13 min) and uses the findings to swap in four
higher-signal entries: Azure/Azure-Sentinel replaces Microsoft's niche
Fabric provider, flet-dev/flet (16k stars, #1 non-Task hit), Anthropic's
Rust protobuf, and charmbracelet/glamour join the list. Gogs drops out
since it no longer surfaces in the best-match slice GitHub exposes.

Rewrites the discovery strategy: GitHub Code Search caps at 1000 results
per query and its size: qualifier turned out unreliable (non-monotone
total_count, sporadic 404s), so the tool now paginates each of the four
Taskfile variants to the cap and supplements with an org: scan over
~100 curated organizations. That's the practical ceiling without GH
Archive or BigQuery, and it captures every big-brand hit we care about.
Also drops the code-search rate from 24 to 8.5 req/min to match the
real 10 req/min authenticated limit.
2026-04-19 14:01:12 +02:00
Valentin Maerten
cb7b4dc235 feat(website): refresh adopters list and add discovery tool
Reshuffles the adopters list to lead with big brands (Docker, HashiCorp,
Microsoft, Vercel, Google Cloud, AWS) followed by high-profile OSS
(FerretDB, Tyk, Outline, etc.), so the section reads as strong social
proof rather than a niche catalog.

Adds website/scripts/find-adopters, a small Go CLI that sidesteps the
1000-result cap on GitHub Code Search by partitioning queries per star
bucket (and per pushed-year when a bucket overflows), then enriches
every hit via a batched GraphQL call. The result is a ranked TSV/JSON
of adopter candidates, filterable by min stars and owner type, that
can be rerun periodically to keep the list fresh. Exposed via
`task find-adopters` in website/Taskfile.yml.
2026-04-19 13:26:18 +02:00
Valentin Maerten
38e12c9f8f feat(website): add adopters section to highlight notable projects
Introduces a new /adopters page listing notable OSS projects using Task,
along with an infinite-scroll carousel on the homepage linking to it.
The adopter list lives in .vitepress/adopters.ts for easy PR-based
submissions; contributing docs explain the process.
2026-04-19 12:37:35 +02:00
50 changed files with 1296 additions and 2348 deletions

View File

@@ -16,7 +16,7 @@ jobs:
name: Lint
strategy:
matrix:
go-version: [1.25.10, 1.26.x]
go-version: [1.25.x, 1.26.x]
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -28,7 +28,7 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: v2.12.2
version: v2.11.4
lint-jsonschema:
runs-on: ubuntu-latest

View File

@@ -21,7 +21,7 @@ jobs:
with:
go-version: "1.26.x"
cache: true
- uses: goreleaser/goreleaser-action@1a80836c5c9d9e5755a25cb59ec6f45a3b5f41a8 # v7
- uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
with:
version: "~> v2"
args: release --snapshot --clean --config .goreleaser-pr.yml

View File

@@ -23,7 +23,7 @@ jobs:
go-version: 1.26.x
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@1a80836c5c9d9e5755a25cb59ec6f45a3b5f41a8 # v7
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
with:
distribution: goreleaser-pro
version: latest

View File

@@ -23,7 +23,7 @@ jobs:
with:
go-version: 1.26.x
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
@@ -35,20 +35,19 @@ jobs:
uses: go-task/setup-task@3be4020d41929789a01026e0e427a4321ce0ad44 # v2
- name: Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
with:
package_json_file: "website/package.json"
run_install: "true"
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@1a80836c5c9d9e5755a25cb59ec6f45a3b5f41a8 # v7
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
with:
distribution: goreleaser-pro
version: latest
args: release --clean --draft
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
GH_GORELEASER_TOKEN: ${{secrets.GH_GORELEASER_TOKEN}}
GORELEASER_KEY: ${{secrets.GORELEASER_KEY}}
CLOUDSMITH_TOKEN: ${{secrets.CLOUDSMITH_TOKEN}}

View File

@@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
go-version: [1.25.10, 1.26.x]
go-version: [1.25.x, 1.26.x]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{matrix.platform}}
steps:

View File

@@ -2,16 +2,33 @@ version: "2"
formatters:
enable:
- gofmt
- gofumpt
- goimports
- gci
settings:
gofmt:
simplify: true
rewrite-rules:
- pattern: interface{}
replacement: any
gofumpt:
module-path: github.com/go-task/task/v3
goimports:
local-prefixes:
- github.com/go-task
gci:
sections:
- standard
- default
- prefix(github.com/go-task)
- localmodule
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
linters:
enable:
@@ -19,7 +36,6 @@ linters:
- gosec
- mirror
- misspell
- modernize
- noctx
- paralleltest
- thelper
@@ -40,8 +56,13 @@ linters:
- pkg: errors
desc: Use github.com/go-task/task/v3/errors instead
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$

View File

@@ -89,7 +89,7 @@ brews:
repository:
owner: go-task
name: homebrew-tap
token: "{{.Env.GH_GORELEASER_TOKEN}}" # So that it runs as the task-bot user
token: "{{secrets.GH_GORELEASER_TOKEN}}" # So that it runs as the task-bot user
test: system "#{bin}/task", "--help"
install: |-
bin.install "task"
@@ -131,7 +131,7 @@ winget:
owner: go-task
name: winget-pkgs
branch: 'task-{{.Version}}'
token: "{{.Env.GH_GORELEASER_TOKEN}}" # So that it runs as the task-bot user
token: "{{secrets.GH_GORELEASER_TOKEN}}" # So that it runs as the task-bot user
pull_request:
enabled: true
draft: false

View File

@@ -1,20 +1,5 @@
# Changelog
## v3.51.1 - 2026-05-16
- A significant performance boost was achieved for large Taskfiles (monorepos)
by skipping templating altogether when the string is static (#2820 by @romnn).
- Added `absPath` template function that resolves a path to its absolute form,
cleaning `..` and `.` components (#2681, #2788 by @mateenanjum).
- Added `joinEnv` function to join paths based on your oprating system: `;` for
Windows and `:` elsewhere, and `joinUrl` to join URL paths. Also, added two
new special variables: `FILE_PATH_SEPARATOR` which returns `\` on Windows
and `/` elsewhere, and `PATH_LIST_SEPARATOR` which returns `;` on Windows and
`:` elsewhere (#2406, #2408 by @solvingj).
- Update the shell interpreter with a regression fix (#2812, #2832 by
@andreynering).
- Fix potential panic with the shell interpreter (#2810 by @trulede).
## v3.50.0 - 2026-04-13
- Added `enum.ref` support in `requires`: enum constraints can now reference

View File

@@ -15,7 +15,6 @@ import (
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/templater"
"github.com/go-task/task/v3/internal/version"
"github.com/go-task/task/v3/taskfile"
"github.com/go-task/task/v3/taskfile/ast"
)
@@ -202,42 +201,18 @@ func (c *Compiler) getSpecialVars(t *ast.Task, call *Call) (map[string]string, e
// Use filepath.ToSlash for all paths to ensure consistent forward slashes
// across platforms. This prevents issues with backslashes being interpreted
// as escape sequences when paths are used in shell commands on Windows.
var rootTaskfile, rootDir string
if taskfile.IsRemoteEntrypoint(c.Entrypoint) {
rootTaskfile = c.Entrypoint
rootDir = ""
} else {
rootTaskfile = filepath.ToSlash(filepathext.SmartJoin(c.Dir, c.Entrypoint))
rootDir = filepath.ToSlash(c.Dir)
}
allVars := map[string]string{
"TASK_EXE": filepath.ToSlash(os.Args[0]),
"ROOT_TASKFILE": rootTaskfile,
"ROOT_DIR": rootDir,
"USER_WORKING_DIR": filepath.ToSlash(c.UserWorkingDir),
"TASK_VERSION": version.GetVersion(),
"PATH_LIST_SEPARATOR": string(os.PathListSeparator),
"FILE_PATH_SEPARATOR": string(os.PathSeparator),
"TASK_EXE": filepath.ToSlash(os.Args[0]),
"ROOT_TASKFILE": filepath.ToSlash(filepathext.SmartJoin(c.Dir, c.Entrypoint)),
"ROOT_DIR": filepath.ToSlash(c.Dir),
"USER_WORKING_DIR": filepath.ToSlash(c.UserWorkingDir),
"TASK_VERSION": version.GetVersion(),
}
if t != nil {
allVars["TASK"] = t.Task
if taskfile.IsRemoteEntrypoint(t.Location.Taskfile) {
allVars["TASKFILE"] = t.Location.Taskfile
allVars["TASKFILE_DIR"] = ""
switch {
case t.Dir == "":
allVars["TASK_DIR"] = filepath.ToSlash(c.UserWorkingDir)
case filepath.IsAbs(t.Dir):
allVars["TASK_DIR"] = filepath.ToSlash(t.Dir)
default:
allVars["TASK_DIR"] = filepath.ToSlash(filepathext.SmartJoin(c.UserWorkingDir, t.Dir))
}
} else {
allVars["TASK_DIR"] = filepath.ToSlash(filepathext.SmartJoin(c.Dir, t.Dir))
allVars["TASKFILE"] = filepath.ToSlash(t.Location.Taskfile)
allVars["TASKFILE_DIR"] = filepath.ToSlash(filepath.Dir(t.Location.Taskfile))
}
allVars["TASK_DIR"] = filepath.ToSlash(filepathext.SmartJoin(c.Dir, t.Dir))
allVars["TASKFILE"] = filepath.ToSlash(t.Location.Taskfile)
allVars["TASKFILE_DIR"] = filepath.ToSlash(filepath.Dir(t.Location.Taskfile))
} else {
allVars["TASK"] = ""
allVars["TASK_DIR"] = ""

View File

@@ -1,135 +0,0 @@
package task
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/go-task/task/v3/internal/filepathext"
"github.com/go-task/task/v3/taskfile/ast"
)
func TestGetSpecialVarsRemote(t *testing.T) {
t.Parallel()
uwd := t.TempDir()
uwdSlash := filepath.ToSlash(uwd)
localProj := filepath.Join(uwd, "proj")
localProjSlash := filepath.ToSlash(localProj)
localTaskfile := filepath.Join(localProj, "Taskfile.yml")
localTaskfileSlash := filepath.ToSlash(localTaskfile)
absTaskDir := filepath.Join(uwd, "opt", "work")
absTaskDirSlash := filepath.ToSlash(absTaskDir)
tests := []struct {
name string
entrypoint string
compilerDir string
taskDir string
taskfileLocation string
wantRootTaskfile string
wantRootDir string
wantTaskfile string
wantTaskfileDir string
wantTaskDir string
}{
{
name: "local entrypoint, local task",
entrypoint: localTaskfile,
compilerDir: localProj,
taskDir: "",
taskfileLocation: localTaskfile,
wantRootTaskfile: localTaskfileSlash,
wantRootDir: localProjSlash,
wantTaskfile: localTaskfileSlash,
wantTaskfileDir: localProjSlash,
wantTaskDir: localProjSlash,
},
{
name: "https entrypoint, empty task.dir",
entrypoint: "https://taskfile.dev/Taskfile.yml",
compilerDir: "",
taskDir: "",
taskfileLocation: "https://taskfile.dev/Taskfile.yml",
wantRootTaskfile: "https://taskfile.dev/Taskfile.yml",
wantRootDir: "",
wantTaskfile: "https://taskfile.dev/Taskfile.yml",
wantTaskfileDir: "",
wantTaskDir: uwdSlash,
},
{
name: "https entrypoint, relative task.dir",
entrypoint: "https://taskfile.dev/Taskfile.yml",
compilerDir: "",
taskDir: "subdir",
taskfileLocation: "https://taskfile.dev/Taskfile.yml",
wantRootTaskfile: "https://taskfile.dev/Taskfile.yml",
wantRootDir: "",
wantTaskfile: "https://taskfile.dev/Taskfile.yml",
wantTaskfileDir: "",
wantTaskDir: filepath.ToSlash(filepathext.SmartJoin(uwd, "subdir")),
},
{
name: "https entrypoint, absolute task.dir",
entrypoint: "https://taskfile.dev/Taskfile.yml",
compilerDir: "",
taskDir: absTaskDir,
taskfileLocation: "https://taskfile.dev/Taskfile.yml",
wantRootTaskfile: "https://taskfile.dev/Taskfile.yml",
wantRootDir: "",
wantTaskfile: "https://taskfile.dev/Taskfile.yml",
wantTaskfileDir: "",
wantTaskDir: absTaskDirSlash,
},
{
name: "git entrypoint",
entrypoint: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
compilerDir: "",
taskDir: "",
taskfileLocation: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
wantRootTaskfile: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
wantRootDir: "",
wantTaskfile: "https://github.com/foo/bar.git//Taskfile.yml?ref=main",
wantTaskfileDir: "",
wantTaskDir: uwdSlash,
},
{
name: "local root, remote included task",
entrypoint: localTaskfile,
compilerDir: localProj,
taskDir: "",
taskfileLocation: "https://taskfile.dev/included.yml",
wantRootTaskfile: localTaskfileSlash,
wantRootDir: localProjSlash,
wantTaskfile: "https://taskfile.dev/included.yml",
wantTaskfileDir: "",
wantTaskDir: uwdSlash,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
c := &Compiler{
Dir: tt.compilerDir,
Entrypoint: tt.entrypoint,
UserWorkingDir: uwd,
}
task := &ast.Task{
Task: "mytask",
Dir: tt.taskDir,
Location: &ast.Location{Taskfile: tt.taskfileLocation},
}
vars, err := c.getSpecialVars(task, nil)
assert.NoError(t, err)
assert.Equal(t, tt.wantRootTaskfile, vars["ROOT_TASKFILE"], "ROOT_TASKFILE")
assert.Equal(t, tt.wantRootDir, vars["ROOT_DIR"], "ROOT_DIR")
assert.Equal(t, tt.wantTaskfile, vars["TASKFILE"], "TASKFILE")
assert.Equal(t, tt.wantTaskfileDir, vars["TASKFILE_DIR"], "TASKFILE_DIR")
assert.Equal(t, tt.wantTaskDir, vars["TASK_DIR"], "TASK_DIR")
})
}
}

38
go.mod
View File

@@ -1,27 +1,27 @@
module github.com/go-task/task/v3
go 1.25.10
go 1.25.8
require (
charm.land/bubbles/v2 v2.1.0
charm.land/bubbletea/v2 v2.0.6
charm.land/lipgloss/v2 v2.0.3
charm.land/bubbletea/v2 v2.0.2
charm.land/lipgloss/v2 v2.0.2
github.com/Ladicle/tabwriter v1.0.0
github.com/Masterminds/semver/v3 v3.5.0
github.com/alecthomas/chroma/v2 v2.24.1
github.com/Masterminds/semver/v3 v3.4.0
github.com/alecthomas/chroma/v2 v2.23.1
github.com/chainguard-dev/git-urls v1.0.2
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/dominikbraun/graph v0.23.0
github.com/elliotchance/orderedmap/v3 v3.1.0
github.com/fatih/color v1.19.0
github.com/fsnotify/fsnotify v1.10.1
github.com/fsnotify/fsnotify v1.9.0
github.com/go-task/slim-sprig/v3 v3.0.0
github.com/go-task/template v0.2.0
github.com/google/uuid v1.6.0
github.com/hashicorp/go-getter v1.8.6
github.com/joho/godotenv v1.5.1
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/puzpuzpuz/xsync/v4 v4.5.0
github.com/puzpuzpuz/xsync/v4 v4.4.0
github.com/sajari/fuzzy v1.0.0
github.com/sebdah/goldie/v2 v2.8.0
github.com/spf13/pflag v1.0.10
@@ -29,9 +29,9 @@ require (
github.com/zeebo/xxh3 v1.1.0
go.yaml.in/yaml/v3 v3.0.4
golang.org/x/sync v0.20.0
golang.org/x/term v0.43.0
golang.org/x/term v0.42.0
mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997
mvdan.cc/sh/v3 v3.13.2-0.20260510185049-f5c6e2779117
mvdan.cc/sh/v3 v3.13.1
)
require (
@@ -68,16 +68,16 @@ require (
github.com/aws/smithy-go v1.24.2 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/colorprofile v0.4.3 // indirect
github.com/charmbracelet/ultraviolet v0.0.0-20260416155717-489999b90468 // indirect
github.com/charmbracelet/x/ansi v0.11.7 // indirect
github.com/charmbracelet/colorprofile v0.4.2 // indirect
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect
github.com/charmbracelet/x/ansi v0.11.6 // indirect
github.com/charmbracelet/x/term v0.2.2 // indirect
github.com/charmbracelet/x/termios v0.1.1 // indirect
github.com/charmbracelet/x/windows v0.2.2 // indirect
github.com/clipperhouse/displaywidth v0.11.0 // indirect
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect
github.com/dlclark/regexp2 v1.12.0 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect
@@ -94,10 +94,10 @@ require (
github.com/klauspost/compress v1.18.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/lucasb-eyer/go-colorful v1.4.0 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.23 // indirect
github.com/mattn/go-runewidth v0.0.21 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
@@ -120,11 +120,11 @@ require (
go.opentelemetry.io/otel/sdk v1.43.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
go.opentelemetry.io/otel/trace v1.43.0 // indirect
golang.org/x/crypto v0.51.0 // indirect
golang.org/x/net v0.54.0 // indirect
golang.org/x/crypto v0.49.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sys v0.44.0 // indirect
golang.org/x/text v0.37.0 // indirect
golang.org/x/sys v0.43.0 // indirect
golang.org/x/text v0.35.0 // indirect
golang.org/x/time v0.15.0 // indirect
google.golang.org/api v0.271.0 // indirect
google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect

70
go.sum
View File

@@ -2,10 +2,10 @@ cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
charm.land/bubbles/v2 v2.1.0 h1:YSnNh5cPYlYjPxRrzs5VEn3vwhtEn3jVGRBT3M7/I0g=
charm.land/bubbles/v2 v2.1.0/go.mod h1:l97h4hym2hvWBVfmJDtrEHHCtkIKeTEb3TTJ4ZOB3wY=
charm.land/bubbletea/v2 v2.0.6 h1:UHN/91OyuhaOFGSrBXQ/hMZD8IO1Uc4BvHlgHXL2WJo=
charm.land/bubbletea/v2 v2.0.6/go.mod h1:MH/D8ZLlN3op37vQvijKuU29g3rqTp+aQapURFonF9g=
charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU=
charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA=
charm.land/bubbletea/v2 v2.0.2 h1:4CRtRnuZOdFDTWSff9r8QFt/9+z6Emubz3aDMnf/dx0=
charm.land/bubbletea/v2 v2.0.2/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ=
charm.land/lipgloss/v2 v2.0.2 h1:xFolbF8JdpNkM2cEPTfXEcW1p6NRzOWTSamRfYEw8cs=
charm.land/lipgloss/v2 v2.0.2/go.mod h1:KjPle2Qd3YmvP1KL5OMHiHysGcNwq6u83MUjYkFvEkM=
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
cloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM=
@@ -38,14 +38,10 @@ github.com/Ladicle/tabwriter v1.0.0 h1:DZQqPvMumBDwVNElso13afjYLNp0Z7pHqHnu0r4t9
github.com/Ladicle/tabwriter v1.0.0/go.mod h1:c4MdCjxQyTbGuQO/gvqJ+IA/89UEwrsD6hUCW98dyp4=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE=
github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
github.com/alecthomas/chroma/v2 v2.24.1 h1:m5ffpfZbIb++k8AqFEKy9uVgY12xIQtBsQlc6DfZJQM=
github.com/alecthomas/chroma/v2 v2.24.1/go.mod h1:l+ohZ9xRXIbGe7cIW+YZgOGbvuVLjMps/FYN/CwuabI=
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
@@ -96,12 +92,12 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiwNkJrVcKQ=
github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o=
github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=
github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=
github.com/charmbracelet/ultraviolet v0.0.0-20260416155717-489999b90468 h1:Q9fO0y1Zo5KB/5Vu8JZoLGm1N3RzF9bNj3Ao3xoR+Ac=
github.com/charmbracelet/ultraviolet v0.0.0-20260416155717-489999b90468/go.mod h1:bAAz7dh/FTYfC+oiHavL4mX1tOIBZ0ZwYjSi3qE6ivM=
github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI=
github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ=
github.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY=
github.com/charmbracelet/colorprofile v0.4.2/go.mod h1:0rTi81QpwDElInthtrQ6Ni7cG0sDtwAd4C4le060fT8=
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 h1:eyFRbAmexyt43hVfeyBofiGSEmJ7krjLOYt/9CF5NKA=
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8/go.mod h1:SQpCTRNBtzJkwku5ye4S3HEuthAlGy2n9VXZnWkEW98=
github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA=
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
@@ -124,8 +120,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo=
github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@@ -146,8 +140,6 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -200,14 +192,14 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=
github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
@@ -222,8 +214,8 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/puzpuzpuz/xsync/v4 v4.5.0 h1:vOSWu6b57/emh+L/Cw0BeQfvxa/cogFywXHeGUxQxAg=
github.com/puzpuzpuz/xsync/v4 v4.5.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
github.com/puzpuzpuz/xsync/v4 v4.4.0 h1:vlSN6/CkEY0pY8KaB0yqo/pCLZvp9nhdbBdjipT4gWo=
github.com/puzpuzpuz/xsync/v4 v4.4.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
@@ -280,23 +272,27 @@ go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
@@ -323,7 +319,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997 h1:3bbJwtPFh98dJ6lxRdR3eLHTH1CmR3BcU6TriIMiXjE=
mvdan.cc/sh/moreinterp v0.0.0-20260120230322-19def062a997/go.mod h1:Qy/zdaMDxq9sT72Gi43K3gsV+TtTohyDO3f1cyBVwuo=
mvdan.cc/sh/v3 v3.13.2-0.20260503214111-9e7dd28c81cf h1:3mGRe/xSr7fd9m+c5FSab/CSCtADsbdMcyhYGdVR6DY=
mvdan.cc/sh/v3 v3.13.2-0.20260503214111-9e7dd28c81cf/go.mod h1:lXJ8SexMvEVcHCoDvAGLZgFJ9Wsm2sulmoNEXGhYZD0=
mvdan.cc/sh/v3 v3.13.2-0.20260510185049-f5c6e2779117 h1:BfzdGSjcnJBb8sPNLudpzTml8zFUxS1N0N/v9IIS6tQ=
mvdan.cc/sh/v3 v3.13.2-0.20260510185049-f5c6e2779117/go.mod h1:lXJ8SexMvEVcHCoDvAGLZgFJ9Wsm2sulmoNEXGhYZD0=
mvdan.cc/sh/v3 v3.13.1 h1:DP3TfgZhDkT7lerUdnp6PTGKyxxzz6T+cOlY/xEvfWk=
mvdan.cc/sh/v3 v3.13.1/go.mod h1:lXJ8SexMvEVcHCoDvAGLZgFJ9Wsm2sulmoNEXGhYZD0=

View File

@@ -81,7 +81,7 @@ func TraverseStringsFunc[T any](v T, fn func(v string) (string, error)) (T, erro
traverseFunc = func(copy, v reflect.Value) error {
switch v.Kind() {
case reflect.Pointer:
case reflect.Ptr:
// Unwrap the pointer
originalValue := v.Elem()
// If the pointer is nil, do nothing

View File

@@ -127,10 +127,7 @@ func ExpandFields(s string) ([]string, error) {
s = escape(s)
p := syntax.NewParser()
var words []*syntax.Word
for w, err := range p.WordsSeq(strings.NewReader(s)) {
if err != nil {
return nil, err
}
for w := range p.WordsSeq(strings.NewReader(s)) {
words = append(words, w)
}
cfg := &expand.Config{

View File

@@ -285,9 +285,7 @@ func isEnvVar(key string, envVars map[string]bool) bool {
key == "TASKFILE_DIR" ||
key == "USER_WORKING_DIR" ||
key == "ALIAS" ||
key == "MATCH" ||
key == "PATH_LIST_SEPARATOR" ||
key == "FILE_PATH_SEPARATOR" {
key == "MATCH" {
return true
}
return envVars[key]

View File

@@ -3,8 +3,6 @@ package templater
import (
"maps"
"math/rand/v2"
"os"
"path"
"path/filepath"
"runtime"
"strings"
@@ -23,8 +21,8 @@ var templateFuncs template.FuncMap
func init() {
taskFuncs := template.FuncMap{
"OS": goos,
"ARCH": goarch,
"OS": os,
"ARCH": arch,
"numCPU": runtime.NumCPU,
"catLines": catLines,
"splitLines": splitLines,
@@ -35,10 +33,7 @@ func init() {
"splitArgs": splitArgs,
"IsSH": IsSH, // Deprecated
"joinPath": filepath.Join,
"joinEnv": joinEnv,
"joinUrl": joinUrl,
"relPath": filepath.Rel,
"absPath": filepath.Abs,
"merge": merge,
"spew": spew.Sdump,
"fromYaml": fromYaml,
@@ -61,11 +56,11 @@ func init() {
maps.Copy(templateFuncs, taskFuncs)
}
func goos() string {
func os() string {
return runtime.GOOS
}
func goarch() string {
func arch() string {
return runtime.GOARCH
}
@@ -99,14 +94,6 @@ func IsSH() bool {
return true
}
func joinEnv(elem ...string) string {
return strings.Join(elem, string(os.PathListSeparator))
}
func joinUrl(elem ...string) string {
return path.Join(elem...)
}
func merge(base map[string]any, v ...map[string]any) map[string]any {
cap := len(v)
for _, m := range v {

View File

@@ -68,13 +68,6 @@ func ReplaceWithExtra[T any](v T, cache *Cache, extra map[string]any) T {
return v
}
// Optimization: skip if string is not a template
if s, ok := any(v).(string); ok {
if !strings.Contains(s, "{{") {
return v
}
}
// Initialize the cache map if it's not already initialized
if cache.cacheMap == nil {
cache.cacheMap = cache.Vars.ToCacheMap()
@@ -89,10 +82,6 @@ func ReplaceWithExtra[T any](v T, cache *Cache, extra map[string]any) T {
// Traverse the value and parse any template variables
copy, err := deepcopy.TraverseStringsFunc(v, func(v string) (string, error) {
// Optimization: skip if string is not a template
if !strings.Contains(v, "{{") {
return v, nil
}
tpl, err := template.New("").Funcs(templateFuncs).Parse(v)
if err != nil {
return v, err

View File

@@ -1 +1 @@
3.51.1
3.50.0

View File

@@ -2601,27 +2601,6 @@ func TestSplitArgs(t *testing.T) {
assert.Equal(t, "3\n", buff.String())
}
func TestAbsPath(t *testing.T) {
t.Parallel()
var buff bytes.Buffer
e := task.NewExecutor(
task.WithDir("testdata/abs_path"),
task.WithStdout(&buff),
task.WithStderr(&buff),
task.WithSilent(true),
)
require.NoError(t, e.Setup())
err := e.Run(t.Context(), &task.Call{Task: "default"})
require.NoError(t, err)
cwd, err := os.Getwd()
require.NoError(t, err)
expected := filepath.Join(cwd, "bar") + "\n"
assert.Equal(t, expected, buff.String())
}
func TestSingleCmdDep(t *testing.T) {
t.Parallel()

View File

@@ -73,7 +73,7 @@ func NewNode(
return node, err
}
func IsRemoteEntrypoint(entrypoint string) bool {
func isRemoteEntrypoint(entrypoint string) bool {
scheme, _ := getScheme(entrypoint)
switch scheme {
case "git", "http", "https":
@@ -93,8 +93,8 @@ func getScheme(uri string) (string, error) {
return "git", nil
}
if before, _, ok := strings.Cut(uri, "://"); ok {
return before, nil
if i := strings.Index(uri, "://"); i != -1 {
return uri[:i], nil
}
return "", nil

View File

@@ -60,7 +60,7 @@ func (node *FileNode) Read() ([]byte, error) {
func (node *FileNode) ResolveEntrypoint(entrypoint string) (string, error) {
// If the file is remote, we don't need to resolve the path
if IsRemoteEntrypoint(entrypoint) {
if isRemoteEntrypoint(entrypoint) {
return entrypoint, nil
}

View File

@@ -188,7 +188,7 @@ func (node *GitNode) ReadContext(ctx context.Context) ([]byte, error) {
func (node *GitNode) ResolveEntrypoint(entrypoint string) (string, error) {
// If the file is remote, we don't need to resolve the path
if IsRemoteEntrypoint(entrypoint) {
if isRemoteEntrypoint(entrypoint) {
return entrypoint, nil
}

View File

@@ -42,7 +42,7 @@ func (node *StdinNode) Read() ([]byte, error) {
func (node *StdinNode) ResolveEntrypoint(entrypoint string) (string, error) {
// If the file is remote, we don't need to resolve the path
if IsRemoteEntrypoint(entrypoint) {
if isRemoteEntrypoint(entrypoint) {
return entrypoint, nil
}

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"net/url"
"os"
"slices"
"sync"
"time"
@@ -286,7 +285,12 @@ func (r *Reader) isTrusted(uri string) bool {
host := parsedURL.Host
// Check against each trusted pattern (exact match including port if provided)
return slices.Contains(r.trustedHosts, host)
for _, pattern := range r.trustedHosts {
if host == pattern {
return true
}
}
return false
}
func (r *Reader) include(ctx context.Context, node Node) error {

View File

@@ -1,6 +0,0 @@
version: '3'
tasks:
default:
cmds:
- cmd: echo '{{absPath "foo/../bar"}}'

View File

@@ -2,137 +2,79 @@ export interface Adopter {
name: string;
url: string;
img: string;
description: string;
}
export const adopters: Adopter[] = [
// Big brand names (first three double as the "featured" showcase)
// Big brand names
{
name: 'Docker',
url: 'https://github.com/docker/mcp-registry',
img: 'https://github.com/docker.png',
description:
'The industry-standard container platform uses Task in mcp-registry, the official registry for Docker Model Context Protocol servers.'
img: 'https://github.com/docker.png'
},
{
name: 'Vercel',
url: 'https://github.com/vercel/terraform-provider-vercel',
img: 'https://github.com/vercel.png',
description:
'The team behind Next.js and the leading frontend cloud platform uses Task to run and release the official Vercel Terraform provider.'
name: 'Microsoft',
url: 'https://github.com/Azure/Azure-Sentinel',
img: 'https://github.com/microsoft.png'
},
{
name: 'HashiCorp',
url: 'https://github.com/hashicorp/terraform-aws-terraform-enterprise-hvd',
img: 'https://github.com/hashicorp.png',
description:
'HashiCorp ships Task across its Validated Design modules for Terraform, Vault, Consul, Nomad, and Boundary on AWS, Azure, and GCP.'
img: 'https://github.com/hashicorp.png'
},
// Other big brands
{
name: 'Microsoft',
url: 'https://github.com/Azure/Azure-Sentinel',
img: 'https://github.com/microsoft.png',
description:
'Azure Sentinel, Microsofts cloud-native SIEM used by enterprises worldwide, relies on Task to orchestrate its repository automation.'
name: 'Vercel',
url: 'https://github.com/vercel/terraform-provider-vercel',
img: 'https://github.com/vercel.png'
},
{
name: 'Google Cloud',
url: 'https://github.com/GoogleCloudPlatform/deploystack',
img: 'https://github.com/GoogleCloudPlatform.png',
description:
'DeployStack, Google Clouds one-click Terraform deployment tool, automates its workflows with Task.'
img: 'https://github.com/GoogleCloudPlatform.png'
},
{
name: 'AWS',
url: 'https://github.com/aws-samples/appmod-blueprints',
img: 'https://github.com/aws-samples.png',
description:
'The AWS Samples AppMod Blueprints reference platform uses Task to orchestrate its demo environments.'
img: 'https://github.com/aws-samples.png'
},
{
name: 'Anthropic',
url: 'https://github.com/anthropics/buffa',
img: 'https://github.com/anthropics.png',
description:
'Anthropics Rust protobuf implementation, buffa, uses Task for its build and release tooling.'
},
{
name: 'MongoDB',
url: 'https://github.com/mongodb/mongo-go-driver',
img: 'https://github.com/mongodb.png',
description:
'The official Go driver for MongoDB uses Task to orchestrate its build, lint, formatting, and full test suite across every commit.'
},
{
name: 'Redpanda',
url: 'https://github.com/redpanda-data/connect',
img: 'https://github.com/redpanda-data.png',
description:
'Redpanda Connect, the stream processor formerly known as Benthos, uses Task to orchestrate builds, Docker images, test suites, and its GitHub release pipeline.'
img: 'https://github.com/anthropics.png'
},
// Notable open source projects
{
name: 'Flet',
url: 'https://github.com/flet-dev/flet',
img: 'https://github.com/flet-dev.png',
description:
'Build realtime web, mobile and desktop apps in Python, with no frontend experience required.'
img: 'https://github.com/flet-dev.png'
},
{
name: 'GoReleaser',
url: 'https://github.com/goreleaser/goreleaser',
img: 'https://github.com/goreleaser.png',
description:
'Release engineering, simplified. GoReleaser is the de-facto release automation tool for Go projects.'
img: 'https://github.com/goreleaser.png'
},
{
name: 'Arduino CLI',
url: 'https://github.com/arduino/arduino-cli',
img: 'https://github.com/arduino.png',
description:
'The official Arduino command-line tool. Task powers the entire Arduino developer tooling stack across 70+ repositories.'
img: 'https://github.com/arduino.png'
},
{
name: 'FerretDB',
url: 'https://github.com/FerretDB/FerretDB',
img: 'https://github.com/FerretDB.png',
description:
'A truly open-source MongoDB alternative built on PostgreSQL, with Task driving every build and release step.'
img: 'https://github.com/FerretDB.png'
},
{
name: 'Tyk',
url: 'https://github.com/TykTechnologies/tyk',
img: 'https://github.com/TykTechnologies.png',
description:
'Open source API gateway supporting REST, GraphQL, TCP and gRPC, automated end-to-end with Task.'
img: 'https://github.com/TykTechnologies.png'
},
{
name: 'Charmbracelet',
url: 'https://github.com/charmbracelet/glamour',
img: 'https://github.com/charmbracelet.png',
description:
'The team behind Bubble Tea uses Task to build Glamour, the stylesheet-based markdown renderer for CLI apps.'
img: 'https://github.com/charmbracelet.png'
},
{
name: 'Outline',
url: 'https://github.com/OutlineFoundation/outline-server',
img: 'https://github.com/OutlineFoundation.png',
description:
'Outline, the open-source proxy server originally built by Jigsaw (Google), uses Task for its build pipeline.'
},
{
name: 'werf',
url: 'https://github.com/werf/werf',
img: 'https://github.com/werf.png',
description:
'werf, the CNCF-hosted CI/CD tool for shipping software to Kubernetes, uses Task as its build and development entry point.'
},
{
name: 'Gobuster',
url: 'https://github.com/OJ/gobuster',
img: 'https://github.com/OJ.png',
description:
'The ubiquitous directory, DNS and virtual-host brute-forcing tool trusted by pen testers worldwide runs its entire build through Task.'
img: 'https://github.com/OutlineFoundation.png'
}
];

View File

@@ -1,629 +0,0 @@
<script setup lang="ts">
import { adopters } from '../adopters';
const featured = adopters.slice(0, 3);
const rest = adopters.slice(3);
const pad = (n: number) => String(n).padStart(2, '0');
const githubPath = (url: string) =>
url.replace(/^https?:\/\/github\.com\//, '').replace(/\/$/, '');
</script>
<template>
<article class="adopters-page">
<header class="hero">
<p class="kicker">
<span class="slashes">//</span>
Who builds with Task
</p>
<h1 class="title">
Trusted by teams shipping<br />
production software.
</h1>
<p class="lead">
Thousands of open source projects use Task as their build and release
orchestrator, from hyperscaler platforms and enterprise security tools
to CLI utilities downloaded millions of times. Below are a few
organizations whose public repositories ship a
<code>Taskfile.yml</code>. Every entry links to real, production code
you can inspect yourself.
</p>
</header>
<section class="featured" aria-labelledby="featured-heading">
<h2 id="featured-heading" class="section-title">
<span class="slashes">//</span>
Featured adopters
</h2>
<div class="featured-grid">
<a
v-for="item in featured"
:key="item.name"
:href="item.url"
target="_blank"
rel="noopener"
class="featured-card"
:aria-label="`${item.name} on GitHub`"
>
<span class="corner tl" aria-hidden="true"></span>
<span class="corner tr" aria-hidden="true"></span>
<span class="corner bl" aria-hidden="true"></span>
<span class="corner br" aria-hidden="true"></span>
<img
:src="item.img"
:alt="`${item.name} logo`"
class="featured-logo"
loading="lazy"
decoding="async"
width="64"
height="64"
/>
<h3 class="featured-name">{{ item.name }}</h3>
<p class="featured-desc">{{ item.description }}</p>
<span class="featured-cta">
<span class="cta-label">View Taskfile on GitHub</span>
<span class="cta-arrow" aria-hidden="true">&rarr;</span>
</span>
</a>
</div>
</section>
<section class="grid-section" aria-labelledby="grid-heading">
<h2 id="grid-heading" class="section-title">
<span class="slashes">//</span>
More projects using Task
</h2>
<div class="grid">
<a
v-for="(item, i) in rest"
:key="item.name"
:href="item.url"
target="_blank"
rel="noopener"
class="card"
:aria-label="`${item.name} on GitHub`"
>
<div class="card-head">
<img
:src="item.img"
:alt="`${item.name} logo`"
class="card-logo"
loading="lazy"
decoding="async"
width="44"
height="44"
/>
<span class="card-index"
>N&deg; {{ pad(i + featured.length + 1) }}</span
>
</div>
<h3 class="card-name">{{ item.name }}</h3>
<p class="card-desc">{{ item.description }}</p>
<div class="card-foot">
<span class="card-path">{{ githubPath(item.url) }}</span>
<span class="card-arrow" aria-hidden="true">&rarr;</span>
</div>
</a>
</div>
</section>
<section class="faq" aria-labelledby="why-heading">
<h2 id="why-heading" class="section-title">
<span class="slashes">//</span>
Why Task?
</h2>
<dl class="faq-list">
<div class="faq-item">
<dt>Is Task production-ready?</dt>
<dd>
Yes. Task ships as a single static binary, has been in wide
production use since 2018, and powers the release workflows of
projects with millions of downloads including Arduino CLI,
GoReleaser, FerretDB, and Gogs.
</dd>
</div>
<div class="faq-item">
<dt>Who uses Task in enterprise?</dt>
<dd>
Docker, Vercel, HashiCorp, Microsoft (Azure Sentinel), Google Cloud,
AWS, and Anthropic are among the organizations that ship code with a
<code>Taskfile.yml</code>. Task is also embedded end-to-end in
Arduinos developer tooling stack across more than 70 repositories.
</dd>
</div>
<div class="faq-item">
<dt>How is Task different from Make?</dt>
<dd>
Task uses plain YAML instead of Makes tab-sensitive syntax, runs
identically on Linux, macOS, and Windows, and provides built-in
caching based on file fingerprints. It also comes with an
<a href="/docs/integrations"
>ecosystem of editor and CI integrations</a
>
that Make lacks by default.
</dd>
</div>
<div class="faq-item">
<dt>Where can I find real-world Taskfile examples?</dt>
<dd>
Every project above links directly to a public repository containing
a production <code>Taskfile.yml</code>. Browsing those is the
fastest way to see Task used in real codebases at different scales.
</dd>
</div>
</dl>
</section>
<aside class="submit-cta">
<div class="submit-body">
<p class="submit-kicker">
<span class="slashes">//</span>
Using Task in your project?
</p>
<p class="submit-text">
Open a pull request on
<a
href="https://github.com/go-task/task/blob/main/website/.vitepress/adopters.ts"
target="_blank"
rel="noopener"
><code>.vitepress/adopters.ts</code></a
>
to get featured here.
</p>
</div>
</aside>
</article>
</template>
<style scoped>
.adopters-page {
max-width: 1152px;
margin: 0 auto;
padding: 0 24px 6rem;
}
.slashes {
color: var(--vp-c-brand-1);
margin-right: 0.4em;
}
.section-title {
font-family: var(--vp-font-family-mono);
font-size: 0.8rem;
font-weight: 500;
letter-spacing: 0.04em;
color: var(--vp-c-text-2);
text-transform: uppercase;
margin: 0 0 1.5rem;
}
/* ---------- Hero ---------- */
.hero {
padding: 3.5rem 0 4rem;
max-width: 48rem;
}
.kicker {
font-family: var(--vp-font-family-mono);
font-size: 0.8rem;
font-weight: 500;
letter-spacing: 0.04em;
color: var(--vp-c-text-2);
text-transform: uppercase;
margin: 0 0 1.25rem;
}
.title {
font-size: clamp(2.25rem, 5vw, 3.5rem);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.05;
margin: 0 0 1.75rem;
color: var(--vp-c-text-1);
}
.lead {
font-size: 1.1rem;
line-height: 1.65;
color: var(--vp-c-text-2);
margin: 0;
}
.lead code {
font-family: var(--vp-font-family-mono);
font-size: 0.9em;
padding: 0.1rem 0.4rem;
border-radius: 4px;
background: var(--vp-c-bg-alt);
color: var(--vp-c-brand-1);
}
/* ---------- Featured ---------- */
.featured {
margin-bottom: 4rem;
}
.featured-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.25rem;
}
.featured-card {
position: relative;
display: flex;
flex-direction: column;
gap: 1rem;
padding: 2rem 1.75rem;
border: 1px solid var(--vp-c-divider);
border-radius: 16px;
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
text-decoration: none !important;
transition:
border-color 0.3s ease,
transform 0.3s ease,
box-shadow 0.3s ease;
isolation: isolate;
overflow: hidden;
}
.featured-card::before {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(
600px circle at 50% 0%,
color-mix(in srgb, var(--vp-c-brand-1) 14%, transparent),
transparent 50%
);
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
z-index: -1;
}
.featured-card:hover {
border-color: color-mix(
in srgb,
var(--vp-c-brand-1) 50%,
var(--vp-c-divider)
);
transform: translateY(-3px);
box-shadow: 0 18px 48px -28px
color-mix(in srgb, var(--vp-c-brand-1) 50%, transparent);
}
.featured-card:hover::before {
opacity: 1;
}
.featured-logo {
width: 56px;
height: 56px;
border-radius: 12px;
object-fit: cover;
background: #fff;
}
.featured-name {
font-size: 1.4rem;
font-weight: 700;
letter-spacing: -0.02em;
margin: 0;
line-height: 1.2;
}
.featured-desc {
font-size: 0.95rem;
line-height: 1.55;
color: var(--vp-c-text-2);
margin: 0;
flex: 1;
}
.featured-cta {
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-family: var(--vp-font-family-mono);
font-size: 0.78rem;
color: var(--vp-c-text-2);
transition: color 0.3s ease;
margin-top: 0.5rem;
}
.featured-card:hover .featured-cta {
color: var(--vp-c-brand-1);
}
.cta-arrow {
display: inline-block;
transition: transform 0.3s ease;
}
.featured-card:hover .cta-arrow {
transform: translateX(4px);
}
/* Crosshair corner marks (shared with grid cards) */
.corner {
position: absolute;
width: 10px;
height: 10px;
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
}
.corner::before,
.corner::after {
content: '';
position: absolute;
background: var(--vp-c-brand-1);
}
.corner::before {
width: 10px;
height: 1px;
top: 50%;
left: 0;
}
.corner::after {
width: 1px;
height: 10px;
top: 0;
left: 50%;
}
.corner.tl {
top: 8px;
left: 8px;
}
.corner.tr {
top: 8px;
right: 8px;
}
.corner.bl {
bottom: 8px;
left: 8px;
}
.corner.br {
bottom: 8px;
right: 8px;
}
.featured-card:hover .corner {
opacity: 0.8;
}
/* ---------- Grid ---------- */
.grid-section {
margin-bottom: 4rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 1rem;
}
.card {
position: relative;
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1.25rem 1.25rem 1rem;
border: 1px solid var(--vp-c-divider);
border-radius: 12px;
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
text-decoration: none !important;
transition:
border-color 0.25s ease,
transform 0.25s ease,
box-shadow 0.25s ease;
}
.card:hover {
border-color: color-mix(
in srgb,
var(--vp-c-brand-1) 45%,
var(--vp-c-divider)
);
transform: translateY(-2px);
box-shadow: 0 10px 28px -22px
color-mix(in srgb, var(--vp-c-brand-1) 40%, transparent);
}
.card-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
}
.card-logo {
width: 40px;
height: 40px;
border-radius: 8px;
object-fit: cover;
background: #fff;
flex-shrink: 0;
}
.card-index {
font-family: var(--vp-font-family-mono);
font-size: 0.7rem;
letter-spacing: 0.04em;
color: var(--vp-c-text-3);
font-variant-numeric: tabular-nums;
transition: color 0.25s ease;
}
.card:hover .card-index {
color: var(--vp-c-brand-1);
}
.card-name {
font-size: 1.05rem;
font-weight: 600;
letter-spacing: -0.01em;
line-height: 1.25;
margin: 0;
}
.card-desc {
font-size: 0.85rem;
line-height: 1.5;
color: var(--vp-c-text-2);
margin: 0;
flex: 1;
}
.card-foot {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
padding-top: 0.75rem;
border-top: 1px dashed var(--vp-c-divider);
}
.card-path {
font-family: var(--vp-font-family-mono);
font-size: 0.72rem;
color: var(--vp-c-text-3);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
flex: 1;
}
.card-arrow {
font-family: var(--vp-font-family-mono);
font-size: 0.8rem;
color: var(--vp-c-text-2);
transition:
transform 0.25s ease,
color 0.25s ease;
}
.card:hover .card-arrow {
transform: translateX(3px);
color: var(--vp-c-brand-1);
}
/* ---------- FAQ ---------- */
.faq {
margin-bottom: 3.5rem;
max-width: 48rem;
}
.faq-list {
margin: 0;
}
.faq-item {
padding: 1.25rem 0;
border-bottom: 1px solid var(--vp-c-divider);
}
.faq-item:first-of-type {
border-top: 1px solid var(--vp-c-divider);
}
.faq-item dt {
font-size: 1.05rem;
font-weight: 600;
color: var(--vp-c-text-1);
margin: 0 0 0.5rem;
letter-spacing: -0.01em;
}
.faq-item dd {
font-size: 0.95rem;
line-height: 1.65;
color: var(--vp-c-text-2);
margin: 0;
}
.faq-item dd a {
color: var(--vp-c-brand-1);
font-weight: 500;
}
.faq-item dd code {
font-family: var(--vp-font-family-mono);
font-size: 0.88em;
padding: 0.08rem 0.35rem;
border-radius: 4px;
background: var(--vp-c-bg-alt);
color: var(--vp-c-brand-1);
}
/* ---------- Submit CTA ---------- */
.submit-cta {
padding: 1.75rem 2rem;
border: 1px solid var(--vp-c-divider);
border-radius: 14px;
background:
linear-gradient(
135deg,
color-mix(in srgb, var(--vp-c-brand-1) 6%, transparent) 0%,
transparent 60%
),
var(--vp-c-bg-soft);
position: relative;
overflow: hidden;
}
.submit-cta::before {
content: '';
position: absolute;
top: -1px;
left: 2rem;
right: 2rem;
height: 1px;
background: linear-gradient(
90deg,
transparent,
var(--vp-c-brand-1),
transparent
);
opacity: 0.5;
}
.submit-kicker {
font-family: var(--vp-font-family-mono);
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 0.04em;
color: var(--vp-c-text-2);
text-transform: uppercase;
margin: 0 0 0.5rem;
}
.submit-text {
font-size: 0.95rem;
line-height: 1.55;
color: var(--vp-c-text-2);
margin: 0;
}
.submit-text a {
color: var(--vp-c-brand-1);
font-weight: 500;
}
.submit-text code {
font-family: var(--vp-font-family-mono);
font-size: 0.88em;
padding: 0.08rem 0.4rem;
border-radius: 4px;
background: var(--vp-c-bg-alt);
}
</style>

View File

@@ -11,14 +11,10 @@ const loop = [...adopters, ...adopters];
Trusted by open source projects
</h2>
<p class="subline">
Adopted by <strong>Docker</strong>, <strong>Vercel</strong>,
<strong>HashiCorp</strong>, <strong>Microsoft</strong>,
Adopted by <strong>Docker</strong>, <strong>Microsoft</strong>,
<strong>HashiCorp</strong>, <strong>Vercel</strong>,
<strong>Google Cloud</strong>, <strong>AWS</strong>,
<strong>Anthropic</strong> and more.
<a class="see-all" href="/adopters">
See all adopters
<span class="see-all-arrow" aria-hidden="true">&rarr;</span>
</a>
</p>
<div class="viewport">
@@ -86,28 +82,6 @@ const loop = [...adopters, ...adopters];
font-weight: 600;
}
.see-all {
display: inline-block;
margin-left: 0.4em;
color: var(--vp-c-brand-1);
font-weight: 500;
white-space: nowrap;
text-decoration: none !important;
}
.see-all:hover {
text-decoration: underline !important;
}
.see-all-arrow {
display: inline-block;
transition: transform 0.25s ease;
}
.see-all:hover .see-all-arrow {
transform: translateX(3px);
}
.viewport {
overflow: hidden;
-webkit-mask-image: linear-gradient(

View File

@@ -136,84 +136,6 @@ export default defineConfig({
])
}
// On the /adopters page, emit CollectionPage + ItemList (richer than the
// homepage snippet because it targets this specific URL) and FAQPage for
// the question block at the bottom of the page. Kept in sync by hand with
// components/Adopters.vue.
if (pageData.relativePath === 'adopters.md') {
head.push([
'script',
{ type: 'application/ld+json' },
JSON.stringify({
'@context': 'https://schema.org',
'@type': 'CollectionPage',
name: 'Who uses Task',
url: 'https://taskfile.dev/adopters',
description:
'Organizations and open source projects that use Task as their build and release runner.',
mainEntity: {
'@type': 'ItemList',
numberOfItems: adopters.length,
itemListElement: adopters.map((a, i) => ({
'@type': 'ListItem',
position: i + 1,
item: {
'@type': 'Organization',
name: a.name,
url: a.url,
logo: a.img,
description: a.description,
sameAs: [a.url]
}
}))
}
})
])
head.push([
'script',
{ type: 'application/ld+json' },
JSON.stringify({
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: [
{
'@type': 'Question',
name: 'Is Task production-ready?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. Task ships as a single static binary, has been in wide production use since 2018, and powers the release workflows of projects with millions of downloads including Arduino CLI, GoReleaser, FerretDB, and Gogs.'
}
},
{
'@type': 'Question',
name: 'Who uses Task in enterprise?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Docker, Vercel, HashiCorp, Microsoft (Azure Sentinel), Google Cloud, AWS, and Anthropic are among the organizations that ship code with a Taskfile.yml. Task is also embedded end-to-end in Arduinos developer tooling stack across more than 70 repositories.'
}
},
{
'@type': 'Question',
name: 'How is Task different from Make?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Task uses plain YAML instead of Makes tab-sensitive syntax, runs identically on Linux, macOS, and Windows, and provides built-in caching based on file fingerprints. It also comes with an ecosystem of editor and CI integrations that Make lacks by default.'
}
},
{
'@type': 'Question',
name: 'Where can I find real-world Taskfile examples?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Every adopter listed above links directly to a public repository containing a production Taskfile.yml. Browsing those is the fastest way to see Task used in real codebases at different scales.'
}
}
]
})
])
}
return head
},
srcDir: 'src',
@@ -470,10 +392,6 @@ export default defineConfig({
{
text: 'Incident Response Plan',
link: '/docs/security/incident-response-plan'
},
{
text: 'Threat Model',
link: '/docs/security/threat-model'
}
]
},
@@ -488,8 +406,7 @@ export default defineConfig({
],
// Hacky to disable sidebar for these pages
'/donate': [],
'/team': [],
'/adopters': []
'/team': []
},
socialLinks: [

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 16"><path d="M7.998 14.5c2.832 0 5-1.98 5-4.5 0-1.463-.68-2.19-1.879-3.383l-.036-.037c-1.013-1.008-2.3-2.29-2.834-4.434-.322.256-.63.579-.864.953-.432.696-.621 1.58-.046 2.73.473.947.67 2.284-.278 3.232-.61.61-1.545.84-2.403.633a2.788 2.788 0 0 1-1.436-.874A3.21 3.21 0 0 0 3 10c0 2.53 2.164 4.5 4.998 4.5zM9.533.753C9.496.34 9.16.009 8.77.146 7.035.75 4.34 3.187 5.997 6.5c.344.689.285 1.218.003 1.5-.419.419-1.54.487-2.04-.832-.173-.454-.659-.762-1.035-.454C2.036 7.44 1.5 8.702 1.5 10c0 3.512 2.998 6 6.498 6s6.5-2.5 6.5-6c0-2.137-1.128-3.26-2.312-4.438-1.19-1.184-2.436-2.425-2.653-4.81z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
<path d="M7.998 14.5c2.832 0 5-1.98 5-4.5 0-1.463-.68-2.19-1.879-3.383l-.036-.037c-1.013-1.008-2.3-2.29-2.834-4.434-.322.256-.63.579-.864.953-.432.696-.621 1.58-.046 2.73.473.947.67 2.284-.278 3.232-.61.61-1.545.84-2.403.633a2.788 2.788 0 0 1-1.436-.874A3.21 3.21 0 0 0 3 10c0 2.53 2.164 4.5 4.998 4.5zM9.533.753C9.496.34 9.16.009 8.77.146 7.035.75 4.34 3.187 5.997 6.5c.344.689.285 1.218.003 1.5-.419.419-1.54.487-2.04-.832-.173-.454-.659-.762-1.035-.454C2.036 7.44 1.5 8.702 1.5 10c0 3.512 2.998 6 6.498 6s6.5-2.5 6.5-6c0-2.137-1.128-3.26-2.312-4.438-1.19-1.184-2.436-2.425-2.653-4.81z"/>
</svg>

Before

Width:  |  Height:  |  Size: 676 B

After

Width:  |  Height:  |  Size: 681 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 16"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 345 B

After

Width:  |  Height:  |  Size: 350 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 16"><path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
<path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 796 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 16"><path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor">
<path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 405 B

View File

@@ -5,7 +5,6 @@ import HomePage from '../components/HomePage.vue';
import AuthorCard from '../components/AuthorCard.vue';
import BlogPost from '../components/BlogPost.vue';
import Version from '../components/Version.vue';
import Adopters from '../components/Adopters.vue';
import { enhanceAppWithTabs } from 'vitepress-plugin-tabs/client';
import { h } from 'vue';
import 'virtual:group-icons.css';
@@ -22,7 +21,6 @@ export default {
app.component('AuthorCard', AuthorCard);
app.component('BlogPost', BlogPost);
app.component('Version', Version);
app.component('Adopters', Adopters);
app.component('CopyOrDownloadAsMarkdownButtons', CopyOrDownloadAsMarkdownButtons);
enhanceAppWithTabs(app);
}

View File

@@ -15,13 +15,13 @@
"devDependencies": {
"@types/markdown-it": "^14.1.2",
"@types/node": "^24.1.0",
"netlify-cli": "^26.0.0",
"netlify-cli": "^24.0.0",
"prettier": "^3.6.2",
"vitepress": "^1.6.3",
"vitepress-plugin-group-icons": "^1.6.1",
"vitepress-plugin-tabs": "^0.9.0",
"vitepress-plugin-tabs": "^0.8.0",
"vitepress-plugin-llms": "^1.9.1",
"vue": "^3.5.18"
},
"packageManager": "pnpm@11.1.2+sha512.415a1cc25974731e75455c1468371be74c5aa5fb7621b50d4056d222451609f11412f23fd602e6169f1e060466641f798597e1be961a10688836a67b16569499"
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
}

1982
website/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +0,0 @@
allowBuilds:
'@parcel/watcher': true
esbuild: true
netlify-cli: true
sharp: true
unix-dgram: true

View File

@@ -1,11 +0,0 @@
---
title: Who uses Task
description:
Organizations and open source projects that use Task as their build and
release runner, including Docker, Microsoft, HashiCorp, Vercel, Google Cloud,
AWS, Anthropic, Arduino, GoReleaser, and more.
layout: page
sidebar: false
---
<Adopters />

View File

@@ -8,21 +8,6 @@ editLink: false
::: v-pre
## v3.51.1 - 2026-05-16
- A significant performance boost was achieved for large Taskfiles (monorepos)
by skipping templating altogether when the string is static (#2820 by @romnn).
- Added `absPath` template function that resolves a path to its absolute form,
cleaning `..` and `.` components (#2681, #2788 by @mateenanjum).
- Added `joinEnv` function to join paths based on your oprating system: `;` for
Windows and `:` elsewhere, and `joinUrl` to join URL paths. Also, added two
new special variables: `FILE_PATH_SEPARATOR` which returns `\` on Windows
and `/` elsewhere, and `PATH_LIST_SEPARATOR` which returns `;` on Windows and
`:` elsewhere (#2406, #2408 by @solvingj).
- Update the shell interpreter with a regression fix (#2812, #2832 by
@andreynering).
- Fix potential panic with the shell interpreter (#2810 by @trulede).
## v3.50.0 - 2026-04-13
- Added `enum.ref` support in `requires`: enum constraints can now reference

View File

@@ -190,21 +190,6 @@ 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

View File

@@ -274,12 +274,6 @@ includes:
internal:
taskfile: ./internal.yml
internal: true
[...]
tasks:
example:
desc: using an internal task
cmds:
- task: internal:default
```
### `aliases`

View File

@@ -249,32 +249,6 @@ tasks:
- echo "Working {{.USER_WORKING_DIR}}"
```
#### `FILE_PATH_SEPARATOR`
- **Type**: `string`
- **Description**: OS-specific path separator: Windows = `\`, others = `/`
::: info
> See `joinPath` in [Path Functions](#path-functions) for joining filesystem paths for use with
> file system operations.
:::
### Environment Variables
#### `PATH_LIST_SEPARATOR`
- **Type**: `string`
- **Description**: OS-specific path separator for environment variables: Windows = `;`, others = `:`
::: info
> See `joinEnv` in [Environment Variable Functions](#environment-variable-functions) for joining
> paths for use in environment variables.
:::
### Status
#### `CHECKSUM`
@@ -623,9 +597,9 @@ tasks:
tasks:
platform:
cmds:
- echo "OS {{OS}}" # linux, darwin, windows, etc.
- echo "Architecture {{ARCH}}" # amd64, arm64, etc.
- echo "CPU cores {{numCPU}}" # Number of CPU cores
- echo "OS {{OS}}" # linux, darwin, windows, etc.
- echo "Architecture {{ARCH}}" # amd64, arm64, etc.
- echo "CPU cores {{numCPU}}" # Number of CPU cores
- echo "Building for {{OS}}/{{ARCH}}"
```
@@ -639,52 +613,10 @@ tasks:
OUTPUT_DIR: 'dist'
BINARY_NAME: 'myapp'
cmds:
- echo "{{.WIN_PATH | toSlash}}" # Convert to forward slashes
- echo "{{.WIN_PATH | fromSlash}}" # Convert to OS-specific slashes
- echo "{{joinPath .OUTPUT_DIR .BINARY_NAME}}" # Join path elements
- echo "Relative {{relPath .ROOT_DIR .TASKFILE_DIR}}" # Get relative path
- echo '{{absPath "../sibling"}}' # Resolve to an absolute path
```
#### Environment Variable Functions
```yaml
tasks:
paths:
vars:
WIN_PATH1: 'C:\Users\Person\bin'
WIN_PATH2: 'C:\Shared\bin'
cmds:
# Join paths for Windows ENV vars:
# C:\Users\Person\bin;C:\Shared\bin
- echo "{{joinEnv .WIN_PATH1 .WIN_PATH2}}"
```
```yaml
tasks:
paths:
vars:
POSIX_PATH1: '/users/person/.local/bin'
POSIX_PATH2: '/usr/bin'
cmds:
# Join paths for POSIX ENV vars:
# /users/person/.local/bin:/usr/bin
- echo "{{joinEnv .POSIX_PATH1 .POSIX_PATH2}}"
```
#### URLs
```yaml
tasks:
paths:
vars:
SERVER: 'http://localhost'
PATH1: 'path1'
PATH2: 'path2'
cmds:
# Join paths for URL:
# http://localhost/path1/path2
- echo "{{joinUrl .SERVER .PATH1 .PATH2}}"
- echo "{{.WIN_PATH | toSlash}}" # Convert to forward slashes
- echo "{{.WIN_PATH | fromSlash}}" # Convert to OS-specific slashes
- echo "{{joinPath .OUTPUT_DIR .BINARY_NAME}}" # Join path elements
- echo "Relative {{relPath .ROOT_DIR .TASKFILE_DIR}}" # Get relative path
```
### Data Structure Functions

View File

@@ -15,8 +15,7 @@ A member of the team will investigate as soon as possible and we will keep you
updated throughout the process.
You can read more about how we handle security-related issues in our [Incident
Response Plan][irp] and [Threat Model][tm].
Response Plan][irp].
[pvr]: https://github.com/go-task/task/security/advisories/new
[irp]: ./incident-response-plan
[tm]: ./threat-model

View File

@@ -1,174 +0,0 @@
---
title: Threat Model
outline: deep
---
# Threat Model
This document outlines the security threats, assets, and mitigations for the
Task project. It serves as a high-level, public guide and is published as part
of our commitment to transparency.
## Asset Inventory
### Critical Assets
- **Source Code:** The Task CLI, build scripts, and configuration files
(e.g., `Taskfile.yml`, `.goreleaser.yml`).
- **Build Artifacts:** Compiled binaries, packages, and containers distributed
to users.
- **Secrets:** API tokens, signing keys, and repository credentials used in
CI/CD and release pipelines.
- **Release Metadata:** Version numbers, changelogs, and checksums.
- **CI/CD Pipelines & Runners:** GitHub Actions workflows that build, test, and
release the project.
- **Third-party Dependencies:** Go modules and tools used to build and
distribute Task.
- **Website & Documentation:** The taskfile.dev site and installation scripts.
### Asset Locations
- Local developer machines
- GitHub Actions runners
- GitHub Releases
- Public package registries (npm, Homebrew, Winget, Cloudsmith)
- Source control platforms (GitHub)
- Netlify (website hosting)
## Threat Model
### Actors
- **Maintainers & Contributors:** Trusted users with varying levels of
repository access.
- **External Attackers:** Untrusted users seeking to compromise builds,
releases, or user systems.
- **Supply Chain Threats:** Malicious dependencies or compromised third-party
services.
- **CI/CD Systems:** Automated agents that may be exploited if misconfigured.
### Entry Points
- Source code contributions (pull requests, issues)
- Configuration files and build scripts
- CI/CD integration and environment variables
- Third-party dependencies
- Release pipelines and artifact repositories
- Remote Taskfile fetching (HTTP, Git)
- Installation scripts
### Trust Boundaries
- Between the project repository and the CI/CD environment
- Between Task and remote Taskfiles fetched over the network
- Between artifact generation and distribution channels
- Between the Task binary and user-defined shell commands
### Threats
#### Supply Chain Attacks
- Compromised Go dependencies or build tools
- Unauthorized changes to source code or configuration
- Exploitation of third-party CI/CD or package registry services
- Compromised installation scripts or distribution channels
#### Secrets Leakage
- Exposure of tokens, credentials, or signing keys in logs, error messages,
or artifacts
- Hardcoded secrets in code or configuration
- Improper secret management in CI/CD environments
#### Code Execution / Injection
- Malicious code execution via compromised pull requests or dependencies
- Remote code execution vulnerabilities in Task or its dependencies
- **Note:** Task intentionally executes user-defined shell commands as part of
its core functionality. Users are responsible for the commands they define in
their Taskfiles.
#### Unauthorized Access
- Unauthorized users triggering releases or accessing sensitive artifacts
- Insecure permissions on runners, repositories, or artifact stores
- Compromised maintainer accounts
#### Data Integrity & Tampering
- Tampering with build artifacts, changelogs, or metadata
- Compromise of signing keys, leading to malicious releases
- Man-in-the-middle attacks against remote Taskfile fetching
#### Denial of Service
- Abuse of CI/CD resources, bandwidth, or artifact storage
- Overloading automated processes or API endpoints
- Malicious Taskfiles designed to exhaust system resources
## Mitigations
### Supply Chain Security
- Pin dependencies and use trusted sources
- Mandatory code review and CI checks on all incoming pull requests
- Signed commits and release tags
- Enable immutable releases where supported
- Run `govulncheck` on every commit and tag
- Pin GitHub Actions to specific commit SHAs
### Secrets Management
- Secure storage using GitHub Secrets
- Never log or expose secrets in build or release outputs
- Regularly rotate secrets and monitor for suspicious activity
- Use least-privilege tokens scoped to specific repositories
### Secure Code Execution
- Validate and sanitize configuration files and user inputs
- Audit dependencies for vulnerabilities
- HTTP is rejected for remote Taskfiles by default (requires `--insecure` flag)
- TLS certificate verification for remote Git repositories
### Access Control
- Enforce least privilege for CI/CD runners, repositories, and artifact stores
- Require multi-factor authentication for maintainers
- Restrict release triggers to tagged releases only
- Lower permissions of less active maintainers
### Artifact Integrity
- Generate checksums for all release artifacts
- Distribute artifacts via trusted, access-controlled repositories
- Verify signatures and checksums in installation scripts where possible
### Availability Protection
- Implement rate limiting and resource quotas on CI/CD jobs
- Monitor for abnormal activity and automate alerts
- Set timeouts on network operations (e.g., remote Taskfile fetching)
## Residual Risks
- Zero-day vulnerabilities in dependencies, CI/CD systems, or Task itself
- Social engineering attacks targeting maintainers
- Unnoticed supply chain compromises
- Human error in configuration or secret management
- Users fetching malicious remote Taskfiles from untrusted sources
## Security Best Practices
- Regularly update dependencies and build tools
- Monitor security advisories and patch vulnerabilities promptly
- Educate contributors on secure coding and secrets hygiene
- Document security policies and incident response procedures
## References
- [Task Documentation](https://taskfile.dev/)
- [Incident Response Plan](./incident-response-plan)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [Supply Chain Security](https://slsa.dev/)
- [GitHub Security Best Practices](https://docs.github.com/en/code-security)

View File

@@ -1 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2507" height="687" fill="none" viewBox="0 0 2507 687"><path fill="#2A6FE1" fill-rule="evenodd" d="M499.999 325.98V360.535L361.332 498.757H326.665L187.999 360.535V325.98L326.665 187.757H361.332L499.999 325.98ZM343.997 436.159C395.468 436.159 437.193 394.568 437.193 343.263C437.193 291.957 395.468 250.366 343.997 250.366C292.527 250.366 250.802 291.957 250.802 343.263C250.802 394.568 292.527 436.159 343.997 436.159Z" clip-rule="evenodd"/><path fill="#092F45" fill-rule="evenodd" d="M1440.66 186.26V433.188L1437.03 436.819H1411.61L1407.98 433.188L1404.35 418.663H1400.72C1389.82 432.461 1372.76 440.45 1353.51 440.45C1302.67 440.45 1273.62 400.506 1273.62 346.037C1273.62 291.567 1302.67 251.623 1353.51 251.623C1371.67 251.623 1389.46 258.886 1400.72 273.411H1404.35V186.26L1407.98 182.628H1437.03L1440.66 186.26ZM1357.14 407.769C1386.19 407.769 1404.35 389.612 1404.35 346.037C1404.35 302.461 1386.19 284.305 1357.14 284.305C1328.09 284.305 1309.93 305.729 1309.93 346.037C1309.93 386.344 1328.09 407.769 1357.14 407.769ZM884.959 346.037C884.959 404.137 917.641 440.45 972.11 440.45C1026.58 440.45 1059.26 404.137 1059.26 346.037C1059.26 287.936 1026.58 251.623 972.11 251.623C917.641 251.623 884.959 287.936 884.959 346.037ZM921.272 346.037C921.272 306.092 939.429 284.305 972.11 284.305C1004.79 284.305 1022.95 306.092 1022.95 346.037C1022.95 385.981 1004.79 407.769 972.11 407.769C939.429 407.769 921.272 385.981 921.272 346.037ZM1240.84 258.886L1237.21 255.254H1208.16L1204.53 258.886V346.037C1204.53 389.612 1186.01 407.769 1160.95 407.769C1131.9 407.769 1124.64 385.981 1124.64 364.193V258.886L1121.01 255.254H1091.96L1088.33 258.886V364.193C1088.33 403.774 1106.48 440.45 1157.32 440.45C1174.75 440.45 1191.45 431.735 1200.9 418.663H1204.53L1208.16 433.188L1211.79 436.819H1237.21L1240.84 433.188V258.886ZM1618.52 385.981C1618.52 353.299 1600.37 338.774 1564.05 331.511C1527.74 324.249 1513.22 320.618 1513.22 302.461C1513.22 287.936 1527.74 284.305 1545.9 284.305C1571.32 284.305 1578.58 295.199 1578.58 306.092L1582.21 309.724H1611.26L1614.89 306.092C1614.89 269.779 1585.84 251.623 1545.9 251.623C1495.06 251.623 1476.9 277.042 1476.9 302.461C1476.9 335.143 1498.69 349.668 1535 356.931C1571.32 364.193 1582.21 367.824 1582.21 385.981C1582.21 400.506 1571.32 407.769 1545.9 407.769C1520.48 407.769 1509.58 396.875 1509.58 378.718L1505.95 375.087H1476.9L1473.27 378.718C1473.27 418.663 1498.69 440.45 1545.9 440.45C1596.74 440.45 1618.52 415.031 1618.52 385.981ZM1843.65 251.623C1894.49 251.623 1905.38 284.305 1905.38 324.249V433.188L1901.75 436.819H1872.7L1869.07 433.188V324.249C1869.07 302.461 1865.44 284.305 1836.39 284.305C1810.97 284.305 1796.44 302.461 1796.44 331.511V433.188L1792.81 436.819H1763.76L1760.13 433.188V324.249C1760.13 302.461 1756.5 284.305 1727.45 284.305C1709.29 284.305 1687.5 295.199 1687.5 331.511V433.188L1683.87 436.819H1654.82L1651.19 433.188V258.886L1654.82 255.254H1680.24L1683.87 258.886L1687.5 273.411H1691.13C1698.4 262.517 1712.92 251.623 1738.34 251.623C1767.39 251.623 1778.29 266.148 1785.55 277.042H1789.18C1800.07 262.517 1818.23 251.623 1843.65 251.623ZM1981.48 222.573V193.522L1977.85 189.891H1948.8L1945.17 193.522V222.573L1948.8 226.204H1977.85L1981.48 222.573ZM1981.48 258.886L1977.85 255.254H1948.8L1945.17 258.886V433.188L1948.8 436.819H1977.85L1981.48 433.188V258.886ZM2126.63 407.769V433.188L2123 436.819H2093.95C2068.53 436.819 2043.11 422.294 2043.11 389.612V291.567L2039.48 287.936H2014.06L2010.43 284.305V258.886L2014.06 255.254H2039.48L2043.11 251.623V218.941L2046.75 215.31H2075.8L2079.43 218.941V251.623L2083.06 255.254H2123L2126.63 258.886V284.305L2123 287.936H2083.06L2079.43 291.567V389.612C2079.43 400.506 2086.69 404.137 2093.95 404.137H2123L2126.63 407.769ZM2319.05 433.188V327.88C2319.05 288.299 2304.53 251.623 2250.06 251.623C2230.81 251.623 2213.38 259.612 2202.85 273.411H2199.22V186.26L2195.59 182.628H2166.54L2162.91 186.26V433.188L2166.54 436.819H2195.59L2199.22 433.188V342.405C2199.22 298.83 2217.37 284.305 2246.42 284.305C2275.48 284.305 2282.74 306.092 2282.74 327.88V433.188L2286.37 436.819H2315.42L2319.05 433.188ZM631.176 345.959C631.176 305.983 649.347 284.178 682.055 284.178C711.129 284.178 722.031 298.715 725.665 313.252L729.3 316.886H758.373L762.007 313.252C758.373 280.544 732.934 251.47 682.055 251.47C627.542 251.47 594.834 287.812 594.834 345.959C594.834 404.107 627.542 440.449 682.055 440.449C732.934 440.449 758.373 411.375 762.007 378.667L758.373 375.033H729.3L725.665 378.667C722.031 393.204 711.129 407.741 682.055 407.741C649.347 407.741 631.176 385.936 631.176 345.959ZM868.926 408.456V433.875L865.294 437.507H846.064C820.645 437.507 795.226 422.982 795.226 390.3L795.224 186.26L798.856 182.628H827.906L831.537 186.26L831.539 390.3C831.539 401.194 838.802 404.825 846.064 404.825H865.294L868.926 408.456Z" clip-rule="evenodd"/></svg>
<svg width="2507" height="687" viewBox="0 0 2507 687" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M499.999 325.98V360.535L361.332 498.757H326.665L187.999 360.535V325.98L326.665 187.757H361.332L499.999 325.98ZM343.997 436.159C395.468 436.159 437.193 394.568 437.193 343.263C437.193 291.957 395.468 250.366 343.997 250.366C292.527 250.366 250.802 291.957 250.802 343.263C250.802 394.568 292.527 436.159 343.997 436.159Z" fill="#2A6FE1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1440.66 186.26V433.188L1437.03 436.819H1411.61L1407.98 433.188L1404.35 418.663H1400.72C1389.82 432.461 1372.76 440.45 1353.51 440.45C1302.67 440.45 1273.62 400.506 1273.62 346.037C1273.62 291.567 1302.67 251.623 1353.51 251.623C1371.67 251.623 1389.46 258.886 1400.72 273.411H1404.35V186.26L1407.98 182.628H1437.03L1440.66 186.26ZM1357.14 407.769C1386.19 407.769 1404.35 389.612 1404.35 346.037C1404.35 302.461 1386.19 284.305 1357.14 284.305C1328.09 284.305 1309.93 305.729 1309.93 346.037C1309.93 386.344 1328.09 407.769 1357.14 407.769ZM884.959 346.037C884.959 404.137 917.641 440.45 972.11 440.45C1026.58 440.45 1059.26 404.137 1059.26 346.037C1059.26 287.936 1026.58 251.623 972.11 251.623C917.641 251.623 884.959 287.936 884.959 346.037ZM921.272 346.037C921.272 306.092 939.429 284.305 972.11 284.305C1004.79 284.305 1022.95 306.092 1022.95 346.037C1022.95 385.981 1004.79 407.769 972.11 407.769C939.429 407.769 921.272 385.981 921.272 346.037ZM1240.84 258.886L1237.21 255.254H1208.16L1204.53 258.886V346.037C1204.53 389.612 1186.01 407.769 1160.95 407.769C1131.9 407.769 1124.64 385.981 1124.64 364.193V258.886L1121.01 255.254H1091.96L1088.33 258.886V364.193C1088.33 403.774 1106.48 440.45 1157.32 440.45C1174.75 440.45 1191.45 431.735 1200.9 418.663H1204.53L1208.16 433.188L1211.79 436.819H1237.21L1240.84 433.188V258.886ZM1618.52 385.981C1618.52 353.299 1600.37 338.774 1564.05 331.511C1527.74 324.249 1513.22 320.618 1513.22 302.461C1513.22 287.936 1527.74 284.305 1545.9 284.305C1571.32 284.305 1578.58 295.199 1578.58 306.092L1582.21 309.724H1611.26L1614.89 306.092C1614.89 269.779 1585.84 251.623 1545.9 251.623C1495.06 251.623 1476.9 277.042 1476.9 302.461C1476.9 335.143 1498.69 349.668 1535 356.931C1571.32 364.193 1582.21 367.824 1582.21 385.981C1582.21 400.506 1571.32 407.769 1545.9 407.769C1520.48 407.769 1509.58 396.875 1509.58 378.718L1505.95 375.087H1476.9L1473.27 378.718C1473.27 418.663 1498.69 440.45 1545.9 440.45C1596.74 440.45 1618.52 415.031 1618.52 385.981ZM1843.65 251.623C1894.49 251.623 1905.38 284.305 1905.38 324.249V433.188L1901.75 436.819H1872.7L1869.07 433.188V324.249C1869.07 302.461 1865.44 284.305 1836.39 284.305C1810.97 284.305 1796.44 302.461 1796.44 331.511V433.188L1792.81 436.819H1763.76L1760.13 433.188V324.249C1760.13 302.461 1756.5 284.305 1727.45 284.305C1709.29 284.305 1687.5 295.199 1687.5 331.511V433.188L1683.87 436.819H1654.82L1651.19 433.188V258.886L1654.82 255.254H1680.24L1683.87 258.886L1687.5 273.411H1691.13C1698.4 262.517 1712.92 251.623 1738.34 251.623C1767.39 251.623 1778.29 266.148 1785.55 277.042H1789.18C1800.07 262.517 1818.23 251.623 1843.65 251.623ZM1981.48 222.573V193.522L1977.85 189.891H1948.8L1945.17 193.522V222.573L1948.8 226.204H1977.85L1981.48 222.573ZM1981.48 258.886L1977.85 255.254H1948.8L1945.17 258.886V433.188L1948.8 436.819H1977.85L1981.48 433.188V258.886ZM2126.63 407.769V433.188L2123 436.819H2093.95C2068.53 436.819 2043.11 422.294 2043.11 389.612V291.567L2039.48 287.936H2014.06L2010.43 284.305V258.886L2014.06 255.254H2039.48L2043.11 251.623V218.941L2046.75 215.31H2075.8L2079.43 218.941V251.623L2083.06 255.254H2123L2126.63 258.886V284.305L2123 287.936H2083.06L2079.43 291.567V389.612C2079.43 400.506 2086.69 404.137 2093.95 404.137H2123L2126.63 407.769ZM2319.05 433.188V327.88C2319.05 288.299 2304.53 251.623 2250.06 251.623C2230.81 251.623 2213.38 259.612 2202.85 273.411H2199.22V186.26L2195.59 182.628H2166.54L2162.91 186.26V433.188L2166.54 436.819H2195.59L2199.22 433.188V342.405C2199.22 298.83 2217.37 284.305 2246.42 284.305C2275.48 284.305 2282.74 306.092 2282.74 327.88V433.188L2286.37 436.819H2315.42L2319.05 433.188ZM631.176 345.959C631.176 305.983 649.347 284.178 682.055 284.178C711.129 284.178 722.031 298.715 725.665 313.252L729.3 316.886H758.373L762.007 313.252C758.373 280.544 732.934 251.47 682.055 251.47C627.542 251.47 594.834 287.812 594.834 345.959C594.834 404.107 627.542 440.449 682.055 440.449C732.934 440.449 758.373 411.375 762.007 378.667L758.373 375.033H729.3L725.665 378.667C722.031 393.204 711.129 407.741 682.055 407.741C649.347 407.741 631.176 385.936 631.176 345.959ZM868.926 408.456V433.875L865.294 437.507H846.064C820.645 437.507 795.226 422.982 795.226 390.3L795.224 186.26L798.856 182.628H827.906L831.537 186.26L831.539 390.3C831.539 401.194 838.802 404.825 846.064 404.825H865.294L868.926 408.456Z" fill="#092F45"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 111 KiB