feat(sg): command to add default site-admin with predefined access token (#63320)

Adds a subcommand to `sg db` called `default-site-admin` that creates a
site-admin user with user:pass `sourcegraph:sourcegraph` and a
predefined hard-coded token
`sgp_local_f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0`


## Test plan

`go run ./dev/sg -- db default-site-admin` with clean database
`" "` after having run that (when everything should be set)
`" "` when user exists but token doesnt

## Changelog
This commit is contained in:
Noah S-C 2024-06-19 15:02:55 +01:00 committed by GitHub
parent 7ef56a60f9
commit a5a6a0dd23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 80 additions and 0 deletions

View File

@ -97,6 +97,7 @@ go_library(
"//internal/download",
"//internal/encryption",
"//internal/extsvc",
"//internal/hashutil",
"//internal/lazyregexp",
"//internal/observation",
"//internal/types",

View File

@ -3,15 +3,18 @@ package main
import (
"context"
"database/sql"
"encoding/hex"
"encoding/json"
"fmt"
"net/url"
"os"
"strings"
"time"
"github.com/gomodule/redigo/redis"
"github.com/google/go-github/v55/github"
"github.com/jackc/pgx/v4"
"github.com/keegancsmith/sqlf"
"github.com/urfave/cli/v2"
"golang.org/x/oauth2"
@ -20,6 +23,7 @@ import (
"github.com/sourcegraph/sourcegraph/dev/sg/internal/category"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/db"
"github.com/sourcegraph/sourcegraph/dev/sg/internal/std"
"github.com/sourcegraph/sourcegraph/internal/accesstoken"
"github.com/sourcegraph/sourcegraph/internal/database"
"github.com/sourcegraph/sourcegraph/internal/database/basestore"
connections "github.com/sourcegraph/sourcegraph/internal/database/connections/live"
@ -31,6 +35,7 @@ import (
"github.com/sourcegraph/sourcegraph/internal/database/postgresdsn"
"github.com/sourcegraph/sourcegraph/internal/encryption"
"github.com/sourcegraph/sourcegraph/internal/extsvc"
"github.com/sourcegraph/sourcegraph/internal/hashutil"
"github.com/sourcegraph/sourcegraph/internal/observation"
"github.com/sourcegraph/sourcegraph/internal/types"
"github.com/sourcegraph/sourcegraph/lib/cliutil/exit"
@ -180,6 +185,12 @@ sg db add-access-token -username=foo
},
Action: dbAddAccessTokenAction,
},
{
Name: "default-site-admin",
Usage: "Create a predefined site-admin user with a preset access token",
Action: dbDefaultSiteAdmin,
},
},
}
)
@ -284,6 +295,74 @@ func dbAddAccessTokenAction(cmd *cli.Context) error {
})
}
// equivalent to "f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0"
var magicTokenSuffix = [20]byte{240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240}
func dbDefaultSiteAdmin(cmd *cli.Context) error {
logger := log.Scoped("dbAddDefaultAccessTokenAction")
ttyOutput := output.NewOutput(os.Stdout, output.OutputOpts{})
conf, _ := getConfig()
if conf == nil {
return errors.New("failed to read sg.config.yaml. This command needs to be run in the `sourcegraph` repository")
}
conn, err := connections.EnsureNewFrontendDB(observation.NewContext(logger), postgresdsn.New("", "", conf.GetEnv), "frontend")
if err != nil {
return err
}
db := database.NewDB(logger, conn)
const (
username = "sourcegraph"
password = "sourcegraph"
)
return db.WithTransact(cmd.Context, func(tx database.DB) error {
user, err := tx.Users().Create(cmd.Context, database.NewUser{
Username: username,
Email: "sourcegraph@sourcegraph.com",
EmailIsVerified: true,
Password: password,
})
if err != nil && !database.IsUsernameExists(err) {
return err
} else if database.IsUsernameExists(err) {
user, err = tx.Users().GetByUsername(cmd.Context, username)
if err != nil {
return err
}
ttyOutput.WriteLine(output.Emojif(output.EmojiInfo, "User %q already exists, continuing...", username))
}
// Make the user site admin.
err = tx.Users().SetIsSiteAdmin(cmd.Context, user.ID, true)
if err != nil {
return err
}
token := fmt.Sprintf("%s%s_%s", accesstoken.PersonalAccessTokenPrefix, accesstoken.LocalInstanceIdentifier, hex.EncodeToString(magicTokenSuffix[:]))
if t, err := tx.AccessTokens().GetByToken(cmd.Context, token); t != nil || err != database.ErrAccessTokenNotFound {
if t != nil {
ttyOutput.WriteLine(output.Emojif(output.EmojiSuccess, "Default site-admin token already set for %q: %q", username, token))
}
return err
}
q := sqlf.Sprintf(`INSERT INTO access_tokens(subject_user_id, scopes, value_sha256, note, creator_user_id, expires_at, internal)
VALUES (%s, '{"user:all"}', %s, 'Default token for site-admin user created by sg', %s, NULL, false)`, user.ID, hashutil.ToSHA256Bytes(magicTokenSuffix[:]), user.ID)
if _, err = tx.ExecContext(cmd.Context, q.Query(sqlf.PostgresBindVar), q.Args()...); err != nil {
return err
}
ttyOutput.WriteLine(output.Emojif(output.EmojiSuccess, "Default site-admin successfully created with username %q, password %q and token %q", username, password, token))
return nil
})
}
func dbUpdateUserExternalAccount(cmd *cli.Context) error {
logger := log.Scoped("dbUpdateUserExternalAccount")
ctx := cmd.Context