{"id":20512574,"url":"https://github.com/jpluscplusm/asdf-arbitrary-code-execution","last_synced_at":"2026-03-10T06:02:10.242Z","repository":{"id":93632346,"uuid":"480035558","full_name":"jpluscplusm/asdf-arbitrary-code-execution","owner":"jpluscplusm","description":"A plugin for the ASDF version manager that installs arbitrary binaries ","archived":false,"fork":false,"pushed_at":"2022-08-13T10:30:57.000Z","size":453,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-16T09:09:32.986Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"CUE","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jpluscplusm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-10T14:04:43.000Z","updated_at":"2022-05-01T14:11:20.000Z","dependencies_parsed_at":"2023-03-16T07:15:54.707Z","dependency_job_id":null,"html_url":"https://github.com/jpluscplusm/asdf-arbitrary-code-execution","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jpluscplusm%2Fasdf-arbitrary-code-execution","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jpluscplusm%2Fasdf-arbitrary-code-execution/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jpluscplusm%2Fasdf-arbitrary-code-execution/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jpluscplusm%2Fasdf-arbitrary-code-execution/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jpluscplusm","download_url":"https://codeload.github.com/jpluscplusm/asdf-arbitrary-code-execution/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242117657,"owners_count":20074435,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T20:42:00.919Z","updated_at":"2026-03-10T06:02:05.168Z","avatar_url":"https://github.com/jpluscplusm.png","language":"CUE","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `asdf-ace`: Arbitrary Code Execution\n\nIn this README:\n  [Introduction](#introduction)\n| [Quick start](#quick-start)\n| [Using this plugin](#using-this-plugin)\n| [Variables provided by this plugin](#variables-provided-by-this-plugin)\n| [An example](#an-example-tool-and-configuration-file)\n| [Contributing to this plugin](#contributing-to-this-plugin)\n| [Why does this plugin exist?](#why-does-this-plugin-exist)\n| [Technical details](#technical-details)\n\n## Introduction\n\n`asdf-ace` is a plugin for the [ASDF version manager](https://asdf-vm.com/) that\ninstalls different version of arbitrary binaries _as configured by the user_,\nand lets ASDF switch between those versions.\n\nTo use it, follow the [Quick start](#quick-start) guide. This guide:\n\n- tells you about [the small set of pre-requisites](#pre-requisites) that\n  you'll need to install first.\n- takes you through [configuring this plugin](#configuration) via a simple file\n  in your home directory. This file is your personally-unique list of all the\n  tools that this plugin is allowed to install on your machine, and it can\n  contain any tool that you find useful. It's not limited to tools that appear in\n  [this plugin's examples directory](/examples) - that directory is just a\n  starting point.\n- shows you how to [use ASDF to add this plugin](#using-asdf-with-this-plugin)\n  for each tool you want to install\n- finally, shows you how to use ASDF to install a specific version of a tool\n  and make it available to your user\n\nBefore doing that, however, folks who care about the security of their systems\nshould expand and read the following Security Klaxon section:\n\n\u003chr\u003e\n\u003cdetails\u003e\n\u003csummary\u003e:accordion: Security Klaxon :rotating_light::rotating_light::rotating_light:\u003c/summary\u003e\n\nThis plugin's name is a \"playful\" reminder that the security model of ASDF\nis very much \"buyer beware\". ASDF requires you to trust plugin authors, as\nplugins execute code directly on your machine. This plugin goes one step\nfurther: **you must explicitly configure this plugin only to download binaries\nthat you trust**.\n\n**The onus is on you, the user, to use only those binaries that you trust**.\n\n_This plugin can only download binaries that you have **explicitly** told it\nabout_.\n\nYou should not use this plugin simply because someone tells you to. You should\nknow what problem you're trying to solve by using it, and should understand the\nlinks in the chain of trust that you're relying on.\n\nA later version of this plugin will deal with the thorny issue of validating\ndownloads. For now, this issue is in the user's hands -- your hands: only tell\nthis plugin to download binaries from sites, projects and users that you trust.\n\u003c/details\u003e\n\u003chr\u003e\n\n## Quick start\n\n1. Have a working [ASDF install](https://asdf-vm.com/).\n1. Find a tool that you want to install that publishes pre-compiled binaries\n   either as direct downloads, or inside compressed tarballs or zip archives.\n1. Grab the appropriate download URL for your machine and operating system.\n1. Install [the `CUE`\n   CLI](https://cuelang.org/docs/install/#install-cue-from-official-release-binaries).\n1. Install `curl`, and optionally either of `unzip` or `tar`, depending on the\n   format you're downloading.\n1. Configure the file `$XDG_CONFIG_HOME/asdf-ace/tools.cue` [as described\n   below](#configuration) with an appropriate tool setup:\n   - the tool's name is only an informative alias, and doesn't have to match\n     anything specific about the tool you're installing. In this quick start,\n     we imagine it to be `example_tool_name`.\n   - the `source` value should be the URL you grabbed, above, with any version\n     components swapped out for `\\(version.oc)`.\n   - the `creates` value (either a simple string for direct binary downloads,\n     or a key/value pair for tarball/zip archives and their contents) defines\n     the name of the binary you want to make available on your machine. In this\n     quick start, we imagine this to be `my_tool`.\n\n\u003chr\u003e\n\u003cdetails\u003e\n\u003csummary\u003e:accordion: Example config file\u003c/summary\u003e\n\n```\npackage asdface\n\nv0: tools:{\n  example_tool_name: #TarGz \u0026 {\n    source: \"https://example.com/a_useful_project/releases/\\(version.oc)/downloads/project-linux-amd64.tar.gz\"\n    create: my_tool: \"from/this/file/in/the/tarball\"\n  }\n}\n```\n\n\u003c/details\u003e\n\u003chr\u003e\n\n7. Install this plugin:\n\n       asdf plugin add example_tool_name https://github.com/jpluscplusm/asdf-arbitrary-code-execution\n\n7. Install a specific version of the tool:\n\n       asdf install example_tool_name v1.2.3\n\n7. Tell ASDF to make this specific version available:\n\n       asdf global example_tool_name v1.2.3\n\n7. Use the tool: `my_tool --help`\n\nIt's well worth reading [the configuration section and example](#configuration)\nto discover how you can make your config more portable, and how you can make it\navailable for other folks to use!\n\n## Using this plugin\n\n_This tool hasn't yet reached version 1.0, which means it's still experimental\nand its interface may change. We're working towards defining a stable\ninterface, so [your\nfeedback](https://github.com/jpluscplusm/asdf-arbitrary-code-execution/discussions/new?category=general)\nabout using the current interface will help us make the right choices, and is\nextremely welcome!_\n\n### Pre-requisites\n\nRequired:\n\n- `curl`\n- `cue` ([see below](#the-cue-cli))\n\nOptional, depending on which packaging formats are referenced:\n\n- Compressed tarballs: `tar` and `gunzip`\n- Zip archives: `unzip`\n- Direct binary downloads: no additional pre-requisites\n\n#### The `cue` CLI\n\nThis plugin requires the `cue` CLI in order to work.\n\nIf you don't already have it on your machine, it can be easily installed from\n[its official release\nbinaries](https://cuelang.org/docs/install/#install-cue-from-official-release-binaries)\non Windows, macOS, and Linux, or [installed from\nsource](https://cuelang.org/docs/install/#install-cue-from-source) on any other\nplatform that Go supports.\n\n*I'm well aware of the irony of this plugin -- a tool to\nautomate the installation of arbitrary binaries off the internet -- requiring\nits users to download a binary **manually** ... but this is the last one you\nshould ever need to fetch!*\n\nMake the `cue` CLI available in your `$PATH`, however you usually do that.\n\nIf you're installing from CUE's [official release\nbinaries](https://cuelang.org/docs/install/#install-cue-from-official-release-binaries)\nthen it's an easy 3-step process:\n\n\u003chr\u003e\n\u003cdetails\u003e\n\u003csummary\u003e:accordion: Installing the `cue` CLI in 3 easy steps\u003c/summary\u003e\n\nHere's how to install `cue` from a package [published by the CUE\nproject](https://github.com/cue-lang/cue/releases/latest):\n\n1. download the appropriate .tar.gz or .zip package for your operating system\n   and machine from their [GitHub releases\n   page](https://github.com/cue-lang/cue/releases/latest), near the bottom,\n   under \"Assets\".\n1. unpack just the `cue` binary from the package.\n   - you don't need the `doc/` directory that's also included in the package.\n   - for example:\n\n         tar xfz path/to/the/package/you/just/downloaded.tar.gz cue\n\n1. move the `cue` binary into a directory that's in your `$PATH`.\n   - `$HOME/bin/` will probably work, as would `/usr/local/bin/` (but it's your\n     machine, so it's up to you!).\n   - for example:\n\n         mkdir -p ~/bin/\n         mv -i cue ~/bin/\n\n   - If this is the first binary you've ever put in `$HOME/bin/`, you'll\n     probably need to close and re-open your terminal to pick it up. Test this\n     out by running `cue version` and seeing if your shell tells you \"command\n     not found\". If so, close and re-open the terminal window.\n\nIf you find doing this even *slightly* annoying, then congratulations: you're\nin the right place! The entire purpose of this ASDF plugin is to avoid having\nto do this *slightly* annoying process ever again!\n\n\u003c/details\u003e\n\u003chr\u003e\n\n### Configuration\n\nEach tool you configure can refer to either a compressed tarball, a zip\narchive, or a single unpackaged binary.\n\nA compressed tarball or zip archive can have multiple binaries extracted from\nthem. An unpackaged binary can only provide that single binary.\n\nPopulate the file `$XDG_CONFIG_HOME/asdf-ace/tools.cue` with 1 or more tool's\ninformation inside the top-level `v0` key (\"v0\" reflects the unstable nature of\nthis plugin, pre-1.0). If `$XDG_CONFIG_HOME` is unset (for instance if the tool\nis being used on a non-Linux OS, or the XDG conventions are not being used),\nthe configuration file should be placed at `$HOME/.config/asdf-ace/tools.cue`.\n\nIndicate that each tool is either a `#TarGz`, a `#Zip`, or a `#BinaryDownload`,\nas demonstrated here. NB The `\u0026 {` suffix is a *vital* part of the config!\n\n```CUE\npackage asdface\n\nv0: {\n  tools: {\n    tool_name: #BinaryDownload \u0026 {\n      source: \"https://example.com/path/to/binary/containing/\\(version.oc)/and/\\(go.os.lc)/and/\\(go.arch.uc)/vars\"\n      create: \"binary_filename_we_want_to_use_in_the_shell\"\n    }\n    \"tool-names-containing-hyphens-need-to-be-in-quotes\": #TarGz \u0026 {\n      source: \"https://example.com/path/to/file/containing/\\(version.oc)/and/\\(go.os.lc)/and/\\(go.arch.uc)/vars.tgz\"\n      create: binary_filename_we_want_to_use_in_the_shell: \"path/to/file/in/tarball\"\n      create: {\n        \"more-binaries-we-want-to-use-this-time-containing-hyphens\": \"path/to/this/file/in/the/same/tarball\"\n        simpleFilename: \"fileAtRootOfTarball\"\n      }\n    }\n    someTool: #Zip \u0026 {\n      source: \"https://example.com/path/\\(version.oc)/withvars/\\(go.os.lc)/and/\\(go.arch.uc)/archive-\\(version.oc).zip\"\n      create: {\n        binary_name:    \"path/to/file/in/ziparchive\"\n        binary_name_2:  \"path/to/this/file/in/the/same/ziparchive\"\n        simpleFilename: \"fileAtRootOfArchive\"\n      }\n    }\n  }\n}\n```\n\n#### Variables\n\nAny string can contain variables, expressed in the configuration language\n[CUE](https://cuelang.org). Expand the next :accordion: section for an\nincomplete crash course in CUE, its strings, and variables.\n\n\u003chr\u003e\n\u003cdetails\u003e\n\u003csummary\u003e:accordion: CUE: an incomplete, 90 second guide\u003c/summary\u003e\n\n##### CUE: an incomplete, 90 second guide\n\nBecause this plugin's configuration is written in [CUE](https://cuelang.org),\nyou have all the facilities of CUE available when writing your configuration.\n\nBut don't let that put you off - **you don't need to learn a whole new language**!\n\nIn the **vast** majority of cases you'll only\nneed to use [CUE's `\\(variable)`\ninterpolation](https://cuelang.org/docs/tutorials/tour/expressions/interpolation/)\nto set things up correctly, and this syntax is extremely plain and\nstraightforward.\n\nHere's a really simple guide to the features of CUE that you'll probably need\nto use.\n\nThis plugin requires your configuration file to declare itself, on its first\nline, to be part of the `asdface` package in order to work correctly.\n\n    package asdface\n\nNote that this package name doesn't contain a hyphen.\n\nCUE is a hierarchy of key:value pairs, nested as deeply as you need.\n\nCUE keys are strings. If they only contain only alphanumerics\n(`[a-z][A-Z][0-9]`) and underscores then they don't need to be quoted. If they\ncontain hyphens, spaces, or other punctuation, then they have to be contained\nin double quotes.\n\n    key: ...\n    key1: ...\n    a_key_with_underscores: ...\n    \"a key with spaces\": ...\n    \"a-key-with-hyphens\": ...\n\nNested keys can also be quoted or unquoted strings, depending on their\nalphanumeric contents, as above. Curly braces are used to indicate nesting.\n\n    key: {\n      a_nested_key: {\n        \"a-third-level-key\": {\n          \"A Deeply nested key\": ...\n        }\n      }\n    }\n\nCUE values can be any type. This plugin require leaf node values to be strings.\n\nThis plugin reads its configuration from keys inside the `v0.tools` hierarchy:\n\n    v0: {\n      tools: {\n        ...\n      }\n    }\n\nString values are contained in double quotes.\n\n    key: \"a key value\"\n\nLine comments extend from a double-forward-slash to the end of the line.\n\n    // this is a comment on a line by itself\n    key: \"a value\" // this is a comment alongside a key\n\nStrings can be concatentated with the `+` operator.\n\n    key: \"a value \" + \"split in 2\" // produces ...\n    key: \"a value split in 2\"\n\nBoth of the above definitions of `key` can co-exist in the same config\nsimultaneously, because they agree with one another. CUE config is evaluated\norder-independently, except where inherently ordered entities are involved,\nsuch as arrays. This plugin does not require you to use arrays.\n\nStrings can be split across multiple lines at any point, any number of times.\nIndentation is unimportant, but the `cue fmt [filename]` command will reformat\nyour config file to the \"official\" standards, if you ask it to!\n\n    key: \"a long value that \" +\n       \"needs to be split \" +\n                \"across \" +\n       \"multiple lines\"\n    key: \"a long value that needs to be split across multiple lines\"\n\nAs above, because both definitions of `key` agree with one another they are\nable to co-exist in the same CUE configuration. However, the 2nd definition is\nnot *required* - it is included here solely to demonstrate the end result. It\nwould be entirely valid if it *were* included, however.\n\nStrings can include variables that are interpolated inline, using `\\(value)`\nsyntax.\n\n    key1: \"a value\"\n    key2: \"this string also contains \\(key1)\"\n    key2: \"this string also contains a value\"\n\nBecause CUE evaluation is order-independent, assignment can happen after use.\n\n    key1: \"this string contains \\(key2)\"\n    key2: \"another string\"\n    key1: \"this string contains another string\"\n\nA single string can use both interpolation and concatentation.\n\n    key1: \"value\"\n    key2: \"this string contains a \\(key1) and also another \" + key1\n    key2: \"this string contains a value and also another value\"\n\nThe [variables that this plugin provides](#variables-provided-by-this-plugin)\ncan be interpolated or concatenated into strings, in all the ways laid out\nabove.\n\nFor example, given the variable `go.os.lc` containing the string `\"linux\"` ...\n\n    key: \"the/current-os/is/\\(go.os.lc)/\" // results in\n    key: \"the/current-os/is/linux/\"\n\n\u003c/details\u003e\n\u003chr\u003e\n\n##### Variables provided by this plugin\n\nAll variables contain 2 components: a selector and a modifier, separated by a\n`.` (period).\n\nThis is the set of valid selectors, which will expand as we discover more\nuseful values:\n\n- `version`: the literal version requested by the user\n- `uname.m`: the output of `uname -m` - the machine's processor architecture\n- `uname.s`: the output of `uname -s` - the machine's operating system\n- `go.os`:   the Go language's concept of the machine's running OS\n- `go.arch`: a reasonable (but incomplete!) approximation of Go's\n  `runtime.GOARCH` concept. Please do submit a PR (or [file an\n  Issue](https://github.com/jpluscplusm/asdf-arbitrary-code-execution/issues/new))\n  if this could be improved in any way!\n\nModifiers indicate the specific upper/lower/etc case version of the selector's\nvalue that you want to use. You can use the following modifiers on all\nselectors:\n\n- `oc` - original case: the exact string that the operating system gave us\n- `uc` - upper case: the `.oc` value, with all upper-case characters\n- `lc` - lower case: the `.oc` value, with all lower-case characters\n- `tc` - title case: the `.oc` value, with all words title-cased\n  -this is not very useful, as title-casing works on word boundaries\n  - it *might* be useful to get the string \"Linux\" from the input \"linux\" or\n    \"Amd64\" from \"amd64\" or \"Bsd\" from \"BSD\"\n- `cc` - camel case: the `.oc` value, with all words camel-cased\n  - even less useful than title-cased. If this IS useful, please do PR an\n    example to this doc!\n\nCombining all the selectors with all the modifiers means that there are\ncurrently 25 variables available to interpolate into your configuration keys:\n\n```\n    case\u003e|   original         upper         lower         title         camel\n---------+--------------------------------------------------------------------\nVersion  | version.oc    version.uc    version.lc    version.tc    version.cc\nCPU      | uname.m.oc    uname.m.uc    uname.m.lc    uname.m.tc    uname.m.cc\nOS       | uname.s.oc    uname.s.uc    uname.s.lc    uname.s.tc    uname.s.cc\nGOOS     | go.os.oc      go.os.uc      go.os.lc      go.os.tc      go.os.cc\nGOARCH   | go.arch.oc    go.arch.uc    go.arch.lc    go.arch.tc    go.arch.cc\n```\n\n### An example tool and configuration file\n\nSo, for example, to reference a binary that's downloadable *for your specific\nmachine* from\n\n```\nhttps://example.com/a_useful_project/releases/v1.2.3/downloads/project-linux-amd64\n```\n\n... the smallest reasonable `source` line that you could use is this (notice we\ncan split the value across lines, to make it more readable):\n\n```\nsource: \"https://example.com/a_useful_project/releases/\" +\n  \"\\(version.oc)/downloads/project-linux-amd64\"\n```\n\nThis is because at least one variant of the `version` selector should (*must*!)\nbe present in the `url` key, because the `$XDG_CONFIG_HOME/asdf-ace/tools.cue`\nfile isn't the final arbiter of *which* version ASDF will install.  No: **ASDF\n(and therefore you, the user) is in charge of WHICH version gets installed, not\nthis config file.**\n\nThe config file teaches ASDF, via this plugin, how to download DIFFERENT\nversions.  If the version is hardcoded in the config then ... what's the point?\n\nHOWEVER, this `source` line example, above, only works to switch between\nversions on your specific machine: a machine running Linux and containing an\n`x86_64`/`amd64` chip.\n\nIn order to make this config more portable, so you could re-use it on different\noperating systems and physical hardware, you'd need to swap more fixed elements\nfor variables in the `source` line. All the examples in [this plugin's examples\ndirectory](/examples/) use this feature, so that you can simply copy and paste\nany of the examples into your `$XDG_CONFIG_HOME/asdf-ace/tools.cue` file, and\ninstall the appropriate tool instantly. If you're going to PR an example into\nthis plugin, so other people can benefit from your effort, please make the\nexample as portable as you can!\n\nTo demonstrate doing this, let's pretend that you check your example\n`a_useful_project`'s Downloads page and discover that the project publishes\nbinaries for 3 different system types, on these 3 URL path suffixes:\n\n```\npaths relative to the prefix \"https://example.com/a_useful_project\":\n\n  /releases/\\(version.oc)/downloads/project-linux-x86_64\n  /releases/\\(version.oc)/downloads/project-darwin-arm64\n  /releases/\\(version.oc)/downloads/project-darwin-x86_64\n```\n\nIn addition to the `version.oc` variable that you used (so that ASDF can switch\nversions for you) there are 2 more variable components of the URL: the\noperating system (`linux` vs `darwin` (Mac OS)) and the machine architecture\n(`x86_64` vs `arm64`).\n\nThese variables are already available in the selectors `uname.s` (operating\nsystem) and `uname.m` (architecture). Putting them in place, we end up with a\nsingle `source` line that works on any machine type for which\n`a_useful_project` has published binaries:\n\n```\nsource: \"https://example.com/a_useful_project/releases/\" +\n  version.oc +\n  \"/downloads/\" +\n  \"project-\\(uname.s.lc)-\\(uname.m.lc)\"\n```\n\nNotice that we split the long line to make it easier to read, and that we mix\nour use of [CUE's string interpolation\nsyntax](https://cuelang.org/docs/tutorials/tour/expressions/interpolation/)\nwith simply [concatenating string values\ntogther](https://cuetorials.com/overview/expressions/#mathematical-operations),\nwhere that makes more sense. This plugin doesn't care about how you use CUE to\nassemble a value - it only cares that it can download and process the resulting\nURL and archive :-)\n\nNext, we add detail in the `create` key about the name of the binary we want to\nbe able to run on our machine (`useful`). We also wrap it up in the config\nhierarchy that the plugin requires:\n\n```\nv0: tools: a_useful_project: #BinaryDownload \u0026 {\n  source: \"https://example.com/a_useful_project/releases/\" +\n    version.oc +\n    \"/downloads/\" +\n    \"project-\\(uname.s.lc)-\\(uname.m.lc)\"\n  create: \"useful\"\n}\n```\n\n### Using ASDF with this plugin\n\nAfter seeding the config file with the neccessary information about the tool we\nwant to install, we can install the binary.\n\n**NB make sure you've [installed the CUE cli](#pre-requisites) -- an easy,\nsmall, single-binary download -- before carrying on!**\n\n```\nasdf plugin add a_useful_project \\\n  https://github.com/jpluscplusm/asdf-arbitrary-code-execution\nasdf install a_useful_project v1.2.3\n```\n\n... and then, to tell ASDF to make that version available to your shell:\n\n```\nasdf global a_useful_project v1.2.3\n```\n\nAfter running this, the (fake!) command `useful` would be available, with the\nrequested version having been downloaded and the correct binary having been\nselected for the machine you're using.\n\n`v1.2.3` in both the commands, above, **is where you tell ASDF which version\nyou want to install**.\n\nCurrently, this tool doesn't list remote versions, or know the latest/stable\nversion that's available. *You need to know and specify the exact version that\nyou want to install.*\n\n## Contributing to this plugin\n\n### Examples of tools that other folks might find useful\n\nIf you have an example of a tool that can installed by this plugin, we'd love\nto hear about them! If we can make the example portable enough, it'll be added\nto the [example library](/examples) of tools that users can simply copy'n'paste\ninto their config files.\n\nPlease [start an \"Ideas\"\nDiscussion](https://github.com/jpluscplusm/asdf-arbitrary-code-execution/discussions/new?category=ideas)\nwith as much detail as you have about the tool, and how you've configured this\nplugin to install it.\n\nIf you feel like [opening a\nPR](https://github.com/jpluscplusm/asdf-arbitrary-code-execution/pulls) to add\nthe tool into the [examples/](examples/) directory, that would be really\nhelpful. If you add [a system test](dagger.cue#L96) to make sure that your\nexample is working, that would be awesome!\n\n### New variables and features\n\nIf you're considering adding new variables or features to this plugin, we'll\nassume you know a bit about development, and will simply outline the process to\nyou. Please read [the plugin's rationale](#why-does-this-plugin-exist) to check\nif the feature you're thinking of proposing looks like a good fit.\n\nPlease:\n\n1. Install [Dagger](https://docs.dagger.io/1200/local-dev)\n   - If you'd prefer Dagger not to use Docker to bootstrap BuildKit for you,\n     but instead you've run BuildKit manually, simply teach Dagger about your\n     Buildkit server with `BUILDKIT_HOST=`\n1. Fork the repo and check out (or branch off) the `develop` branch\n1. Make changes, including adding tests\n1. Run `dagger do test`\n1. Make both your tests and the existing tests pass\n1. Push your changes to your fork\n1. Open a PR to incoporate your changes into the `develop` branch\n\n## Why does this plugin exist?\n\nI got bored with the repeated process of having to check that ASDF plugins\nweren't malicious, so I wrote a plugin to replace ~90% of the ASDF plugins that\nI use. This is that plugin: `asdf-ace`. If you'd like more detail, read the\n:accordion:.\n\n\u003chr\u003e\n\u003cdetails\u003e\n\u003csummary\u003e:accordion: Why oh why oh why?\u003c/summary\u003e\n\n[ASDF](https://asdf-vm.com) is *great*! Just look at [the long list of all the\nplugins](https://github.com/asdf-vm/asdf-plugins#plugin-list) folks have\nwritten for it, and the size of its ecosystem! The folks who bother to take the\ntime to write those plugins are excellent human beings - their efforts helped\nme start using ASDF, and I thank them for all their hard work :-)\n\nI started using ASDF a while ago, as I wanted to replace a DIY version\nmanagement system I'd hacked into existence. But as I added to the set of tools\nthat I managed via ASDF, a boring process kept happening.\n\nFor every tool I installed, I found myself having to go into the associated\nplugin's repo and double-check that its installer did what it said. After all,\nit's running code on my machine ... I need to check it's not malicious.\n\nI began to notice that each of the tools I installed, using plugins in that\nlong list, seemed to belong to one of three categories:\n\n1. tools that are complex to install, and perhaps bring their own package\n   manager along with them (e.g. `ruby`, `node`, `npm`)\n1. tools that require several steps to compile, install; or perhaps unpack and\n   arrange many files from an installer on the target system\n1. tools whose installers download a single file from the internet, maybe\n   uncompress it, and then chmod+x the result.\n\nOver time, a pattern emerged.\n\nI noticed that a significant majority of the tools I installed belonged to\ncategory #3: `download`, then *maybe* `extract`, then `chmod`. And very often\ntheir plugins were copy/paste versions of some normalised ASDF shell script ...\nbut I **still** had to manually check each one, as I couldn't be sure they\nactually *were* a copy/paste.\n\nThis commonality strongly suggested that there was a repeatable, automatable\nsolution to this problem. And so, because I wanted to stop repeatedly\nperforming this mini-audit, over and over again, I wrote this plugin.\n\nThis plugin, `asdf-ace` tries to handle the simple, boring, \"download a binary\noff the internet and chmod it\" case for tools that fit into category #3.\n\nIt takes a *tiny* bit of setup and 1% more effort to use than the many-plugins\napproach, but it's worth it to me.\n\nBy publishing [config examples that users can cut'n'paste](/examples), even\nthat tiny bit of setup and +1% effort is reduced.\n\nBy allowing users to put anything they like in their configuration file, **this\nplugin's repo doesn't act as a gatekeeper** of which tools are \"allowed\" to be\ninstalled with this plugin. Adding any specific tool's config into the\n[examples](/examples) directory is merely a **friendly, positive addition to\nthe ecosystem**, and *not a required step* in the process of using this plugin\nto install that tool.\n\nHopefully, if you also like to know what code is running on your machine, you\ndon't have to *trust* this plugin: you can audit the code in this repo once,\npin to a specific commit for all your boring-tool ASDF installs, and not have\nto repeat the audit rigamarole of a subtly different plugin for each new tool\nyou teach it about. Yes, you'll miss out on new features that this plugin\nintroduces (remote version listing and binary checksum checking is planned!),\nbut you'll *know* that you understand what's running on your machine.\n\nTo understand the plugin's inner workings, please read the [technical\ndetails](#technical-details) section.\n\n\u003c/details\u003e\n\u003chr\u003e\n\n## Technical details\n\n### Summary\n\nThis plugin:\n\n- learns which tool is it being told to install, by looking at the directory\n  hierarchy into which it has been git-cloned by ASDF\n- learns which version of the tool it is being told to install, by looking at\n  an environment variable set by ASDF\n- discovers various runtime-specific facts about the machine it's running on\n  (e.g. processor architecture; OS type)\n- feeds all the above data points into a CUE-based templating system, which ...\n- reads the user-specified configuration, which contains user-authored mappings\n  from facts to tool-and-version-specific download and install parameters; and\n- emits a pair of download and install snippets, tailored to the machine on\n  which the tool is being installed.\n\nThe plugin then:\n\n- executes the download snippet to fetch the remote file\n- executes the install snippet, which involves it:\n  - uncompressing the downloaded file, if the user indicates that the remote\n    file is a `.zip` or `.tar.gz`\n  - renaming the resulting file to the name the user chose\n  - making the file executable\n  - moving the executable into the directory that ASDF told it to use\n\nIf the user points to a remote `.zip` or `.tar.gz`, the tool can be told to\nextract more than one executable binary from the archive. This mechanism is\ndeliberately intended not to scale beyond a few files.\n\n### A poor analogy to a shell script\n\nThis plugin is a more capable but more complicated version of the following\n(fake, non-functional) shell script. It's hidden behind a :accordion: because\nit's so ugly that it's offputting, and *this shell script plays absolutely no\npart in this plugin's job: **it's shown here solely as a pseudo-code analogy**!*\n\n\u003chr\u003e\n\u003cdetails\u003e\n\u003csummary\u003e:accordion: Don't worry - this isn't the actual implementation!\u003c/summary\u003e\n\n```bash\nconfig_file=~/.config/asdf-ace/tools.not-really.this-is-fake.txt\n\nread TOOL_TO_INSTALL\nread VERSION_TO_INSTALL\nread INSTALL_DIRECTORY\n\nURL=$(grep \"^${TOOL_TO_INSTALL}.url\" $config_file | cut -f2)\nUNAME_M=$(uname -m)\nUNAME_S=$(uname -s)\n\ncat generic-download-script                      \\\n| sed -e \"s/__URL__/$URL/g\"                      \\\n      -e \"s/__VERSION__/$VERSION_TO_INSTALL/g\"   \\\n      -e \"s/__UNAME_M__/$UNAME_M/g\"              \\\n      -e \"s/__UNAME_S__/$UNAME_S/g\"              \\\n| bash                                           \\\n\u003e downloaded-file\n\nUNPACKER=$(grep \"^${TOOL_TO_INSTALL}.unpacker\" $config_file | cut -f2)\nBINARY=$(grep   \"^${TOOL_TO_INSTALL}.binary\"   $config_file | cut -f2)\n\ncat generic-install-script                       \\\n| sed -e \"s/__UNPACKER__/$UNPACKER/g\"            \\\n      -e \"s/__BINARY__/$BINARY/g\"                \\\n      -e \"s/__DOWNLOAD__/downloaded-file/g\"      \\\n      -e \"s/__VERSION__/$VERSION_TO_INSTALL/g\"   \\\n      -e \"s/__INSTALL_TO__/$INSTALL_DIRECTORY/g\" \\\n      -e \"s/__UNAME_M__/$UNAME_M/g\"              \\\n      -e \"s/__UNAME_S__/$UNAME_S/g\"              \\\n| bash\n```\n\n\u003c/details\u003e\n\u003chr\u003e\n\nMore detail will be added here.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjpluscplusm%2Fasdf-arbitrary-code-execution","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjpluscplusm%2Fasdf-arbitrary-code-execution","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjpluscplusm%2Fasdf-arbitrary-code-execution/lists"}