From 16a7bb1cb4af4978905cec7a295438fcc92221bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=9C=C9=B4=E1=B4=8B=C9=B4=E1=B4=A1=E1=B4=8F=C9=B4?= Date: Mon, 26 Apr 2021 21:14:57 +0800 Subject: [PATCH] authtest: add tests for site admin endpoints (#20266) --- dev/authtest/CODENOTIFY | 3 + dev/authtest/main_test.go | 2 + dev/authtest/site_admin_test.go | 423 +++++++++++++++++++++++++++++++- internal/gqltestutil/user.go | 2 +- 4 files changed, 424 insertions(+), 6 deletions(-) create mode 100644 dev/authtest/CODENOTIFY diff --git a/dev/authtest/CODENOTIFY b/dev/authtest/CODENOTIFY new file mode 100644 index 00000000000..b58720ac880 --- /dev/null +++ b/dev/authtest/CODENOTIFY @@ -0,0 +1,3 @@ +# See https://github.com/sourcegraph/codenotify for documentation. + +**/* @unknwon diff --git a/dev/authtest/main_test.go b/dev/authtest/main_test.go index 5af68615385..7154ec2b3e3 100644 --- a/dev/authtest/main_test.go +++ b/dev/authtest/main_test.go @@ -24,6 +24,8 @@ var ( password = flag.String("password", "supersecurepassword", "The password of the admin user") githubToken = flag.String("github-token", os.Getenv("GITHUB_TOKEN"), "The GitHub personal access token that will be used to authenticate a GitHub external service") + + dotcom = flag.Bool("dotcom", false, "Whether to test dotcom specific constraints") ) func TestMain(m *testing.M) { diff --git a/dev/authtest/site_admin_test.go b/dev/authtest/site_admin_test.go index 4e521ac3fb6..a6822d25342 100644 --- a/dev/authtest/site_admin_test.go +++ b/dev/authtest/site_admin_test.go @@ -1,29 +1,442 @@ package authtest import ( + "fmt" + "net/http" + "strings" "testing" + + "github.com/sourcegraph/sourcegraph/internal/gqltestutil" ) func TestSiteAdminEndpoints(t *testing.T) { // Create a test user (authtest-user-1) which is not a site admin, the user // should receive access denied for site admin endpoints. const testUsername = "authtest-user-1" - testUserID, err := client.CreateUser(testUsername, testUsername+"@sourcegraph.com") + userClient, err := gqltestutil.SignUp(*baseURL, testUsername+"@sourcegraph.com", testUsername, "mysecurepassword") if err != nil { t.Fatal(err) } defer func() { - err := client.DeleteUser(testUserID, true) + err := client.DeleteUser(userClient.AuthenticatedUserID(), true) if err != nil { t.Fatal(err) } }() - t.Run("HTTP endpoints", func(t *testing.T) { - // TODO(jchen): Add HTTP endpoints that are site-admin-only + t.Run("debug endpoints", func(t *testing.T) { + tests := []struct { + name string + path string + }{ + { + name: "debug", + path: "/-/debug/", + }, { + name: "jaeger", + path: "/-/debug/jaeger/", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + resp, err := userClient.Get(*baseURL + test.path) + if err != nil { + t.Fatal(err) + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusUnauthorized { + t.Fatalf(`Want status code %d error but got %d`, http.StatusUnauthorized, resp.StatusCode) + } + }) + } + }) + + t.Run("latest ping", func(t *testing.T) { + resp, err := userClient.Get(*baseURL + "/site-admin/pings/latest") + if err != nil { + t.Fatal(err) + } + defer func() { _ = resp.Body.Close() }() + + if want, got := http.StatusUnauthorized, resp.StatusCode; want != got { + t.Fatalf("Want %d but got %d", want, got) + } + }) + + t.Run("usage stats archive", func(t *testing.T) { + resp, err := userClient.Get(*baseURL + "/site-admin/usage-statistics/archive") + if err != nil { + t.Fatal(err) + } + defer func() { _ = resp.Body.Close() }() + + if want, got := http.StatusUnauthorized, resp.StatusCode; want != got { + t.Fatalf("Want %d but got %d", want, got) + } }) t.Run("GraphQL queries", func(t *testing.T) { - // TODO(jchen): Add GraphQL queries that are site-admin-only + type gqlTest struct { + name string + query string + variables map[string]interface{} + } + tests := []gqlTest{ + { + name: "resetTriggerQueryTimestamps", + query: ` +mutation { + resetTriggerQueryTimestamps(id: "SUQ6MTIz") { + alwaysNil + } +}`, + }, { + name: "dotcom.productLicenses", + query: ` +{ + dotcom { + productLicenses { + __typename + } + } +}`, + }, { + name: "dotcom.createProductSubscription", + query: ` +mutation { + dotcom { + createProductSubscription(accountID: "VXNlcjox") { + id + } + } +}`, + }, { + name: "dotcom.setProductSubscriptionBilling", + query: ` +mutation { + dotcom { + setProductSubscriptionBilling(id: "VXNlcjox") { + alwaysNil + } + } +}`, + }, { + name: "dotcom.archiveProductSubscription", + query: ` +mutation { + dotcom { + archiveProductSubscription(id: "VXNlcjox") { + alwaysNil + } + } +}`, + }, { + name: "dotcom.generateProductLicenseForSubscription", + query: ` +mutation { + dotcom { + generateProductLicenseForSubscription( + productSubscriptionID: "UHJvZHVjdFN1YnNjcmlwdGlvbjox" + license: {tags: [], userCount: 1, expiresAt: 1} + ) { + id + } + } +}`, + }, { + name: "dotcom.setUserBilling", + query: ` +mutation { + dotcom { + setUserBilling(user: "VXNlcjox", billingCustomerID: "404") { + alwaysNil + } + } +}`, + }, { + name: "updateMirrorRepository", + query: ` +mutation { + updateMirrorRepository(repository: "UmVwb3NpdG9yeTox") { + alwaysNil + } +}`, + }, { + name: "addUserToOrganization", + query: ` +mutation { + addUserToOrganization(organization: "T3JnYW5pemF0aW9uOjE=", username: "alice") { + alwaysNil + } +}`, + }, { + name: "site.configuration", + query: ` +{ + site { + configuration { + id + } + } +}`, + }, { + name: "site.accessTokens", + query: ` +{ + site { + accessTokens { + totalCount + } + } +}`, + }, { + name: "site.externalAccounts", + query: ` +{ + site { + externalAccounts { + nodes { + id + } + } + } +}`, + }, { + name: "updateSiteConfiguration", + query: ` +mutation { + updateSiteConfiguration(input: "", lastID: 0) +}`, + }, { + name: "deleteLSIFUpload", + query: ` +mutation { + deleteLSIFUpload(id: "TFNJRjox") { + alwaysNil + } +}`, + }, { + name: "outOfBandMigrations", + query: ` +{ + outOfBandMigrations { + id + } +}`, + }, { + name: "SetMigrationDirection", + query: ` +mutation { + SetMigrationDirection(id: "TWlncmF0aW9uOjE=", applyReverse: false) { + alwaysNil + } +}`, + }, { + name: "sendSavedSearchTestNotification", + query: ` +mutation { + sendSavedSearchTestNotification(id: "U2F2ZWRTZWFyY2g6MQ==") { + alwaysNil + } +}`, + }, { + name: "createAccessToken.ScopeSiteAdminSudo", + query: ` +mutation CreateAccessToken($userID: ID!) { + createAccessToken(user: $userID, scopes: ["site-admin:sudo"], note: "") { + id + } +}`, + variables: map[string]interface{}{ + "userID": userClient.AuthenticatedUserID(), + }, + }, { + name: "setRepositoryPermissionsForUsers", + query: ` +mutation { + setRepositoryPermissionsForUsers( + repository: "UmVwb3NpdG9yeTox" + userPermissions: [{bindID: "alice@example.com"}] + ) { + alwaysNil + } +}`, + }, { + name: "scheduleRepositoryPermissionsSync", + query: ` +mutation { + scheduleRepositoryPermissionsSync(repository: "UmVwb3NpdG9yeTox") { + alwaysNil + } +}`, + }, { + name: "scheduleUserPermissionsSync", + query: ` +mutation { + scheduleUserPermissionsSync(user: "VXNlcjox") { + alwaysNil + } +}`, + }, { + name: "authorizedUserRepositories", + query: ` +{ + authorizedUserRepositories(username: "alice", first: 1) { + totalCount + } +}`, + }, { + name: "usersWithPendingPermissions", + query: ` +{ + usersWithPendingPermissions +}`, + }, { + name: "authorizedUserRepositories", + query: ` +{ + authorizedUserRepositories(username: "alice", first: 1) { + totalCount + } +}`, + }, { + name: "setUserEmailVerified", + query: ` +mutation { + setUserEmailVerified( + user: "VXNlcjox" + email: "alice@exmaple.com" + verified: true + ) { + alwaysNil + } +}`, + }, { + name: "setUserIsSiteAdmin", + query: ` +mutation { + setUserIsSiteAdmin(userID: "VXNlcjox", siteAdmin: true) { + alwaysNil + } +}`, + }, { + name: "invalidateSessionsByID", + query: ` +mutation { + invalidateSessionsByID(userID: "VXNlcjox") { + alwaysNil + } +}`, + }, { + name: "triggerObservabilityTestAlert", + query: ` +mutation { + triggerObservabilityTestAlert(level: "critical") { + alwaysNil + } +}`, + }, { + name: "reloadSite", + query: ` +mutation { + reloadSite { + alwaysNil + } +}`, + }, { + name: "organizations", + query: ` +{ + organizations { + nodes { + id + } + } +}`, + }, { + name: "surveyResponses", + query: ` +{ + surveyResponses { + nodes { + id + } + } +}`, + }, { + name: "repositoryStats", + query: ` +{ + repositoryStats { + gitDirBytes + } +}`, + }, { + name: "createUser", + query: ` +mutation { + createUser(username: "alice") { + resetPasswordURL + } +}`, + }, { + name: "deleteUser", + query: ` +mutation { + deleteUser(user: "VXNlcjox") { + alwaysNil + } +}`, + }, { + name: "deleteOrganization", + query: ` +mutation { + deleteOrganization(organization: "T3JnYW5pemF0aW9uOjE=") { + alwaysNil + } +}`, + }, { + name: "randomizeUserPassword", + query: ` +mutation { + randomizeUserPassword(user: "VXNlcjox") { + resetPasswordURL + } +}`, + }, { + name: "setTag", + query: ` +mutation { + setTag(node: "VXNlcjox", tag: "tag", present: true) { + alwaysNil + } +}`, + }, + } + + if *dotcom { + tests = append(tests, + gqlTest{ + name: "look up user by email", + query: ` +{ + user(email: "alice@example.com") { + id + } +} +`, + }, + ) + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := userClient.GraphQL("", test.query, test.variables, nil) + got := fmt.Sprintf("%v", err) + if !strings.Contains(got, "must be site admin") { + t.Fatalf(`Want "must be site admin"" error but got %q`, got) + } + }) + } }) } diff --git a/internal/gqltestutil/user.go b/internal/gqltestutil/user.go index 2289843fe74..a99cd41e941 100644 --- a/internal/gqltestutil/user.go +++ b/internal/gqltestutil/user.go @@ -45,7 +45,7 @@ mutation CreateUser($username: String!, $email: String) { func (c *Client) DeleteUser(id string, hard bool) error { const query = ` mutation DeleteUser($user: ID!, $hard: Boolean) { - deleteUser(user: $user, hard: $hard) { + deleteUser(user: $user, hard: $hard) { alwaysNil } }