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 3f8a059
Show file tree
Hide file tree
Showing 13 changed files with 244 additions and 91 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."
8 changes: 8 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,12 @@ 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 }}
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
75 changes: 56 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,96 @@
<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. **(yes, this is an asdf plugin to manage asdf plugins!)**

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 [usage](#usage) for more details.
</div>

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

- [Why?](#why)
- [Dependencies](#dependencies)
- [Install](#install)
- [Usage](#usage)
- [Known Limitations](#known-limitations)
- [Contributing](#contributing)
- [License](#license)

# Dependencies
# Why?

[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!

[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.

**TODO: adapt this section**

- `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.
# Dependencies

- [asdf-vm](https://asdf-vm.com/)
- `bash`, `cat`, `grep`: 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 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 update asdf-plugin-manager 1.0.0
```

plugin-manager:
Set asdf-plugin-manager version:

```shell
# Show all installable versions
asdf list-all plugin-manager
asdf list-all asdf-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 list
```

# Usage

The `.plugin-versions` file syntax:

```
# Name Git URL Git ref (hash or version)
venom https://github.com/aabouzaid/asdf-venom.git 2d94d17
```

And `asdf-plugin-manager` args:

# Now plugin-manager commands are available
asdf-plugin-manager --version
```
asdf-plugin-manager help : Print this help message
asdf-plugin-manager version : Print asdf-plugin-manager current version
asdf-plugin-manager list : List managed plugins according to .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
```

# Known Limitations

Check [asdf](https://github.com/asdf-vm/asdf) readme for more instructions on how to
install & manage versions.
Currently [asdf](https://github.com/asdf-vm/asdf) supports plugin's git-ref on the default branch only (e.g. `main`). So it's not possible to use a git-ref that's not in the default branch (this limitation will be fixed by [asdf-vm/asdf/pull/1204](https://github.com/asdf-vm/asdf/pull/1204)).

# 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

Expand Down
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"
105 changes: 105 additions & 0 deletions cli/asdf-plugin-manager.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/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 list : List managed plugins according to .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
}

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
;;
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.
Loading

0 comments on commit 3f8a059

Please sign in to comment.