Skip to content

Commit

Permalink
Make it work end-to-end
Browse files Browse the repository at this point in the history
  • Loading branch information
sourishkrout committed Jul 30, 2024
1 parent e6860a0 commit 0646c78
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 4 deletions.
13 changes: 12 additions & 1 deletion internal/cmd/beta/beta_cmd.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package beta

import (
"fmt"

"github.com/spf13/cobra"
"github.com/spf13/pflag"

Expand All @@ -10,8 +12,10 @@ import (
)

type commonFlags struct {
silent bool
categories []string
filename string
subtle bool
}

func BetaCmd() *cobra.Command {
Expand All @@ -27,7 +31,7 @@ All commands are experimental and not yet ready for production use.
All commands use the runme.yaml configuration file.`,
Hidden: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return autoconfig.InvokeForCommand(func(cfg *config.Config) error {
err := autoconfig.InvokeForCommand(func(cfg *config.Config) error {
// Override the filename if provided.
if cFlags.filename != "" {
cfg.ProjectFilename = cFlags.filename
Expand All @@ -44,6 +48,10 @@ All commands use the runme.yaml configuration file.`,

return nil
})
if !cFlags.silent && err != nil {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%s\n", err)
}
return nil
},
}

Expand All @@ -54,6 +62,8 @@ All commands use the runme.yaml configuration file.`,
pFlags := cmd.PersistentFlags()
pFlags.StringVar(&cFlags.filename, "filename", "", "Name of the Markdown file to run blocks from.")
pFlags.StringSliceVar(&cFlags.categories, "category", nil, "Run blocks only from listed categories.")
pFlags.BoolVar(&cFlags.silent, "silent", false, "Silent mode. Do not error messages.")
pFlags.BoolVar(&cFlags.subtle, "subtle", false, "Explicitly allow delicate operations to prevent misuse")

// Hide all persistent flags from the root command.
// "beta" is a completely different set of commands and
Expand All @@ -73,6 +83,7 @@ All commands use the runme.yaml configuration file.`,
cmd.AddCommand(printCmd(cFlags))
cmd.AddCommand(server.Cmd())
cmd.AddCommand(runCmd(cFlags))
cmd.AddCommand(envCmd(cFlags))

return &cmd
}
118 changes: 118 additions & 0 deletions internal/cmd/beta/env_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package beta

import (
"fmt"
"os"
"strings"

"github.com/pkg/errors"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"

runmetls "github.com/stateful/runme/v3/internal/tls"
runnerv2 "github.com/stateful/runme/v3/pkg/api/gen/proto/go/runme/runner/v2alpha1"
)

func envCmd(cflags *commonFlags) *cobra.Command {
cmd := cobra.Command{
Use: "env",
Aliases: []string{"environment"},
Hidden: true,
Short: "Environment management",
Long: "Various commands to manage environments in runme",
}

cmd.AddCommand(envSourceCmd(cflags))

return &cmd
}

func envSourceCmd(cflags *commonFlags) *cobra.Command {
var (
serverAddr string
sessionID string
sessionStrategy string
tlsDir string
fExport bool
)

cmd := cobra.Command{
Use: "source",
Short: "Source environment variables from session",
Long: "Source environment variables from session",
RunE: func(cmd *cobra.Command, args []string) error {
if !cflags.subtle {
return errors.New("must be run in subtle mode to prevent misuse; enable by adding --subtle flag")
}

tlsConfig, err := runmetls.LoadClientConfigFromDir(tlsDir)
if err != nil {
return err
}

credentials := credentials.NewTLS(tlsConfig)
conn, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(credentials))
if err != nil {
return errors.Wrap(err, "failed to connect")
}
defer conn.Close()

client := runnerv2.NewRunnerServiceClient(conn)

// todo(sebastian): would it be better to require a specific session?
if strings.ToLower(sessionStrategy) == "recent" {
req := &runnerv2.ListSessionsRequest{}
resp, err := client.ListSessions(cmd.Context(), req)
if err != nil {
return err
}
l := len(resp.Sessions)
if l == 0 {
return errors.New("no sessions found")
}
// potentially unreliable
sessionID = resp.Sessions[l-1].Id
}

req := &runnerv2.GetSessionRequest{Id: sessionID}
resp, err := client.GetSession(cmd.Context(), req)
if err != nil {
return err
}

for _, kv := range resp.Session.Env {
parts := strings.Split(kv, "=")
if len(parts) < 2 {
return errors.Errorf("invalid key-value pair: %s", kv)
}

envVar := fmt.Sprintf("%s=%q", parts[0], strings.Join(parts[1:], "="))
if fExport {
envVar = fmt.Sprintf("export %s", envVar)
}

if _, err := fmt.Fprintf(cmd.OutOrStdout(), "%s\n", envVar); err != nil {
return err
}
}

return nil
},
}

