diff --git a/.github/workflows/homebrew.yml b/.github/workflows/homebrew.yml index fee97d74..87817243 100644 --- a/.github/workflows/homebrew.yml +++ b/.github/workflows/homebrew.yml @@ -12,10 +12,10 @@ jobs: id: extract-version run: | printf "::set-output name=%s::%s\n" tag-name "${GITHUB_REF#refs/tags/}" - - uses: mislav/bump-homebrew-formula-action@v2 + - uses: mislav/bump-homebrew-formula-action@v3.1 if: "!contains(github.ref, '-')" with: formula-name: zrok - download-url: https://github.com/openziti/zrok/archive/${{ steps.extract-version.outputs.tag-name }}.tar.gz + download-url: https://github.com/openziti/zrok/archive/refs/tags/${{ steps.extract-version.outputs.tag-name }}.tar.gz env: COMMITTER_TOKEN: ${{ secrets.BREW_COMMITTER_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a972b91..192e3ee0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,21 @@ -# v0.4.11 +# v0.4.14 FEATURE: `zrok` Drives "Phase 1" (`p1`) functionality included in this release. This includes new `--backend-mode drive`, which accepts a folder path as a target. A `drive` share can be mounted as a network drive on Windows, macOS, and Linux, allowing full read/write access from all applications on those systems (https://github.com/openziti/zrok/issues/218) Subsequent releases will address CLI use cases and provide further refinements to the overall approach. +# v0.4.13 + +FIX: Update to Homebrew automation to properly integrate with the latest version of the Homebrew release process. + +# v0.4.12 + +FIX: The `zrok reserve` command was not properly recording the reserved share status of the shares that it created, preventing the `zrok release` command from properly releasing them (https://github.com/openziti/zrok/issues/427) If a user encounters reserved shares that cannot be released with the `zrok release` command, they can be deleted through the web console. + +# v0.4.11 + +FEATURE: The `zrok reserve` command now incorporates the `--json-output|-j` flag, which outputs the reservation details as JSON, rather than as human-consumable log messages. Other commands will produce similar output in the future (https://github.com/openziti/zrok/issues/422) + +FIX: Include `--oauth-provider` and associated flags for the `zrok reserve` command, allowing reserved shares to specify OAuth authentication (https://github.com/openziti/zrok/issues/421) + # v0.4.10 CHANGE: The public frontend configuration has been bumped from `v: 2` to `v: 3`. The `redirect_host`, `redirect_port` and `redirect_http_only` parameters have been removed. These three configuration options have been replaced with `bind_address`, `redirect_url` and `cookie_domain`. See the OAuth configuration guide at `docs/guides/self-hosting/oauth/configuring-oauth.md` for more details (https://github.com/openziti/zrok/issues/411) diff --git a/cmd/zrok/reserve.go b/cmd/zrok/reserve.go index a5f0173c..b6be848d 100644 --- a/cmd/zrok/reserve.go +++ b/cmd/zrok/reserve.go @@ -1,12 +1,14 @@ package main import ( + "encoding/json" "fmt" "github.com/openziti/zrok/environment" "github.com/openziti/zrok/sdk" "github.com/openziti/zrok/tui" "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "time" ) func init() { @@ -14,10 +16,14 @@ func init() { } type reserveCommand struct { - basicAuth []string - frontendSelection []string - backendMode string - cmd *cobra.Command + basicAuth []string + frontendSelection []string + backendMode string + jsonOutput bool + oauthProvider string + oauthEmailDomains []string + oauthCheckInterval time.Duration + cmd *cobra.Command } func newReserveCommand() *reserveCommand { @@ -27,9 +33,15 @@ func newReserveCommand() *reserveCommand { Args: cobra.ExactArgs(2), } command := &reserveCommand{cmd: cmd} - cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (,...)") cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share") cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, , caddy}") + cmd.Flags().BoolVarP(&command.jsonOutput, "json-output", "j", false, "Emit JSON describing the created reserved share") + cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (,...)") + cmd.Flags().StringVar(&command.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]") + cmd.Flags().StringArrayVar(&command.oauthEmailDomains, "oauth-email-domains", []string{}, "Allow only these email domains to authenticate via OAuth") + cmd.Flags().DurationVar(&command.oauthCheckInterval, "oauth-check-interval", 3*time.Hour, "Maximum lifetime for OAuth authentication; reauthenticate after expiry") + cmd.MarkFlagsMutuallyExclusive("basic-auth", "oauth-provider") + cmd.Run = command.run return command } @@ -45,10 +57,7 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { case "proxy": v, err := parseUrl(args[1]) if err != nil { - if !panicInstead { - tui.Error("invalid target endpoint URL", err) - } - panic(err) + tui.Error("invalid target endpoint URL", err) } target = v @@ -70,10 +79,7 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { env, err := environment.LoadRoot() if err != nil { - if !panicInstead { - tui.Error("error loading environment", err) - } - panic(err) + tui.Error("error loading environment", err) } if !env.IsEnabled() { @@ -81,6 +87,7 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { } req := &sdk.ShareRequest{ + Reserved: true, BackendMode: sdk.BackendMode(cmd.backendMode), ShareMode: shareMode, BasicAuth: cmd.basicAuth, @@ -89,16 +96,29 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) { if shareMode == sdk.PublicShareMode { req.Frontends = cmd.frontendSelection } + if cmd.oauthProvider != "" { + if shareMode != sdk.PublicShareMode { + tui.Error("--oauth-provider only supported for public shares", nil) + } + req.OauthProvider = cmd.oauthProvider + req.OauthEmailDomains = cmd.oauthEmailDomains + req.OauthAuthorizationCheckInterval = cmd.oauthCheckInterval + } shr, err := sdk.CreateShare(env, req) if err != nil { - if !panicInstead { - tui.Error("unable to create share", err) - } - panic(err) + tui.Error("unable to create share", err) } - logrus.Infof("your reserved share token is '%v'", shr.Token) - for _, fpe := range shr.FrontendEndpoints { - logrus.Infof("reserved frontend endpoint: %v", fpe) + if !cmd.jsonOutput { + logrus.Infof("your reserved share token is '%v'", shr.Token) + for _, fpe := range shr.FrontendEndpoints { + logrus.Infof("reserved frontend endpoint: %v", fpe) + } + } else { + out, err := json.Marshal(shr) + if err != nil { + tui.Error("error emitting JSON", err) + } + fmt.Println(string(out)) } } diff --git a/docker/images/zrok/Dockerfile b/docker/images/zrok/Dockerfile index f9ff31fb..161b2df3 100644 --- a/docker/images/zrok/Dockerfile +++ b/docker/images/zrok/Dockerfile @@ -1,7 +1,8 @@ # this builds docker.io/openziti/zrok -FROM docker.io/openziti/ziti-cli:0.27.9 -# This build stage grabs artifacts that are copied into the final image. -# It uses the same base as the final image to maximize docker cache hits. +ARG ZITI_CLI_TAG="0.30.5" +ARG ZITI_CLI_IMAGE="docker.io/openziti/ziti-cli" +# this builds docker.io/openziti/ziti-controller +FROM ${ZITI_CLI_IMAGE}:${ZITI_CLI_TAG} ARG ARTIFACTS_DIR=./dist ARG DOCKER_BUILD_DIR=. @@ -19,6 +20,11 @@ LABEL name="openziti/zrok" \ USER root +### install packages (jq introduced in source image in next release 0.30.6) +RUN INSTALL_PKGS="jq" && \ + microdnf -y update --setopt=install_weak_deps=0 --setopt=tsflags=nodocs && \ + microdnf -y install --setopt=install_weak_deps=0 --setopt=tsflags=nodocs ${INSTALL_PKGS} + ### add licenses to this directory RUN mkdir -p -m0755 /licenses COPY ./LICENSE /licenses/apache.txt diff --git a/sdk/model.go b/sdk/model.go index 4592a483..4eed621b 100644 --- a/sdk/model.go +++ b/sdk/model.go @@ -21,6 +21,7 @@ const ( ) type ShareRequest struct { + Reserved bool BackendMode BackendMode ShareMode ShareMode Target string @@ -32,8 +33,8 @@ type ShareRequest struct { } type Share struct { - Token string - FrontendEndpoints []string + Token string `json:"token"` + FrontendEndpoints []string `json:"frontend_endpoints"` } type AccessRequest struct { diff --git a/sdk/share.go b/sdk/share.go index 9a1838b8..45feb57f 100644 --- a/sdk/share.go +++ b/sdk/share.go @@ -25,6 +25,7 @@ func CreateShare(root env_core.Root, request *ShareRequest) (*Share, error) { default: return nil, errors.Errorf("unknown share mode '%v'", request.ShareMode) } + out.Body.Reserved = request.Reserved if len(request.BasicAuth) > 0 { out.Body.AuthScheme = string(Basic)