Skip to content

Commit

Permalink
feat: asdf-plugin-manager first version (#1)
Browse files Browse the repository at this point in the history
Manage asdf plugins securely and declaratively.

Fixes:
- asdf-vm/asdf#166
- asdf-vm/asdf#240
- asdf-vm/asdf#829
- asdf-vm/asdf#1577
  • Loading branch information
aabouzaid committed Aug 7, 2023
1 parent 924b11c commit a68f1d7
Show file tree
Hide file tree
Showing 14 changed files with 275 additions and 94 deletions.
24 changes: 21 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
pull_request:

jobs:
plugin_test:
plugin-test:
name: asdf plugin test
strategy:
matrix:
Expand All @@ -16,7 +16,25 @@ jobs:
- macos-latest
runs-on: ${{ matrix.os }}
steps:
- name: asdf_plugin_test
- name: Run asdf plugin test
uses: asdf-vm/actions/plugin-test@v2
with:
command: asdf-plugin-manager --version
command: asdf-plugin-manager version
- uses: actions/checkout@v3
- name: Install asdf-plugin-manager
run: |
asdf plugin add asdf-plugin-manager .
asdf install asdf-plugin-manager latest
asdf global asdf-plugin-manager latest
- name: Test asdf-plugin-manager
run: |
cd test
asdf-plugin-manager list
asdf-plugin-manager add-all
asdf plugin list --refs
- name: Validate installed plugins
run: |
set -euox pipefail
PLUGIN_GIT_REF=$(grep -oE "[^ ]\w{39}$" test/.plugin-versions)
asdf plugin list --refs | grep "${PLUGIN_GIT_REF}" &&
echo "[Passed] The plugin git ref in test/.plugin-versions matches the installed one."
10 changes: 10 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- main

permissions:
actions: write
contents: write
pull-requests: write

Expand All @@ -14,5 +15,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: GoogleCloudPlatform/release-please-action@v3
id: release
with:
release-type: simple
- uses: actions/checkout@v3
- name: Upload Release Artifact
if: ${{ steps.release.outputs.release_created }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cp -a cli/asdf-plugin-manager.sh asdf-plugin-manager-${{ steps.release.outputs.tag_name }}.sh
gh release upload ${{ steps.release.outputs.tag_name }} asdf-plugin-manager-${{ steps.release.outputs.tag_name }}.sh
2 changes: 1 addition & 1 deletion .github/workflows/semantic-pr.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Lint
name: Semantic PR

on:
pull_request_target:
Expand Down
4 changes: 1 addition & 3 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
TODO: INSERT YOUR NAME COPYRIGHT YEAR (if applicable to your license)

Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Expand Down Expand Up @@ -188,7 +186,7 @@ TODO: INSERT YOUR NAME COPYRIGHT YEAR (if applicable to your license)
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2023 Ahmed AbouZaid

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
99 changes: 77 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,115 @@
<div align="center">

<!-- omit in toc -->
# asdf-plugin-manager [![Build](https://github.com/aabouzaid/asdf-plugin-manager/actions/workflows/build.yml/badge.svg)](https://github.com/aabouzaid/asdf-plugin-manager/actions/workflows/build.yml) [![Lint](https://github.com/aabouzaid/asdf-plugin-manager/actions/workflows/lint.yml/badge.svg)](https://github.com/aabouzaid/asdf-plugin-manager/actions/workflows/lint.yml)

[plugin-manager](https://github.com/aabouzaid/asdf-plugin-manager) plugin for the [asdf version manager](https://asdf-vm.com).
Manage [asdf version manager](https://asdf-vm.com) plugins securely and declaratively.

Using `asdf-plugin-manager`, you can set plugins Git URL and ref for security and integrity. So it's the only plugin you need to validate manually and the rest are validated via `.plugin-versions` file. Check [example](#example) for more details.

**Yes, this is an asdf plugin to manage asdf plugins!**
</div>

<!-- omit in toc -->
# Contents

- [Why?](#why)
- [Dependencies](#dependencies)
- [Install](#install)
- [Example](#example)
- [Parameters](#parameters)
- [Contributing](#contributing)
- [License](#license)

# Dependencies
# Why?

**TODO: adapt this section**
[Asdf is a great universal version manager](https://tech.aabouzaid.com/2022/01/asdf-vm-a-universal-version-manager-tools.html).
However, it lacks a secure and declarative method to manage its plugins. For example, you cannot pin a specific asdf plugin version, which means you will be easily hacked if one of the asdf plugins you use is compromised!

- `bash`, `curl`, `tar`: generic POSIX utilities.
- `SOME_ENV_VAR`: set this environment variable in your shell config to load the correct version of tool x.
[Many exist requests asking to fix that](https://github.com/asdf-vm/asdf/issues/1577), but no solution has been proposed in `asdf` upstream yet! (Last check: Aug 2023)

Hence, `asdf-plugin-manager` fills the gap to manage asdf plugins securely and declaratively via `.plugin-versions` file.

# Dependencies

- [asdf-vm](https://asdf-vm.com/): Tested with `v0.12.0` but probably will work with older versions.
- `bash`, `cat`, `grep`, `tr`, `cut`, `column`: Generic POSIX utilities.
- `ASDF_PLUGIN_MANAGER_PLUGIN_VERSIONS_FILENAME`: Set default name for the file with the list of managed plugins.
Default: `.plugin-versions`.

# Install

Plugin:
Setup `asdf-plugin-manager` asdf plugin:

```shell
asdf plugin add plugin-manager
# or
asdf plugin add plugin-manager https://github.com/aabouzaid/asdf-plugin-manager.git
asdf plugin add asdf-plugin-manager https://github.com/aabouzaid/asdf-plugin-manager.git
asdf plugin update asdf-plugin-manager v1.0.0
```

plugin-manager:
Setup `asdf-plugin-manager` actual CLI:

```shell
# Show all installable versions
asdf list-all plugin-manager

# Install specific version
asdf install plugin-manager latest
asdf install asdf-plugin-manager latest

# Set a version globally (on your ~/.tool-versions file)
asdf global plugin-manager latest
asdf global asdf-plugin-manager latest

# Now asdf-plugin-manager commands are available
asdf-plugin-manager version
```

# Example

Using `asdf-plugin-manager`, the `.plugin-versions` file will be the source of truth for asdf plugins.
Its syntax as follows:

```
# Plugin name Git URL Git ref (hash, tag, or branch)
venom https://github.com/aabouzaid/asdf-venom.git 2d94d17
```

# Now plugin-manager commands are available
asdf-plugin-manager --version
You can also export the current added plugins to be managed by `asdf-plugin-manager`:

```shell
asdf-plugin-manager export > .plugin-versions
```

From now on, you can use `.plugin-versions` to manage asdf plugins.

```shell
# Add all plugins according to .plugin-versions file
asdf-plugin-manager add-all
```

Or

```shell
# Add named plugin according to .plugin-versions file
asdf-plugin-manager add venom
```

Check [asdf](https://github.com/asdf-vm/asdf) readme for more instructions on how to
install & manage versions.
# Parameters

The following all `asdf-plugin-manager` parameters:

```
asdf-plugin-manager help : Print this help message
asdf-plugin-manager version : Print asdf-plugin-manager current version
asdf-plugin-manager export : List currently installed plugins to be used in .plugin-versions
asdf-plugin-manager list : List plugins in .plugin-versions file
asdf-plugin-manager add <plugin-name> : Add named plugin according to .plugin-versions file
asdf-plugin-manager add-all : Add all plugins according to .plugin-versions file
asdf-plugin-manager remove <plugin-name> : Remove named plugin according to .plugin-versions file
asdf-plugin-manager remove-all : Remove all plugins according to .plugin-versions file
```

# Contributing

Contributions of any kind welcome! See the [contributing guide](contributing.md).
Contributions of any kind are welcome! See the [contributing guide](contributing.md).

[Thanks goes to these contributors](https://github.com/aabouzaid/asdf-plugin-manager/graphs/contributors)!
[Thanks go to these contributors](https://github.com/aabouzaid/asdf-plugin-manager/graphs/contributors)!

# License

See [LICENSE](LICENSE) © [Ahmed AbouZaid](https://github.com/aabouzaid/)
See [LICENSE](LICENSE) © [Ahmed AbouZaid](https://github.com/aabouzaid/).
11 changes: 2 additions & 9 deletions bin/download
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,7 @@ source "${plugin_dir}/lib/utils.bash"

mkdir -p "$ASDF_DOWNLOAD_PATH"

# TODO: Adapt this to proper extension and adapt extracting strategy.
release_file="$ASDF_DOWNLOAD_PATH/$TOOL_NAME-$ASDF_INSTALL_VERSION.tar.gz"
release_file="$ASDF_DOWNLOAD_PATH/$TOOL_NAME-$ASDF_INSTALL_VERSION"

# Download tar.gz file to the download directory
# Download release file to the download directory
download_release "$ASDF_INSTALL_VERSION" "$release_file"

# Extract contents of tar.gz file into the download directory
tar -xzf "$release_file" -C "$ASDF_DOWNLOAD_PATH" --strip-components=1 || fail "Could not extract $release_file"

# Remove the tar.gz file since we don't need to keep it
rm "$release_file"
6 changes: 3 additions & 3 deletions bin/latest-stable
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ plugin_dir=$(dirname "$(dirname "$current_script_path")")
curl_opts=(-sI)

if [ -n "${GITHUB_API_TOKEN:-}" ]; then
curl_opts=("${curl_opts[@]}" -H "Authorization: token $GITHUB_API_TOKEN")
curl_opts=("${curl_opts[@]}" -H "Authorization: token $GITHUB_API_TOKEN")
fi

# curl of REPO/releases/latest is expected to be a 302 to another URL
Expand All @@ -21,9 +21,9 @@ redirect_url=$(curl "${curl_opts[@]}" "$GH_REPO/releases/latest" | sed -n -e "s|
version=
printf "redirect url: %s\n" "$redirect_url" >&2
if [[ "$redirect_url" == "$GH_REPO/releases" ]]; then
version="$(list_all_versions | sort_versions | tail -n1 | xargs echo)"
version="$(list_all_versions | sort_versions | tail -n1 | xargs echo)"
else
version="$(printf "%s\n" "$redirect_url" | sed 's|.*/tag/v\{0,1\}||')"
version="$(printf "%s\n" "$redirect_url" | sed 's|.*/tag/v\{0,1\}||')"
fi

printf "%s\n" "$version"
113 changes: 113 additions & 0 deletions cli/asdf-plugin-manager.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env bash

set -eo pipefail

VERSION=1.0.0
PLUGIN_VERSIONS_FILENAME="${ASDF_PLUGIN_MANAGER_PLUGIN_VERSIONS_FILENAME:-.plugin-versions}"

print_version() {
echo "${VERSION}"
}

print_plugin_versions_filename() {
echo "${PLUGIN_VERSIONS_FILENAME}"
}

print_help() {
cat <<EOF
Manage asdf plugins securely and declaratively via .plugin-versions file.
Using asdf-plugin-manager, you can set plugins Git URL and ref for security and integrity.
VARS:
ASDF_PLUGIN_MANAGER_PLUGIN_VERSIONS_FILENAME: Set default name for the file with the list of managed plugins.
Default: "$(print_plugin_versions_filename)".
USAGE:
asdf-plugin-manager help : Print this help message
asdf-plugin-manager version : Print asdf-plugin-manager current version
asdf-plugin-manager export : List currently installed plugins to be used in .plugin-versions
asdf-plugin-manager list : List plugins in .plugin-versions file
asdf-plugin-manager add <plugin-name> : Add named plugin according to .plugin-versions file
asdf-plugin-manager add-all : Add all plugins according to .plugin-versions file
asdf-plugin-manager remove <plugin-name> : Remove named plugin according to .plugin-versions file
asdf-plugin-manager remove-all : Remove all plugins according to .plugin-versions file
EOF
}

export_plugins() {
asdf plugin-list --refs --urls | tr -s ' ' | cut -d ' ' -f 1,2,4 | column -t
}

list_plugins() {
plugin_name=$1
if [[ -n ${plugin_name} ]]; then
grep "^${plugin_name} " "$(print_plugin_versions_filename)"
else
grep -v "^#" "$(print_plugin_versions_filename)"
fi
}

remove_plugins() {
local managed_plugins="$1"
echo "${managed_plugins}" | while read managed_plugin; do
read -r plugin_name _plugin_url _plugin_ref < <(echo ${managed_plugin})
echo "[INFO] Removing: ${plugin_name}"
asdf plugin remove "${plugin_name}" || true
done
}

add_plugins() {
local managed_plugins="$1"
echo "${managed_plugins}" | while read managed_plugin; do
read -r plugin_name plugin_url plugin_ref < <(echo ${managed_plugin})
echo "[INFO] Adding: ${plugin_name} ${plugin_url} ${plugin_ref}"
remove_plugins "$(list_plugins ${plugin_name})"
asdf plugin add "${plugin_name}" "${plugin_url}"
# TODO: Remove the plugin update once asdf supports adding plugin with git-ref.
# https://github.com/asdf-vm/asdf/pull/1204
asdf plugin update "${plugin_name}" "${plugin_ref}"
echo "[INFO] Done."
done
}

if [[ -z $1 ]]; then
print_help
exit 1
fi

while test -n "$1"; do
case "$1" in
help | -h)
print_help
exit 1
;;
version | -v)
print_version
exit 0
;;
export)
export_plugins
;;
list)
list_plugins
;;
add)
add_plugins "$(list_plugins $2)"
;;
add-all)
add_plugins "$(list_plugins)"
;;
remove)
remove_plugins "$(list_plugins $2)"
;;
remove-all)
remove_plugins "$(list_plugins)"
;;
*)
echo "Unknown argument: $1"
print_help
exit 1
;;
esac
shift
done
3 changes: 1 addition & 2 deletions contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ Testing Locally:
```shell
asdf plugin test <plugin-name> <plugin-url> [--asdf-tool-version <version>] [--asdf-plugin-gitref <git-ref>] [test-command*]

# TODO: adapt this
asdf plugin test plugin-manager https://github.com/aabouzaid/asdf-plugin-manager.git "asdf-plugin-manager --version"
asdf plugin test asdf-plugin-manager https://github.com/aabouzaid/asdf-plugin-manager.git "asdf-plugin-manager list"
```

Tests are automatically run in GitHub Actions on push and PR.

0 comments on commit a68f1d7

Please sign in to comment.