cmd.Flags().StringVar(&serverAddr, "ServerAddress", os.Getenv("RUNME_SERVER_ADDR"), "The Server ServerAddress to connect to, i.e. 127.0.0.1:7865")
cmd.Flags().StringVar(&tlsDir, "TLSDir", os.Getenv("RUNME_TLS_DIR"), "Path to tls files")
cmd.Flags().StringVar(&sessionID, "session", os.Getenv("RUNME_SESSION"), "Session Id")
cmd.Flags().StringVar(&sessionStrategy, "session-strategy", func() string {
if val, ok := os.LookupEnv("RUNME_SESSION_STRATEGY"); ok {
return val
}

return "manual"
}(), "Strategy for session selection. Options are manual, recent. Defaults to manual")

cmd.Flags().BoolVarP(&fExport, "export", "", false, "export variables")

return &cmd
}
2 changes: 1 addition & 1 deletion internal/cmd/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func environmentDumpCmd() *cobra.Command {
Long: "Dumps all environment variables to stdout as a list of K=V separated by null terminators",
RunE: func(cmd *cobra.Command, args []string) error {
if !fInsecure {
return errors.New("must be run in insecure mode; enable by running with --insecure flag")
return errors.New("must be run in insecure mode to prevent misuse; enable by adding --insecure flag")
}

producer, err := newOSEnvironReader()
Expand Down
4 changes: 3 additions & 1 deletion internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var (
fRespectGitignore bool
fSkipRunnerFallback bool
fInsecure bool
fSubtle bool
fLogEnabled bool
fLogFilePath string
fExtensionHandle string
Expand Down Expand Up @@ -84,7 +85,8 @@ func Root() *cobra.Command {

pflags.StringVar(&fChdir, "chdir", getCwd(), "Switch to a different working directory before executing the command")
pflags.StringVar(&fFileName, "filename", "README.md", "Name of the README file")
pflags.BoolVar(&fInsecure, "insecure", false, "Run command in insecure-mode")
pflags.BoolVar(&fInsecure, "insecure", false, "Explicitly allow insecure operations to prevent misuse")
pflags.BoolVar(&fSubtle, "subtle", false, "Explicitly allow delicate operations to prevent misuse")

pflags.StringVar(&fProject, "project", "", "Root project to find runnable tasks")
pflags.BoolVar(&fRespectGitignore, "git-ignore", true, "Whether to respect .gitignore file(s) in project")
Expand Down
6 changes: 5 additions & 1 deletion internal/command/command_terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ func (c *terminalCommand) Start(ctx context.Context) (err error) {
}
}

if _, err := c.stdinWriter.Write([]byte(" eval $(runme beta env source --silent --subtle --export)\n clear\n")); err != nil {
return err
}

// todo(sebastian): good enough for prototype; it makes more sense to write this message at the TTY-level
initMsg := []byte(" clear\n # Runme: This terminal forked your session. " +
initMsg := []byte(" # Runme: This terminal forked your session. " +
"Upon exit exported environment variables will be rolled up into the session.\n\n")
_, err = c.stdinWriter.Write(initMsg)

Expand Down
3 changes: 3 additions & 0 deletions internal/runnerv2service/service_sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package runnerv2service
import (
"context"

"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

Expand Down Expand Up @@ -45,6 +46,8 @@ func (r *runnerService) CreateSession(ctx context.Context, req *runnerv2alpha1.C

r.sessions.Add(sess)

r.logger.Debug("created session", zap.String("id", sess.ID))

return &runnerv2alpha1.CreateSessionResponse{
Session: convertSessionToRunnerv2alpha1Session(sess),
}, nil
Expand Down

0 comments on commit 0646c78

Please sign in to comment.