diff --git a/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index c8906933809..9014822f741 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 00000000000..5178a749ff6 --- /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 88503617bff..219d7d3e9fa 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 72c4b73f4d3..41d36353a79 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 4a05d2a1b47..923f3faa376 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 dcd789d3de2..1497ca5d41a 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 bf78f4c967c..fe125bf08c0 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 e3823d2da53..c0852a2237f 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 bd6516ae583..c4c0cf50617 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 4fb32ea84c0..3e31967e10c 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 b2bb8dd44d9..ce1460496f6 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 00000000000..ea475737bb1 --- /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 cefabbe2893..8ba0d386600 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 2f970474ddc..d46b2b2d98f 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 b20c655b325..9bb6ef84071 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 5bcddeee072..5634f4f28e6 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 3a220e1a5f2..05e19a65780 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 0fb6f07b26a..adb6225c027 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 8e6cdbc1cf8..738e2f99b8b 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 6d35ea2b1c6..68eeb098e46 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 91e9cab4a3d..0c64d4a28f7 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 1d5872b41a8..71f0a9d6138 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 ed4ecaba07b..2d00b87b40c 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 256532c12bd..8568bd764f5 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 70be5e16fe9..7dedc62b58a 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