Monorepo for Tangled tangled.org

guard: supress logging #745

closed opened by oppi.li targeting master from push-ykxtvrlpxwrl

the default slog logger caused indigo/identity to emit logs when resolving identities. using a bespoke logger in the guard subcommand fixes this.

Signed-off-by: oppiliappan me@oppi.li

Labels

None yet.

assignee

None yet.

Participants 2
AT URI
at://did:plc:qfpnj4og54vl56wngdriaxug/sh.tangled.repo.pull/3m4qbkdfovt22
+26 -29
Diff #0
+26 -29
guard/guard.go
··· 16 securejoin "github.com/cyphar/filepath-securejoin" 17 "github.com/urfave/cli/v3" 18 "tangled.org/core/idresolver" 19 - "tangled.org/core/log" 20 ) 21 22 func Command() *cli.Command { ··· 55 } 56 57 func Run(ctx context.Context, cmd *cli.Command) error { 58 - l := log.FromContext(ctx) 59 - 60 incomingUser := cmd.String("user") 61 gitDir := cmd.String("git-dir") 62 logPath := cmd.String("log-path") 63 endpoint := cmd.String("internal-api") 64 motdFile := cmd.String("motd-file") 65 66 logFile, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 67 - if err != nil { 68 - l.Error("failed to open log file", "error", err) 69 - return err 70 - } else { 71 - fileHandler := slog.NewJSONHandler(logFile, &slog.HandlerOptions{Level: slog.LevelInfo}) 72 - l = slog.New(fileHandler) 73 } 74 75 var clientIP string 76 if connInfo := os.Getenv("SSH_CONNECTION"); connInfo != "" { 77 parts := strings.Fields(connInfo) ··· 81 } 82 83 if incomingUser == "" { 84 - l.Error("access denied: no user specified") 85 fmt.Fprintln(os.Stderr, "access denied: no user specified") 86 os.Exit(-1) 87 } 88 89 sshCommand := os.Getenv("SSH_ORIGINAL_COMMAND") 90 91 - l.Info("connection attempt", 92 "user", incomingUser, 93 "command", sshCommand, 94 "client", clientIP) 95 96 if sshCommand == "" { 97 - l.Info("access denied: no interactive shells", "user", incomingUser) 98 fmt.Fprintf(os.Stderr, "Hi @%s! You've successfully authenticated.\n", incomingUser) 99 os.Exit(-1) 100 } 101 102 cmdParts := strings.Fields(sshCommand) 103 if len(cmdParts) < 2 { 104 - l.Error("invalid command format", "command", sshCommand) 105 fmt.Fprintln(os.Stderr, "invalid command format") 106 os.Exit(-1) 107 } ··· 113 // any of the above with a leading slash (/) 114 115 components := strings.Split(strings.TrimPrefix(strings.Trim(cmdParts[1], "'"), "/"), "/") 116 - l.Info("command components", "components", components) 117 118 if len(components) != 2 { 119 - l.Error("invalid repo format", "components", components) 120 fmt.Fprintln(os.Stderr, "invalid repo format, needs <user>/<repo> or /<user>/<repo>") 121 os.Exit(-1) 122 } 123 124 didOrHandle := components[0] 125 - identity := resolveIdentity(ctx, l, didOrHandle) 126 did := identity.DID.String() 127 repoName := components[1] 128 qualifiedRepoName, _ := securejoin.SecureJoin(did, repoName) ··· 133 "git-upload-archive": true, 134 } 135 if !validCommands[gitCommand] { 136 - l.Error("access denied: invalid git command", "command", gitCommand) 137 fmt.Fprintln(os.Stderr, "access denied: invalid git command") 138 return fmt.Errorf("access denied: invalid git command") 139 } 140 141 if gitCommand != "git-upload-pack" { 142 - if !isPushPermitted(l, incomingUser, qualifiedRepoName, endpoint) { 143 - l.Error("access denied: user not allowed", 144 "did", incomingUser, 145 "reponame", qualifiedRepoName) 146 fmt.Fprintln(os.Stderr, "access denied: user not allowed") ··· 150 151 fullPath, _ := securejoin.SecureJoin(gitDir, qualifiedRepoName) 152 153 - l.Info("processing command", 154 "user", incomingUser, 155 "command", gitCommand, 156 "repo", repoName, ··· 160 var motdReader io.Reader 161 if reader, err := os.Open(motdFile); err != nil { 162 if !errors.Is(err, os.ErrNotExist) { 163 - l.Error("failed to read motd file", "error", err) 164 } 165 motdReader = strings.NewReader("Welcome to this knot!\n") 166 } else { ··· 181 ) 182 183 if err := gitCmd.Run(); err != nil { 184 - l.Error("command failed", "error", err) 185 fmt.Fprintf(os.Stderr, "command failed: %v\n", err) 186 return fmt.Errorf("command failed: %v", err) 187 } 188 189 - l.Info("command completed", 190 "user", incomingUser, 191 "command", gitCommand, 192 "repo", repoName, ··· 195 return nil 196 } 197 198 - func resolveIdentity(ctx context.Context, l *slog.Logger, didOrHandle string) *identity.Identity { 199 resolver := idresolver.DefaultResolver() 200 ident, err := resolver.ResolveIdent(ctx, didOrHandle) 201 if err != nil { 202 - l.Error("Error resolving handle", "error", err, "handle", didOrHandle) 203 fmt.Fprintf(os.Stderr, "error resolving handle: %v\n", err) 204 os.Exit(1) 205 } 206 if ident.Handle.IsInvalidHandle() { 207 - l.Error("Error resolving handle", "invalid handle", didOrHandle) 208 fmt.Fprintf(os.Stderr, "error resolving handle: invalid handle\n") 209 os.Exit(1) 210 } 211 return ident 212 } 213 214 - func isPushPermitted(l *slog.Logger, user, qualifiedRepoName, endpoint string) bool { 215 u, _ := url.Parse(endpoint + "/push-allowed") 216 q := u.Query() 217 q.Add("user", user) ··· 220 221 req, err := http.Get(u.String()) 222 if err != nil { 223 - l.Error("Error verifying permissions", "error", err) 224 fmt.Fprintf(os.Stderr, "error verifying permissions: %v\n", err) 225 os.Exit(1) 226 } 227 228 - l.Info("Checking push permission", 229 "url", u.String(), 230 "status", req.Status) 231
··· 16 securejoin "github.com/cyphar/filepath-securejoin" 17 "github.com/urfave/cli/v3" 18 "tangled.org/core/idresolver" 19 ) 20 21 func Command() *cli.Command { ··· 54 } 55 56 func Run(ctx context.Context, cmd *cli.Command) error { 57 incomingUser := cmd.String("user") 58 gitDir := cmd.String("git-dir") 59 logPath := cmd.String("log-path") 60 endpoint := cmd.String("internal-api") 61 motdFile := cmd.String("motd-file") 62 63 + stream := io.Discard 64 logFile, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 65 + if err == nil { 66 + stream = logFile 67 } 68 69 + fileHandler := slog.NewJSONHandler(stream, &slog.HandlerOptions{Level: slog.LevelInfo}) 70 + slog.SetDefault(slog.New(fileHandler)) 71 + 72 var clientIP string 73 if connInfo := os.Getenv("SSH_CONNECTION"); connInfo != "" { 74 parts := strings.Fields(connInfo) ··· 78 } 79 80 if incomingUser == "" { 81 + slog.Error("access denied: no user specified") 82 fmt.Fprintln(os.Stderr, "access denied: no user specified") 83 os.Exit(-1) 84 } 85 86 sshCommand := os.Getenv("SSH_ORIGINAL_COMMAND") 87 88 + slog.Info("connection attempt", 89 "user", incomingUser, 90 "command", sshCommand, 91 "client", clientIP) 92 93 if sshCommand == "" { 94 + slog.Info("access denied: no interactive shells", "user", incomingUser) 95 fmt.Fprintf(os.Stderr, "Hi @%s! You've successfully authenticated.\n", incomingUser) 96 os.Exit(-1) 97 } 98 99 cmdParts := strings.Fields(sshCommand) 100 if len(cmdParts) < 2 { 101 + slog.Error("invalid command format", "command", sshCommand) 102 fmt.Fprintln(os.Stderr, "invalid command format") 103 os.Exit(-1) 104 } ··· 110 // any of the above with a leading slash (/) 111 112 components := strings.Split(strings.TrimPrefix(strings.Trim(cmdParts[1], "'"), "/"), "/") 113 + slog.Info("command components", "components", components) 114 115 if len(components) != 2 { 116 + slog.Error("invalid repo format", "components", components) 117 fmt.Fprintln(os.Stderr, "invalid repo format, needs <user>/<repo> or /<user>/<repo>") 118 os.Exit(-1) 119 } 120 121 didOrHandle := components[0] 122 + identity := resolveIdentity(ctx, didOrHandle) 123 did := identity.DID.String() 124 repoName := components[1] 125 qualifiedRepoName, _ := securejoin.SecureJoin(did, repoName) ··· 130 "git-upload-archive": true, 131 } 132 if !validCommands[gitCommand] { 133 + slog.Error("access denied: invalid git command", "command", gitCommand) 134 fmt.Fprintln(os.Stderr, "access denied: invalid git command") 135 return fmt.Errorf("access denied: invalid git command") 136 } 137 138 if gitCommand != "git-upload-pack" { 139 + if !isPushPermitted(incomingUser, qualifiedRepoName, endpoint) { 140 + slog.Error("access denied: user not allowed", 141 "did", incomingUser, 142 "reponame", qualifiedRepoName) 143 fmt.Fprintln(os.Stderr, "access denied: user not allowed") ··· 147 148 fullPath, _ := securejoin.SecureJoin(gitDir, qualifiedRepoName) 149 150 + slog.Info("processing command", 151 "user", incomingUser, 152 "command", gitCommand, 153 "repo", repoName, ··· 157 var motdReader io.Reader 158 if reader, err := os.Open(motdFile); err != nil { 159 if !errors.Is(err, os.ErrNotExist) { 160 + slog.Error("failed to read motd file", "error", err) 161 } 162 motdReader = strings.NewReader("Welcome to this knot!\n") 163 } else { ··· 178 ) 179 180 if err := gitCmd.Run(); err != nil { 181 + slog.Error("command failed", "error", err) 182 fmt.Fprintf(os.Stderr, "command failed: %v\n", err) 183 return fmt.Errorf("command failed: %v", err) 184 } 185 186 + slog.Info("command completed", 187 "user", incomingUser, 188 "command", gitCommand, 189 "repo", repoName, ··· 192 return nil 193 } 194 195 + func resolveIdentity(ctx context.Context, didOrHandle string) *identity.Identity { 196 resolver := idresolver.DefaultResolver() 197 ident, err := resolver.ResolveIdent(ctx, didOrHandle) 198 if err != nil { 199 + slog.Error("Error resolving handle", "error", err, "handle", didOrHandle) 200 fmt.Fprintf(os.Stderr, "error resolving handle: %v\n", err) 201 os.Exit(1) 202 } 203 if ident.Handle.IsInvalidHandle() { 204 + slog.Error("Error resolving handle", "invalid handle", didOrHandle) 205 fmt.Fprintf(os.Stderr, "error resolving handle: invalid handle\n") 206 os.Exit(1) 207 } 208 return ident 209 } 210 211 + func isPushPermitted(user, qualifiedRepoName, endpoint string) bool { 212 u, _ := url.Parse(endpoint + "/push-allowed") 213 q := u.Query() 214 q.Add("user", user) ··· 217 218 req, err := http.Get(u.String()) 219 if err != nil { 220 + slog.Error("Error verifying permissions", "error", err) 221 fmt.Fprintf(os.Stderr, "error verifying permissions: %v\n", err) 222 os.Exit(1) 223 } 224 225 + slog.Info("checking push permission", 226 "url", u.String(), 227 "status", req.Status) 228

History

1 round 7 comments
sign up or login to add to the discussion
oppi.li submitted #0
1 commit
expand
guard: supress logging
3/3 success
expand
expand 7 comments

I've moved part of the guard logics to internal server in #700 which also address this issue a bit (ignore all outdated title/description, see the commit.)

Do we want to move all guard logics to internal server instead? would be helpful in other directions too e.g. greeting with user handle in ssh -T

I've moved part of the guard logics to internal server in #700 which also address this issue a bit (ignore all outdated title/description, see the commit.)

Do we want to move all guard logics to internal server instead? would be helpful in other directions too e.g. greeting with user handle in ssh -T

uhh why the comment is duplicated. I pressed the button once. I lost the network log after second comment so can't check what happend.

that could be interesting. perhaps we could convert the knot keys command to do something similar as well.

that change can be sumbmitted independent of the rest of the stack, it is a bit hard to merge now because it is it the middle of the other changes in that patch.

Can we merge the stack below the #684? #684 is there only to share my dev setup but I think all 702~701 are fine to merge.

this PR is no longer required!

closed without merging