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

Changed files
+26 -29
guard
+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