From 3516e2502974e46f440e8aa9b28fd9a680cbde01 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Fri, 19 Jul 2019 18:25:57 +0300 Subject: [PATCH 01/15] Small tool to fetch configured SSH keys for a Github Team Note: The included authtoken was included as an example, not by mistake and has been revoked long ago --- access/fetch-keys/README.md | 11 +++ access/fetch-keys/authtoken.go | 3 + access/fetch-keys/main.go | 137 +++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 access/fetch-keys/README.md create mode 100644 access/fetch-keys/authtoken.go create mode 100644 access/fetch-keys/main.go diff --git a/access/fetch-keys/README.md b/access/fetch-keys/README.md new file mode 100644 index 0000000..ae83209 --- /dev/null +++ b/access/fetch-keys/README.md @@ -0,0 +1,11 @@ +Use the Github API to fetch configured SSH keys for a team. + +Build by +``` +go get +go build +``` +Run +``` +./fetch-keys --help +``` diff --git a/access/fetch-keys/authtoken.go b/access/fetch-keys/authtoken.go new file mode 100644 index 0000000..ad85a29 --- /dev/null +++ b/access/fetch-keys/authtoken.go @@ -0,0 +1,3 @@ +package main + +const AuthToken = "c90e06359175cfccc4db21f60c44b83d93ccbd28" diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go new file mode 100644 index 0000000..e14d1c0 --- /dev/null +++ b/access/fetch-keys/main.go @@ -0,0 +1,137 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "github.com/akamensky/argparse" + "github.com/google/go-github/github" // with go modules disabled + "golang.org/x/oauth2" + "io/ioutil" + "os" +) + +func main() { + + parser := argparse.NewParser("sshkeys", "Fetch SSH keys for a Github team members") + ghTeam := parser.String("t", "team", &argparse.Options{Required: false, Help: "Github Team name", Default: "NOC"}) + ghOrganization := parser.String("o", "org", &argparse.Options{Required: false, Help: "Github Organization name", Default: "OpenFest"}) + authToken := parser.String("a", "authtoken", &argparse.Options{Required: false, Help: "Github Auth token", Default: AuthToken}) + + // Parse input + err := parser.Parse(os.Args) + if err != nil { + fmt.Print(parser.Usage(err)) + os.Exit(1) + } + + ctx := context.Background() + ts := oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: *authToken}, + ) + tc := oauth2.NewClient(ctx, ts) + + client := github.NewClient(tc) + + var nocTeam *github.Team + var nocMembers []*string + + for nextPage := 0; ; { + // list all teams for the specified org + opt := &github.ListOptions{nextPage, 50} + teams, rsp, err := client.Teams.ListTeams(ctx, *ghOrganization, opt) + + if err != nil { + fmt.Errorf("client.ListTeams error: %v", err) + os.Exit(-1) + } + + if rsp == nil { + fmt.Errorf("client.Repositories.List returned empty response: %v", err) + } + + for _, team := range teams { + if *team.Name == *ghTeam { + nocTeam = team + break + } + } + + if rsp.NextPage == 0 || nextPage == rsp.NextPage { + break + } + nextPage = rsp.NextPage + } + + if nocTeam == nil { + fmt.Errorf("NOC team not found in OpenFest") + os.Exit(2) + } + + for nextPage := 0; ; { + // list all members for the given organization's team + opt := &github.TeamListTeamMembersOptions{ + Role: "all", + ListOptions: github.ListOptions{nextPage, 50}, + } + + users, rsp, err := client.Teams.ListTeamMembers(context.Background(), *nocTeam.ID, opt) + + if err != nil { + fmt.Errorf("client.Teams.ListTeamMembers %v", err) + os.Exit(-1) + } + + if rsp == nil { + fmt.Errorf("client.Teams.ListTeamMembers: %v", err) + } + + for _, user := range users { + nocMembers = append(nocMembers, user.Login) + } + + if rsp.NextPage == 0 || nextPage == rsp.NextPage { + break + } + nextPage = rsp.NextPage + } + + for _, user := range nocMembers { + fmt.Println("Fetching keys for ", *user) + var sshKeys bytes.Buffer + + for nextPage := 0; ; { + + // list all teams an org for the current user + opt := &github.ListOptions{nextPage, 50} + keys, rsp, err := client.Users.ListKeys(ctx, *user, opt) + + if err != nil { + fmt.Errorf("client.Users.ListKeys error: %v", err) + os.Exit(-1) + } + + if rsp == nil { + fmt.Errorf("Users.ListKeyss returned empty response: %v", err) + } + + for _, key := range keys { + fmt.Println(*key.Key) + sshKeys.WriteString(*key.Key) + sshKeys.WriteString("\n") + } + + if rsp.NextPage == 0 || nextPage == rsp.NextPage { + break + } + nextPage = rsp.NextPage + } + + err := ioutil.WriteFile(*user+".key", sshKeys.Bytes(), 0444) + if err != nil { + fmt.Errorf(*user+".key error %v", err) + } + } + + os.Exit(0) +} From dfdf16693e288d04be76b637430273b80b65103f Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Fri, 19 Jul 2019 18:33:12 +0300 Subject: [PATCH 02/15] Add a note --- access/fetch-keys/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/access/fetch-keys/README.md b/access/fetch-keys/README.md index ae83209..dbd8a69 100644 --- a/access/fetch-keys/README.md +++ b/access/fetch-keys/README.md @@ -9,3 +9,6 @@ Run ``` ./fetch-keys --help ``` + +TODO: This polutes the current working directory with `{user}.key` files - add +a command line option for custom output target dir From fa5b07036c6366a5cc2a0925dc6d855a154a970e Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sat, 20 Jul 2019 15:01:19 +0300 Subject: [PATCH 03/15] Add liscense --- access/fetch-keys/main.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index e14d1c0..1c1d973 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -1,3 +1,12 @@ +/*- + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 69): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. -Shteryana Shopova + * ---------------------------------------------------------------------------- + */ + package main import ( From 46f994e190cb6945b0e343402a37a0f624ad3ebb Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sat, 20 Jul 2019 15:06:13 +0300 Subject: [PATCH 04/15] Option to suppress verbose output --- access/fetch-keys/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index 1c1d973..eaff0f3 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -26,6 +26,7 @@ func main() { ghTeam := parser.String("t", "team", &argparse.Options{Required: false, Help: "Github Team name", Default: "NOC"}) ghOrganization := parser.String("o", "org", &argparse.Options{Required: false, Help: "Github Organization name", Default: "OpenFest"}) authToken := parser.String("a", "authtoken", &argparse.Options{Required: false, Help: "Github Auth token", Default: AuthToken}) + quiet := parser.Flag("q", "quiet", &argparse.Options{Required: false, Help: "Skip output to stdout", Default: false}) // Parse input err := parser.Parse(os.Args) @@ -106,7 +107,9 @@ func main() { } for _, user := range nocMembers { - fmt.Println("Fetching keys for ", *user) + if *quiet == false { + fmt.Println("Fetching keys for ", *user) + } var sshKeys bytes.Buffer for nextPage := 0; ; { @@ -125,7 +128,9 @@ func main() { } for _, key := range keys { - fmt.Println(*key.Key) + if *quiet == false { + fmt.Println(*key.Key) + } sshKeys.WriteString(*key.Key) sshKeys.WriteString("\n") } From 56e4e4218ad5e836f2f39344e60e820c73c5e47f Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sat, 20 Jul 2019 22:04:12 +0300 Subject: [PATCH 05/15] Custom output directory --- access/fetch-keys/main.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index eaff0f3..847d7c1 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -27,6 +27,7 @@ func main() { ghOrganization := parser.String("o", "org", &argparse.Options{Required: false, Help: "Github Organization name", Default: "OpenFest"}) authToken := parser.String("a", "authtoken", &argparse.Options{Required: false, Help: "Github Auth token", Default: AuthToken}) quiet := parser.Flag("q", "quiet", &argparse.Options{Required: false, Help: "Skip output to stdout", Default: false}) + keysDir := parser.String("d", "directory", &argparse.Options{Required: false, Help: "Path where to store the key files", Default: "./"}) // Parse input err := parser.Parse(os.Args) @@ -35,6 +36,17 @@ func main() { os.Exit(1) } + fi, err := os.Lstat(*keysDir) + if err != nil { + fmt.Println(*keysDir, ": target directory error :", err) + os.Exit(1) + } else { + if fi.Mode().IsDir() == false { + fmt.Println(*keysDir, ": target directory error : not a directory - ", fi.Mode()) + os.Exit(1) + } + } + ctx := context.Background() ts := oauth2.StaticTokenSource( &oauth2.Token{AccessToken: *authToken}, @@ -141,7 +153,8 @@ func main() { nextPage = rsp.NextPage } - err := ioutil.WriteFile(*user+".key", sshKeys.Bytes(), 0444) + fmt.Println("Writing to", *keysDir + *user+".key") + err := ioutil.WriteFile(*keysDir + "/" + *user+".key", sshKeys.Bytes(), 0444) if err != nil { fmt.Errorf(*user+".key error %v", err) } From 0ffbf28dd20aff284cade86c9215be6a693cb7d2 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sat, 20 Jul 2019 22:06:22 +0300 Subject: [PATCH 06/15] Reorder cmdline args proper (no functional change) --- access/fetch-keys/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index 847d7c1..a56b7a6 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -23,11 +23,11 @@ import ( func main() { parser := argparse.NewParser("sshkeys", "Fetch SSH keys for a Github team members") - ghTeam := parser.String("t", "team", &argparse.Options{Required: false, Help: "Github Team name", Default: "NOC"}) - ghOrganization := parser.String("o", "org", &argparse.Options{Required: false, Help: "Github Organization name", Default: "OpenFest"}) authToken := parser.String("a", "authtoken", &argparse.Options{Required: false, Help: "Github Auth token", Default: AuthToken}) - quiet := parser.Flag("q", "quiet", &argparse.Options{Required: false, Help: "Skip output to stdout", Default: false}) keysDir := parser.String("d", "directory", &argparse.Options{Required: false, Help: "Path where to store the key files", Default: "./"}) + quiet := parser.Flag("q", "quiet", &argparse.Options{Required: false, Help: "Skip output to stdout", Default: false}) + ghOrganization := parser.String("o", "org", &argparse.Options{Required: false, Help: "Github Organization name", Default: "OpenFest"}) + ghTeam := parser.String("t", "team", &argparse.Options{Required: false, Help: "Github Team name", Default: "NOC"}) // Parse input err := parser.Parse(os.Args) From 73639ad0fde8068fd8dbc469135263f953873b57 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sat, 20 Jul 2019 22:12:35 +0300 Subject: [PATCH 07/15] Print errors proper --- access/fetch-keys/main.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index a56b7a6..0ddcadf 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -64,12 +64,12 @@ func main() { teams, rsp, err := client.Teams.ListTeams(ctx, *ghOrganization, opt) if err != nil { - fmt.Errorf("client.ListTeams error: %v", err) + fmt.Println("client.ListTeams error: %v", err) os.Exit(-1) } if rsp == nil { - fmt.Errorf("client.Repositories.List returned empty response: %v", err) + fmt.Println("client.Repositories.List returned empty response: %v", err) } for _, team := range teams { @@ -86,7 +86,7 @@ func main() { } if nocTeam == nil { - fmt.Errorf("NOC team not found in OpenFest") + fmt.Println("NOC team not found in OpenFest") os.Exit(2) } @@ -100,12 +100,12 @@ func main() { users, rsp, err := client.Teams.ListTeamMembers(context.Background(), *nocTeam.ID, opt) if err != nil { - fmt.Errorf("client.Teams.ListTeamMembers %v", err) + fmt.Println("client.Teams.ListTeamMembers %v", err) os.Exit(-1) } if rsp == nil { - fmt.Errorf("client.Teams.ListTeamMembers: %v", err) + fmt.Println("client.Teams.ListTeamMembers: %v", err) } for _, user := range users { @@ -131,12 +131,12 @@ func main() { keys, rsp, err := client.Users.ListKeys(ctx, *user, opt) if err != nil { - fmt.Errorf("client.Users.ListKeys error: %v", err) + fmt.Println("client.Users.ListKeys error: %v", err) os.Exit(-1) } if rsp == nil { - fmt.Errorf("Users.ListKeyss returned empty response: %v", err) + fmt.Println("Users.ListKeyss returned empty response: %v", err) } for _, key := range keys { @@ -153,10 +153,12 @@ func main() { nextPage = rsp.NextPage } - fmt.Println("Writing to", *keysDir + *user+".key") + if *quiet == false { + fmt.Println("Writing to", *keysDir + "/" + *user+".key") + } err := ioutil.WriteFile(*keysDir + "/" + *user+".key", sshKeys.Bytes(), 0444) if err != nil { - fmt.Errorf(*user+".key error %v", err) + fmt.Println(*user+".key error %v", err) } } From c3856472a831d5782d816657b80b6c83b9fb7d49 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sat, 20 Jul 2019 22:16:56 +0300 Subject: [PATCH 08/15] Minor improvements --- access/fetch-keys/main.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index 0ddcadf..1ae4422 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -55,8 +55,8 @@ func main() { client := github.NewClient(tc) - var nocTeam *github.Team - var nocMembers []*string + var targetTeam *github.Team + var teamMembers []*string for nextPage := 0; ; { // list all teams for the specified org @@ -64,17 +64,17 @@ func main() { teams, rsp, err := client.Teams.ListTeams(ctx, *ghOrganization, opt) if err != nil { - fmt.Println("client.ListTeams error: %v", err) + fmt.Println("client.ListTeams error: ", err) os.Exit(-1) } if rsp == nil { - fmt.Println("client.Repositories.List returned empty response: %v", err) + fmt.Println("client.ListTeams returned empty response: ", err) } for _, team := range teams { if *team.Name == *ghTeam { - nocTeam = team + targetTeam = team break } } @@ -85,8 +85,8 @@ func main() { nextPage = rsp.NextPage } - if nocTeam == nil { - fmt.Println("NOC team not found in OpenFest") + if targetTeam == nil { + fmt.Println(*ghTeam , " team not found in ", *ghOrganization) os.Exit(2) } @@ -97,19 +97,19 @@ func main() { ListOptions: github.ListOptions{nextPage, 50}, } - users, rsp, err := client.Teams.ListTeamMembers(context.Background(), *nocTeam.ID, opt) + users, rsp, err := client.Teams.ListTeamMembers(context.Background(), *targetTeam.ID, opt) if err != nil { - fmt.Println("client.Teams.ListTeamMembers %v", err) + fmt.Println("client.Teams.ListTeamMembers ", err) os.Exit(-1) } if rsp == nil { - fmt.Println("client.Teams.ListTeamMembers: %v", err) + fmt.Println("client.Teams.ListTeamMembers: ", err) } for _, user := range users { - nocMembers = append(nocMembers, user.Login) + teamMembers = append(teamMembers, user.Login) } if rsp.NextPage == 0 || nextPage == rsp.NextPage { @@ -118,7 +118,7 @@ func main() { nextPage = rsp.NextPage } - for _, user := range nocMembers { + for _, user := range teamMembers { if *quiet == false { fmt.Println("Fetching keys for ", *user) } @@ -131,12 +131,12 @@ func main() { keys, rsp, err := client.Users.ListKeys(ctx, *user, opt) if err != nil { - fmt.Println("client.Users.ListKeys error: %v", err) + fmt.Println("client.Users.ListKeys error: ", err) os.Exit(-1) } if rsp == nil { - fmt.Println("Users.ListKeyss returned empty response: %v", err) + fmt.Println("Users.ListKeys returned empty response: ", err) } for _, key := range keys { @@ -158,7 +158,7 @@ func main() { } err := ioutil.WriteFile(*keysDir + "/" + *user+".key", sshKeys.Bytes(), 0444) if err != nil { - fmt.Println(*user+".key error %v", err) + fmt.Println(*user+".key error ", err) } } From 4724952c61a91f393c81c3f9db287b02f48e43f6 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sat, 20 Jul 2019 22:58:53 +0300 Subject: [PATCH 09/15] Rework the code a bit (no functional change) --- access/fetch-keys/main.go | 129 ++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 62 deletions(-) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index 1ae4422..dd9b62e 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -55,69 +55,8 @@ func main() { client := github.NewClient(tc) - var targetTeam *github.Team - var teamMembers []*string - - for nextPage := 0; ; { - // list all teams for the specified org - opt := &github.ListOptions{nextPage, 50} - teams, rsp, err := client.Teams.ListTeams(ctx, *ghOrganization, opt) - - if err != nil { - fmt.Println("client.ListTeams error: ", err) - os.Exit(-1) - } - - if rsp == nil { - fmt.Println("client.ListTeams returned empty response: ", err) - } - - for _, team := range teams { - if *team.Name == *ghTeam { - targetTeam = team - break - } - } - - if rsp.NextPage == 0 || nextPage == rsp.NextPage { - break - } - nextPage = rsp.NextPage - } - - if targetTeam == nil { - fmt.Println(*ghTeam , " team not found in ", *ghOrganization) - os.Exit(2) - } - - for nextPage := 0; ; { - // list all members for the given organization's team - opt := &github.TeamListTeamMembersOptions{ - Role: "all", - ListOptions: github.ListOptions{nextPage, 50}, - } - - users, rsp, err := client.Teams.ListTeamMembers(context.Background(), *targetTeam.ID, opt) - - if err != nil { - fmt.Println("client.Teams.ListTeamMembers ", err) - os.Exit(-1) - } - - if rsp == nil { - fmt.Println("client.Teams.ListTeamMembers: ", err) - } - - for _, user := range users { - teamMembers = append(teamMembers, user.Login) - } - - if rsp.NextPage == 0 || nextPage == rsp.NextPage { - break - } - nextPage = rsp.NextPage - } + teamMembers := fetchUsers(client, ghOrganization, ghTeam) for _, user := range teamMembers { if *quiet == false { fmt.Println("Fetching keys for ", *user) @@ -164,3 +103,69 @@ func main() { os.Exit(0) } + +func fetchUsers(client *github.Client, org *string, team *string) (teamMembers []*string) { + var targetTeam *github.Team + + for nextPage := 0; ; { + // list all teams for the specified org + opt := &github.ListOptions{nextPage, 50} + teams, rsp, err := client.Teams.ListTeams(context.Background(), *org, opt) + + if err != nil { + fmt.Println("client.ListTeams error: ", err) + os.Exit(-1) + } + + if rsp == nil { + fmt.Println("client.ListTeams returned empty response: ", err) + } + + for _, ghTeam := range teams { + if *ghTeam.Name == *team { + targetTeam = ghTeam + break + } + } + + if rsp.NextPage == 0 || nextPage == rsp.NextPage { + break + } + nextPage = rsp.NextPage + } + + if targetTeam == nil { + fmt.Println(*team , " team not found in ", *org) + os.Exit(2) + } + + for nextPage := 0; ; { + // list all members for the given organization's team + opt := &github.TeamListTeamMembersOptions{ + Role: "all", + ListOptions: github.ListOptions{nextPage, 50}, + } + + users, rsp, err := client.Teams.ListTeamMembers(context.Background(), *targetTeam.ID, opt) + + if err != nil { + fmt.Println("client.Teams.ListTeamMembers ", err) + os.Exit(-1) + } + + if rsp == nil { + fmt.Println("client.Teams.ListTeamMembers: ", err) + } + + for _, user := range users { + teamMembers = append(teamMembers, user.Login) + } + + if rsp.NextPage == 0 || nextPage == rsp.NextPage { + break + } + nextPage = rsp.NextPage + } + + return teamMembers +} From 040a46ae7e5b7d0891ccd189b1a1428a62b87078 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sat, 20 Jul 2019 23:07:01 +0300 Subject: [PATCH 10/15] Add team "all",i.e everyone in the organization --- access/fetch-keys/main.go | 120 ++++++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 45 deletions(-) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index dd9b62e..b4a6d33 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -27,7 +27,7 @@ func main() { keysDir := parser.String("d", "directory", &argparse.Options{Required: false, Help: "Path where to store the key files", Default: "./"}) quiet := parser.Flag("q", "quiet", &argparse.Options{Required: false, Help: "Skip output to stdout", Default: false}) ghOrganization := parser.String("o", "org", &argparse.Options{Required: false, Help: "Github Organization name", Default: "OpenFest"}) - ghTeam := parser.String("t", "team", &argparse.Options{Required: false, Help: "Github Team name", Default: "NOC"}) + ghTeam := parser.String("t", "team", &argparse.Options{Required: false, Help: "Github Team name, 'all' for all members of the organization", Default: "NOC"}) // Parse input err := parser.Parse(os.Args) @@ -107,64 +107,94 @@ func main() { func fetchUsers(client *github.Client, org *string, team *string) (teamMembers []*string) { var targetTeam *github.Team - for nextPage := 0; ; { - // list all teams for the specified org - opt := &github.ListOptions{nextPage, 50} - teams, rsp, err := client.Teams.ListTeams(context.Background(), *org, opt) + if team == nil || *team == "all" { + for nextPage := 0; ; { + // list all members for the given organization's team + opt := &github.ListMembersOptions{ + PublicOnly: false, + ListOptions: github.ListOptions{nextPage, 50}, + } - if err != nil { - fmt.Println("client.ListTeams error: ", err) - os.Exit(-1) - } + users, rsp, err := client.Organizations.ListMembers(context.Background(), *org, opt) - if rsp == nil { - fmt.Println("client.ListTeams returned empty response: ", err) - } + if err != nil { + fmt.Println("client.Organizations.ListMembers ", err) + os.Exit(-1) + } - for _, ghTeam := range teams { - if *ghTeam.Name == *team { - targetTeam = ghTeam + if rsp == nil { + fmt.Println("client.Organizations.ListMembers: ", err) + } + + for _, user := range users { + teamMembers = append(teamMembers, user.Login) + } + + if rsp.NextPage == 0 || nextPage == rsp.NextPage { break } + nextPage = rsp.NextPage + } + } else { + for nextPage := 0; ; { + // list all teams for the specified org + opt := &github.ListOptions{nextPage, 50} + teams, rsp, err := client.Teams.ListTeams(context.Background(), *org, opt) + + if err != nil { + fmt.Println("client.ListTeams error: ", err) + os.Exit(-1) + } + + if rsp == nil { + fmt.Println("client.ListTeams returned empty response: ", err) + } + + for _, ghTeam := range teams { + if *ghTeam.Name == *team { + targetTeam = ghTeam + break + } + } + + if rsp.NextPage == 0 || nextPage == rsp.NextPage { + break + } + nextPage = rsp.NextPage } - if rsp.NextPage == 0 || nextPage == rsp.NextPage { - break - } - nextPage = rsp.NextPage - } - - if targetTeam == nil { - fmt.Println(*team , " team not found in ", *org) - os.Exit(2) - } - - for nextPage := 0; ; { - // list all members for the given organization's team - opt := &github.TeamListTeamMembersOptions{ - Role: "all", - ListOptions: github.ListOptions{nextPage, 50}, + if targetTeam == nil { + fmt.Println(*team , " team not found in ", *org) + os.Exit(2) } - users, rsp, err := client.Teams.ListTeamMembers(context.Background(), *targetTeam.ID, opt) + for nextPage := 0; ; { + // list all members for the given organization's team + opt := &github.TeamListTeamMembersOptions{ + Role: "all", + ListOptions: github.ListOptions{nextPage, 50}, + } - if err != nil { - fmt.Println("client.Teams.ListTeamMembers ", err) - os.Exit(-1) - } + users, rsp, err := client.Teams.ListTeamMembers(context.Background(), *targetTeam.ID, opt) - if rsp == nil { - fmt.Println("client.Teams.ListTeamMembers: ", err) - } + if err != nil { + fmt.Println("client.Teams.ListTeamMembers ", err) + os.Exit(-1) + } - for _, user := range users { - teamMembers = append(teamMembers, user.Login) - } + if rsp == nil { + fmt.Println("client.Teams.ListTeamMembers: ", err) + } - if rsp.NextPage == 0 || nextPage == rsp.NextPage { - break + for _, user := range users { + teamMembers = append(teamMembers, user.Login) + } + + if rsp.NextPage == 0 || nextPage == rsp.NextPage { + break + } + nextPage = rsp.NextPage } - nextPage = rsp.NextPage } return teamMembers From ae0756bf5c269d6dc74c9ca68429877bf93371b2 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sat, 20 Jul 2019 23:26:13 +0300 Subject: [PATCH 11/15] Fetch also configured PGP keys if requested --- access/fetch-keys/main.go | 42 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index b4a6d33..b3384fe 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -25,8 +25,9 @@ func main() { parser := argparse.NewParser("sshkeys", "Fetch SSH keys for a Github team members") authToken := parser.String("a", "authtoken", &argparse.Options{Required: false, Help: "Github Auth token", Default: AuthToken}) keysDir := parser.String("d", "directory", &argparse.Options{Required: false, Help: "Path where to store the key files", Default: "./"}) - quiet := parser.Flag("q", "quiet", &argparse.Options{Required: false, Help: "Skip output to stdout", Default: false}) ghOrganization := parser.String("o", "org", &argparse.Options{Required: false, Help: "Github Organization name", Default: "OpenFest"}) + fetchPgp := parser.Flag("p", "pgp-keys", &argparse.Options{Required: false, Help: "Fetch configured PGP key ids", Default: false}) + quiet := parser.Flag("q", "quiet", &argparse.Options{Required: false, Help: "Skip output to stdout", Default: false}) ghTeam := parser.String("t", "team", &argparse.Options{Required: false, Help: "Github Team name, 'all' for all members of the organization", Default: "NOC"}) // Parse input @@ -62,6 +63,7 @@ func main() { fmt.Println("Fetching keys for ", *user) } var sshKeys bytes.Buffer + var pgpKeys bytes.Buffer for nextPage := 0; ; { @@ -99,6 +101,44 @@ func main() { if err != nil { fmt.Println(*user+".key error ", err) } + + if *fetchPgp == true { + for nextPage := 0; ; { + + // list all teams an org for the current user + opt := &github.ListOptions{nextPage, 50} + keys, rsp, err := client.Users.ListGPGKeys(ctx, *user, opt) + + if err != nil { + fmt.Println("client.Users.ListGPGKeys error: ", err) + os.Exit(-1) + } + + if rsp == nil { + fmt.Println("Users.ListGPGKeys returned empty response: ", err) + } + + for _, key := range keys { + if *quiet == false { + fmt.Println(*key.KeyID) + } + pgpKeys.WriteString(*key.KeyID) + pgpKeys.WriteString("\n") + } + + if rsp.NextPage == 0 || nextPage == rsp.NextPage { + break + } + nextPage = rsp.NextPage + } + if *quiet == false { + fmt.Println("Writing to", *keysDir + "/" + *user+".gpg") + } + err = ioutil.WriteFile(*keysDir + "/" + *user+".gpg", pgpKeys.Bytes(), 0444) + if err != nil { + fmt.Println(*user+".gpg error ", err) + } + } } os.Exit(0) From 4aede61066de0d944b64f77f7c54ea6a9dccd3e7 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sat, 20 Jul 2019 23:59:50 +0300 Subject: [PATCH 12/15] Note is no longer relevant --- access/fetch-keys/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/access/fetch-keys/README.md b/access/fetch-keys/README.md index dbd8a69..ae83209 100644 --- a/access/fetch-keys/README.md +++ b/access/fetch-keys/README.md @@ -9,6 +9,3 @@ Run ``` ./fetch-keys --help ``` - -TODO: This polutes the current working directory with `{user}.key` files - add -a command line option for custom output target dir From c9dda0209235e974a22452cecf6f169f7bcae50d Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sun, 21 Jul 2019 00:06:50 +0300 Subject: [PATCH 13/15] go fmt --- access/fetch-keys/main.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index b3384fe..a7c141a 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -38,7 +38,7 @@ func main() { } fi, err := os.Lstat(*keysDir) - if err != nil { + if err != nil { fmt.Println(*keysDir, ": target directory error :", err) os.Exit(1) } else { @@ -56,7 +56,6 @@ func main() { client := github.NewClient(tc) - teamMembers := fetchUsers(client, ghOrganization, ghTeam) for _, user := range teamMembers { if *quiet == false { @@ -95,9 +94,9 @@ func main() { } if *quiet == false { - fmt.Println("Writing to", *keysDir + "/" + *user+".key") + fmt.Println("Writing to", *keysDir+"/"+*user+".key") } - err := ioutil.WriteFile(*keysDir + "/" + *user+".key", sshKeys.Bytes(), 0444) + err := ioutil.WriteFile(*keysDir+"/"+*user+".key", sshKeys.Bytes(), 0444) if err != nil { fmt.Println(*user+".key error ", err) } @@ -132,9 +131,9 @@ func main() { nextPage = rsp.NextPage } if *quiet == false { - fmt.Println("Writing to", *keysDir + "/" + *user+".gpg") + fmt.Println("Writing to", *keysDir+"/"+*user+".gpg") } - err = ioutil.WriteFile(*keysDir + "/" + *user+".gpg", pgpKeys.Bytes(), 0444) + err = ioutil.WriteFile(*keysDir+"/"+*user+".gpg", pgpKeys.Bytes(), 0444) if err != nil { fmt.Println(*user+".gpg error ", err) } @@ -151,7 +150,7 @@ func fetchUsers(client *github.Client, org *string, team *string) (teamMembers [ for nextPage := 0; ; { // list all members for the given organization's team opt := &github.ListMembersOptions{ - PublicOnly: false, + PublicOnly: false, ListOptions: github.ListOptions{nextPage, 50}, } @@ -204,7 +203,7 @@ func fetchUsers(client *github.Client, org *string, team *string) (teamMembers [ } if targetTeam == nil { - fmt.Println(*team , " team not found in ", *org) + fmt.Println(*team, " team not found in ", *org) os.Exit(2) } From 61b73ceecea92f53589f092c3629c30568126052 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sun, 21 Jul 2019 00:22:50 +0300 Subject: [PATCH 14/15] Don't dump the keys to stdout by default Include a flag to do so though, and ignore file system errors if dumping keys is enabled --- access/fetch-keys/main.go | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/access/fetch-keys/main.go b/access/fetch-keys/main.go index a7c141a..ea6ca35 100644 --- a/access/fetch-keys/main.go +++ b/access/fetch-keys/main.go @@ -29,6 +29,7 @@ func main() { fetchPgp := parser.Flag("p", "pgp-keys", &argparse.Options{Required: false, Help: "Fetch configured PGP key ids", Default: false}) quiet := parser.Flag("q", "quiet", &argparse.Options{Required: false, Help: "Skip output to stdout", Default: false}) ghTeam := parser.String("t", "team", &argparse.Options{Required: false, Help: "Github Team name, 'all' for all members of the organization", Default: "NOC"}) + verbose := parser.Flag("v", "verbose", &argparse.Options{Required: false, Help: "Verbose output: print keys to stdout", Default: false}) // Parse input err := parser.Parse(os.Args) @@ -37,14 +38,16 @@ func main() { os.Exit(1) } - fi, err := os.Lstat(*keysDir) - if err != nil { - fmt.Println(*keysDir, ": target directory error :", err) - os.Exit(1) - } else { - if fi.Mode().IsDir() == false { - fmt.Println(*keysDir, ": target directory error : not a directory - ", fi.Mode()) + if *verbose == false { + fi, err := os.Lstat(*keysDir) + if err != nil { + fmt.Println(*keysDir, ": target directory error :", err) os.Exit(1) + } else { + if fi.Mode().IsDir() == false { + fmt.Println(*keysDir, ": target directory error : not a directory - ", fi.Mode()) + os.Exit(1) + } } } @@ -59,7 +62,7 @@ func main() { teamMembers := fetchUsers(client, ghOrganization, ghTeam) for _, user := range teamMembers { if *quiet == false { - fmt.Println("Fetching keys for ", *user) + fmt.Println("Fetching keys for", *user) } var sshKeys bytes.Buffer var pgpKeys bytes.Buffer @@ -80,7 +83,7 @@ func main() { } for _, key := range keys { - if *quiet == false { + if *verbose == true { fmt.Println(*key.Key) } sshKeys.WriteString(*key.Key) @@ -93,11 +96,11 @@ func main() { nextPage = rsp.NextPage } - if *quiet == false { + if *quiet == false && *verbose == false { fmt.Println("Writing to", *keysDir+"/"+*user+".key") } err := ioutil.WriteFile(*keysDir+"/"+*user+".key", sshKeys.Bytes(), 0444) - if err != nil { + if err != nil && *verbose == false { fmt.Println(*user+".key error ", err) } @@ -118,7 +121,7 @@ func main() { } for _, key := range keys { - if *quiet == false { + if *verbose == true { fmt.Println(*key.KeyID) } pgpKeys.WriteString(*key.KeyID) @@ -130,11 +133,11 @@ func main() { } nextPage = rsp.NextPage } - if *quiet == false { + if *quiet == false && *verbose == false { fmt.Println("Writing to", *keysDir+"/"+*user+".gpg") } err = ioutil.WriteFile(*keysDir+"/"+*user+".gpg", pgpKeys.Bytes(), 0444) - if err != nil { + if err != nil && *verbose == false { fmt.Println(*user+".gpg error ", err) } } From ab4cfe84f7a17d0562c2df47004e0e16b1044097 Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Sun, 21 Jul 2019 00:58:54 +0300 Subject: [PATCH 15/15] Add a note on the OAuth token config --- access/fetch-keys/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/access/fetch-keys/README.md b/access/fetch-keys/README.md index ae83209..21c6acf 100644 --- a/access/fetch-keys/README.md +++ b/access/fetch-keys/README.md @@ -1,11 +1,14 @@ Use the Github API to fetch configured SSH keys for a team. -Build by +Build by (making sure your GOPATH environment variable is properly configured) - ``` go get go build ``` + Run ``` ./fetch-keys --help ``` + +The tool uses an OAuth Token to connect to the Github API, make sure you've added a personal access token via your [Github account settings](https://github.com/settings/tokens) and have either properly edited the [authtoken.go](authtoken.go#L3) source file (!!! with caution), or pass the appropriate token via the command line.