diff --git a/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index c89069338..9014822f7 100644 --- a/docs/development/plugin-triggers.md +++ b/docs/development/plugin-triggers.md @@ -2367,3 +2367,44 @@ shift 2 [[ "$SSH_NAME" == "default" && $1 == plugin:* ]] && exit 1 exit 0 ``` + +### `user-auth-app` + +This is a special plugin trigger that is executed when listing apps or checking if an app exists. All Dokku commands should check if an app exists at least once before interacting with them so as not to circumvent the check. + +Note that the trigger should exit `0`, and each non-empty line on stdout is captured as a valid app name. + +The `SSH_USER` is the original ssh user. If you are running remote commands, this user will typically be `dokku`, and as such should not be trusted when checking permissions. If you are connected via ssh as a different user who then invokes `dokku`, the value of this variable will be that user's name (`root`, `myuser`, etc.). + +The `SSH_NAME` is the `NAME` variable set via the `sshcommand acl-add` command. For reference, the following command can be run as the root user to specify a specific `NAME` for a given ssh key: + +```shell +sshcommand acl-add dokku NAME < $PATH_TO_SSH_KEY +``` + +Note that the `NAME` value is set at the first ssh key match. If an ssh key is set in the `/home/dokku/.ssh/authorized_keys` multiple times, the first match will decide the value. + +- Description: Allows you to deny access to a Dokku app by either ssh user or associated ssh-command NAME user. +- Invoked by: `dokku` +- Arguments: `$SSH_USER $SSH_NAME $DOKKU_COMMAND` +- Example: + +```shell +#!/usr/bin/env bash +# hide any apps with the prefix "admin" +# if the logged in user (SSH_USER) or SSH_NAME is not `root` + +main() { + declare SSH_USER="$1" SSH_NAME="$2" ARGS=("${@:3}") + + for arg in "${ARGS[@]}"; do + if [[ "$arg" == admin-* ]] && [[ "$SSH_USER" != "root" ]] && [[ "$SSH_NAME" != "root" ]]; then + continue + fi + + echo "${arg}" + done +} + +main "$@" +``` diff --git a/plugins/20_events/user-auth-app b/plugins/20_events/user-auth-app new file mode 120000 index 000000000..5178a749f --- /dev/null +++ b/plugins/20_events/user-auth-app @@ -0,0 +1 @@ +hook \ No newline at end of file diff --git a/plugins/builder-dockerfile/internal-functions b/plugins/builder-dockerfile/internal-functions index 88503617b..219d7d3e9 100755 --- a/plugins/builder-dockerfile/internal-functions +++ b/plugins/builder-dockerfile/internal-functions @@ -9,7 +9,6 @@ cmd-builder-dockerfile-report() { declare cmd="builder-dockerfile:report" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" INFO_FLAG="$2" - local INSTALLED_APPS=$(dokku_apps) if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" @@ -21,7 +20,7 @@ cmd-builder-dockerfile-report() { fi if [[ -z "$APP" ]]; then - for app in $INSTALLED_APPS; do + for app in $(dokku_apps); do cmd-builder-dockerfile-report-single "$app" "$INFO_FLAG" | tee || true done else diff --git a/plugins/builder-pack/internal-functions b/plugins/builder-pack/internal-functions index 72c4b73f4..41d36353a 100755 --- a/plugins/builder-pack/internal-functions +++ b/plugins/builder-pack/internal-functions @@ -9,7 +9,6 @@ cmd-builder-pack-report() { declare cmd="builder-pack:report" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" INFO_FLAG="$2" - local INSTALLED_APPS=$(dokku_apps) if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" @@ -21,7 +20,7 @@ cmd-builder-pack-report() { fi if [[ -z "$APP" ]]; then - for app in $INSTALLED_APPS; do + for app in $(dokku_apps); do cmd-builder-pack-report-single "$app" "$INFO_FLAG" | tee || true done else diff --git a/plugins/certs/internal-functions b/plugins/certs/internal-functions index 4a05d2a1b..923f3faa3 100755 --- a/plugins/certs/internal-functions +++ b/plugins/certs/internal-functions @@ -9,7 +9,6 @@ cmd-certs-report() { declare cmd="certs:report" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" INFO_FLAG="$2" - local INSTALLED_APPS=$(dokku_apps) if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" @@ -21,7 +20,7 @@ cmd-certs-report() { fi if [[ -z "$APP" ]]; then - for app in $INSTALLED_APPS; do + for app in $(dokku_apps); do cmd-certs-report-single "$app" "$INFO_FLAG" | tee || true done else diff --git a/plugins/checks/install b/plugins/checks/install index dcd789d3d..1497ca5d4 100755 --- a/plugins/checks/install +++ b/plugins/checks/install @@ -6,13 +6,10 @@ source "$PLUGIN_AVAILABLE_PATH/config/functions" migrate_checks_vars_0_5_0() { declare desc="migrates deprecated CHECKS config variables to simplified counter part introduced in 0.5.x" - local APPS="$(dokku_apps)" local GLOBAL_SKIP_ALL_CHECKS=$(config_get --global DOKKU_SKIP_ALL_CHECKS || true) local GLOBAL_SKIP_DEFAULT_CHECKS=$(config_get --global DOKKU_SKIP_DEFAULT_CHECKS || true) - local app - - for app in $APPS; do + for app in $(dokku_apps); do local APP_SKIP_ALL_CHECKS=$(config_get "$app" DOKKU_SKIP_ALL_CHECKS || true) local APP_SKIP_DEFAULT_CHECKS=$(config_get "$app" DOKKU_SKIP_DEFAULT_CHECKS || true) @@ -37,11 +34,8 @@ migrate_checks_vars_0_5_0() { migrate_checks_vars_0_6_0() { declare desc="migrates CHECKS config variables from 0.5.x to support fully-disabled zero-downtime checks" - local APPS="$(dokku_apps)" - local app - - for app in $APPS; do + for app in $(dokku_apps); do local APP_DOKKU_CHECKS_ENABLED=$(config_get "$app" DOKKU_CHECKS_ENABLED || true) if [[ $APP_DOKKU_CHECKS_ENABLED ]]; then dokku_log_info1 "Migrating zero downtime env variables to 0.6.x. The following variables will be migrated" diff --git a/plugins/checks/internal-functions b/plugins/checks/internal-functions index bf78f4c96..fe125bf08 100755 --- a/plugins/checks/internal-functions +++ b/plugins/checks/internal-functions @@ -9,7 +9,6 @@ cmd-checks-report() { declare cmd="checks:report" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" INFO_FLAG="$2" - local INSTALLED_APPS=$(dokku_apps) if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" @@ -21,7 +20,7 @@ cmd-checks-report() { fi if [[ -z "$APP" ]]; then - for app in $INSTALLED_APPS; do + for app in $(dokku_apps); do cmd-checks-report-single "$app" "$INFO_FLAG" | tee || true done else diff --git a/plugins/common/Makefile b/plugins/common/Makefile index e3823d2da..c0852a223 100644 --- a/plugins/common/Makefile +++ b/plugins/common/Makefile @@ -1,4 +1,4 @@ -TRIGGERS = triggers/core-post-deploy triggers/install triggers/post-delete +TRIGGERS = triggers/app-list triggers/core-post-deploy triggers/install triggers/post-delete BUILD = prop common triggers PLUGIN_NAME = common diff --git a/plugins/common/common.go b/plugins/common/common.go index bd6516ae5..c4c0cf506 100644 --- a/plugins/common/common.go +++ b/plugins/common/common.go @@ -244,12 +244,12 @@ func GetRunningImageTag(appName string, imageTag string) (string, error) { } // DokkuApps returns a list of all local apps -func DokkuApps() (apps []string, err error) { +func DokkuApps() ([]string, error) { + apps := []string{} dokkuRoot := MustGetEnv("DOKKU_ROOT") files, err := ioutil.ReadDir(dokkuRoot) if err != nil { - err = fmt.Errorf("You haven't deployed any applications yet") - return + return apps, fmt.Errorf("You haven't deployed any applications yet") } for _, f := range files { @@ -264,11 +264,10 @@ func DokkuApps() (apps []string, err error) { } if len(apps) == 0 { - err = fmt.Errorf("You haven't deployed any applications yet") - return + return apps, fmt.Errorf("You haven't deployed any applications yet") } - return + return filterApps(apps) } // GetAppImageName returns image identifier for a given app, tag tuple. validate if tag is presented diff --git a/plugins/common/common_test.go b/plugins/common/common_test.go index 4fb32ea84..3e31967e1 100644 --- a/plugins/common/common_test.go +++ b/plugins/common/common_test.go @@ -87,6 +87,7 @@ func TestCommonDokkuAppsError(t *testing.T) { func TestCommonDokkuApps(t *testing.T) { RegisterTestingT(t) + os.Setenv("PLUGIN_ENABLED_PATH", "/var/lib/dokku/plugins/enabled") Expect(setupTestApp()).To(Succeed()) apps, err := DokkuApps() Expect(err).NotTo(HaveOccurred()) diff --git a/plugins/common/functions b/plugins/common/functions index b2bb8dd44..ce1460496 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -17,8 +17,11 @@ has_tty() { dokku_apps() { declare desc="prints list of all local apps" - local INSTALLED_APPS=$(find "$DOKKU_ROOT" -follow -maxdepth 1 -mindepth 1 -type d ! -name '.*' -printf "%f\n" 2>/dev/null | sort) || (dokku_log_fail "You haven't deployed any applications yet") - [[ $INSTALLED_APPS ]] && echo "$INSTALLED_APPS" + local INSTALLED_APPS="$(plugn trigger app-list)" + if [[ -z "$INSTALLED_APPS" ]]; then + dokku_log_fail "You haven't deployed any applications yet" + fi + echo "$INSTALLED_APPS" } dokku_version() { diff --git a/plugins/common/functions.go b/plugins/common/functions.go new file mode 100644 index 000000000..ea475737b --- /dev/null +++ b/plugins/common/functions.go @@ -0,0 +1,44 @@ +package common + +import ( + "fmt" + "os" + "strings" +) + +func filterApps(apps []string) ([]string, error) { + if !PlugnTriggerExists("user-auth-app") { + return apps, nil + } + + sshUser := os.Getenv("SSH_USER") + if sshUser == "" { + sshUser = os.Getenv("USER") + } + + sshName := os.Getenv("SSH_NAME") + if sshName == "" { + sshName = "default" + } + + args := append([]string{sshUser, sshName}, apps...) + b, _ := PlugnTriggerOutput("user-auth-app", args...) + filteredApps := strings.Split(strings.TrimSpace(string(b[:])), "\n") + filteredApps = removeEmptyEntries(filteredApps) + + if len(filteredApps) == 0 { + return filteredApps, fmt.Errorf("You haven't deployed any applications yet") + } + + return filteredApps, nil +} + +func removeEmptyEntries(s []string) []string { + var r []string + for _, str := range s { + if str != "" { + r = append(r, str) + } + } + return r +} diff --git a/plugins/common/src/triggers/triggers.go b/plugins/common/src/triggers/triggers.go index cefabbe28..8ba0d3866 100644 --- a/plugins/common/src/triggers/triggers.go +++ b/plugins/common/src/triggers/triggers.go @@ -17,6 +17,8 @@ func main() { var err error switch trigger { + case "app-list": + err = common.TriggerAppList() case "core-post-deploy": appName := flag.Arg(0) err = common.TriggerCorePostDeploy(appName) diff --git a/plugins/common/subprocess.go b/plugins/common/subprocess.go index 2f970474d..d46b2b2d9 100644 --- a/plugins/common/subprocess.go +++ b/plugins/common/subprocess.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "os/exec" + "path/filepath" "strings" "github.com/codeskyblue/go-sh" @@ -128,3 +129,19 @@ func PlugnTriggerSetup(triggerName string, args ...string) *sh.Session { } return sh.Command("plugn", shellArgs...) } + +// PlugnTriggerExists returns whether a plugin trigger exists (ignoring the existence of any within the 20_events plugin) +func PlugnTriggerExists(triggerName string) bool { + pluginPath := MustGetEnv("PLUGIN_ENABLED_PATH") + glob := filepath.Join(pluginPath, "*", triggerName) + exists := false + files, _ := filepath.Glob(glob) + for _, file := range files { + plugin := strings.Trim(strings.TrimPrefix(strings.TrimSuffix(file, "/"+triggerName), pluginPath), "/") + if plugin != "20_events" { + exists = true + break + } + } + return exists +} diff --git a/plugins/common/triggers.go b/plugins/common/triggers.go index b20c655b3..9bb6ef840 100644 --- a/plugins/common/triggers.go +++ b/plugins/common/triggers.go @@ -5,6 +5,16 @@ import ( "os" ) +// TriggerAppList outputs each app name to stdout on a newline +func TriggerAppList() error { + apps, _ := DokkuApps() + for _, app := range apps { + Log(app) + } + + return nil +} + // TriggerCorePostDeploy associates the container with a specified network func TriggerCorePostDeploy(appName string) error { quiet := os.Getenv("DOKKU_QUIET_OUTPUT") diff --git a/plugins/docker-options/internal-functions b/plugins/docker-options/internal-functions index 5bcddeee0..5634f4f28 100755 --- a/plugins/docker-options/internal-functions +++ b/plugins/docker-options/internal-functions @@ -9,7 +9,6 @@ cmd-docker-options-report() { declare cmd="docker-options:report" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" INFO_FLAG="$2" - local INSTALLED_APPS=$(dokku_apps) if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" @@ -21,7 +20,7 @@ cmd-docker-options-report() { fi if [[ -z "$APP" ]]; then - for app in $INSTALLED_APPS; do + for app in $(dokku_apps); do cmd-docker-options-report-single "$app" "$INFO_FLAG" | tee || true done else diff --git a/plugins/domains/install b/plugins/domains/install index 3a220e1a5..05e19a657 100755 --- a/plugins/domains/install +++ b/plugins/domains/install @@ -8,9 +8,8 @@ trigger-domains-install() { declare trigger="install" shopt -s nullglob - for app in $DOKKU_ROOT/*/CONTAINER; do - APP=$(basename "$(dirname "$app")") - domains_setup "$APP" + for app in $(dokku_apps); do + domains_setup "$app" done } diff --git a/plugins/domains/internal-functions b/plugins/domains/internal-functions index 0fb6f07b2..adb6225c0 100755 --- a/plugins/domains/internal-functions +++ b/plugins/domains/internal-functions @@ -9,7 +9,6 @@ cmd-domains-report() { declare cmd="domains:report" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" INFO_FLAG="$2" - local INSTALLED_APPS=$(dokku_apps) if [[ "$APP" == "--global" ]]; then cmd-domains-report-single "$APP" "$INFO_FLAG" @@ -26,7 +25,7 @@ cmd-domains-report() { fi if [[ -z "$APP" ]]; then - for app in $INSTALLED_APPS; do + for app in $(dokku_apps); do cmd-domains-report-single "$app" "$INFO_FLAG" | tee || true done else diff --git a/plugins/git/install b/plugins/git/install index 8e6cdbc1c..738e2f99b 100755 --- a/plugins/git/install +++ b/plugins/git/install @@ -18,7 +18,6 @@ trigger-git-install() { migrate_git_vars_0_12_0() { declare desc="migrates git config variables from 0.11.x" - local APPS="$(dokku_apps)" local DOKKU_DEPLOY_BRANCH app DOKKU_DEPLOY_BRANCH=$(config_get --global DOKKU_DEPLOY_BRANCH || true) @@ -27,7 +26,7 @@ migrate_git_vars_0_12_0() { DOKKU_QUIET_OUTPUT=1 config_unset --global DOKKU_DEPLOY_BRANCH || true fi - for app in $APPS; do + for app in $(dokku_apps); do DOKKU_DEPLOY_BRANCH=$(config_get "$app" DOKKU_DEPLOY_BRANCH || true) if [[ -n "$DOKKU_DEPLOY_BRANCH" ]]; then fn-plugin-property-write "git" "$app" "deploy-branch" "$DOKKU_DEPLOY_BRANCH" diff --git a/plugins/git/internal-functions b/plugins/git/internal-functions index 6d35ea2b1..68eeb098e 100755 --- a/plugins/git/internal-functions +++ b/plugins/git/internal-functions @@ -222,7 +222,6 @@ cmd-git-report() { declare cmd="git:report" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" INFO_FLAG="$2" - local INSTALLED_APPS=$(dokku_apps) if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" @@ -234,7 +233,7 @@ cmd-git-report() { fi if [[ -z "$APP" ]]; then - for app in $INSTALLED_APPS; do + for app in $(dokku_apps); do cmd-git-report-single "$app" "$INFO_FLAG" | tee || true done else diff --git a/plugins/logs/go.mod b/plugins/logs/go.mod index 91e9cab4a..0c64d4a28 100644 --- a/plugins/logs/go.mod +++ b/plugins/logs/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 - github.com/dokku/dokku/plugins/docker-options v0.0.0-20210208020425-f7beb3d95ddd + github.com/dokku/dokku/plugins/docker-options v0.0.0-00010101000000-000000000000 github.com/joncalhoun/qson v0.0.0-20200422171543-84433dcd3da0 github.com/spf13/pflag v1.0.5 ) diff --git a/plugins/nginx-vhosts/command-functions b/plugins/nginx-vhosts/command-functions index 1d5872b41..71f0a9d61 100755 --- a/plugins/nginx-vhosts/command-functions +++ b/plugins/nginx-vhosts/command-functions @@ -11,7 +11,6 @@ cmd-nginx-report() { declare cmd="nginx:report" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" INFO_FLAG="$2" - local INSTALLED_APPS=$(dokku_apps) if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" @@ -23,7 +22,7 @@ cmd-nginx-report() { fi if [[ -z "$APP" ]]; then - for app in $INSTALLED_APPS; do + for app in $(dokku_apps); do cmd-nginx-report-single "$app" "$INFO_FLAG" | tee || true done else diff --git a/plugins/ps/subcommands.go b/plugins/ps/subcommands.go index ed4ecaba0..2d00b87b4 100644 --- a/plugins/ps/subcommands.go +++ b/plugins/ps/subcommands.go @@ -6,9 +6,8 @@ import ( "path/filepath" "strings" - dockeroptions "github.com/dokku/dokku/plugins/docker-options" - "github.com/dokku/dokku/plugins/common" + dockeroptions "github.com/dokku/dokku/plugins/docker-options" "github.com/gofrs/flock" ) diff --git a/plugins/scheduler-docker-local/internal-functions b/plugins/scheduler-docker-local/internal-functions index 256532c12..8568bd764 100755 --- a/plugins/scheduler-docker-local/internal-functions +++ b/plugins/scheduler-docker-local/internal-functions @@ -10,7 +10,6 @@ cmd-scheduler-docker-local-report() { declare cmd="scheduler-docker-local:report" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" INFO_FLAG="$2" - local INSTALLED_APPS=$(dokku_apps) if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" @@ -22,7 +21,7 @@ cmd-scheduler-docker-local-report() { fi if [[ -z "$APP" ]]; then - for app in $INSTALLED_APPS; do + for app in $(dokku_apps); do cmd-scheduler-docker-local-report-single "$app" "$INFO_FLAG" | tee || true done else diff --git a/plugins/storage/internal-functions b/plugins/storage/internal-functions index 70be5e16f..7dedc62b5 100755 --- a/plugins/storage/internal-functions +++ b/plugins/storage/internal-functions @@ -66,7 +66,6 @@ cmd-storage-report() { declare cmd="storage:report" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" INFO_FLAG="$2" - local INSTALLED_APPS=$(dokku_apps) if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then INFO_FLAG="$APP" @@ -78,7 +77,7 @@ cmd-storage-report() { fi if [[ -z "$APP" ]]; then - for app in $INSTALLED_APPS; do + for app in $(dokku_apps); do cmd-storage-report-single "$app" "$INFO_FLAG" | tee || true done else