blob: 6816769431f7fbc2873f37746ac25ba5a782df9b [file] [log] [blame]
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package common
import (
"context"
"errors"
"fmt"
"dawn.googlesource.com/dawn/tools/src/gerrit"
"dawn.googlesource.com/dawn/tools/src/gitiles"
"dawn.googlesource.com/dawn/tools/src/resultsdb"
)
// The following known remote services are not currently checked:
// - Buildbucket (tools/src/buildbucket), as all supported API calls rely
// directly or indirectly on Buildbucket IDs which are liable to age out over
// time, and thus are liable to randomly break the check.
// - Sheets (tools/src/cmd/cts/common/export), as the API does not appear to
// have a way of checking if the user has edit permissions without actually
// attempting to edit.
type CredCheckInputs struct {
GerritConfig *gerrit.Gerrit
GitilesConfig *gitiles.Gitiles
Querier resultsdb.Querier
}
// CheckAllRequiredCredentials checks that all the services that are necessary
// for CTS tooling functionality can be accessed correctly. Specifically, this
// checks:
// - Interacting with Gerrit
// - Reading from Gitiles
// - Querying ResultDB via BigQuery
func CheckAllRequiredCredentials(ctx context.Context, inputs CredCheckInputs) error {
var err error
if inputs.GerritConfig != nil {
fmt.Print("Checking if Gerrit can be accessed...")
err = checkGerritCredentials(ctx, inputs.GerritConfig)
if err != nil {
fmt.Println(" failed")
return err
}
fmt.Println(" success")
} else {
fmt.Println("Gerrit information not provided, not checking")
}
if inputs.GitilesConfig != nil {
fmt.Print("Checking if Gitiles can be accessed...")
err = checkGitilesCredentials(ctx, inputs.GitilesConfig)
if err != nil {
fmt.Println(" failed")
return err
}
fmt.Println(" success")
} else {
fmt.Println("Gitiles information not provided, not checking")
}
if inputs.Querier != nil {
fmt.Print("Checking if ResultsDB can be queried...")
client := inputs.Querier.(*resultsdb.BigQueryClient)
err = checkResultDBCredentials(ctx, client)
if err != nil {
fmt.Println(" failed")
return err
}
fmt.Println(" success")
} else {
fmt.Println("ResultDB information not provided, not checking")
}
return nil
}
// checkGerritCredentials checks that the provided Gerrit instance has the
// necessary permissions for the "dawn" project.
func checkGerritCredentials(ctx context.Context, gerritConfig *gerrit.Gerrit) error {
project := "dawn"
accessInfo, err := gerritConfig.ListAccessRights(ctx, project)
if err != nil {
return err
}
projectPermissions, exists := (*accessInfo)[project]
if !exists {
return fmt.Errorf("Project %v not in returned data", project)
}
if !projectPermissions.CanUpload {
return errors.New("Do not have permission to upload to Gerrit")
}
if !projectPermissions.CanAdd {
return errors.New("Do not have permission to add to existing Gerrit CLs")
}
if !projectPermissions.CanAddTags {
return errors.New("Do not have permission to add tags to existing Gerrit CLs")
}
return nil
}
// checkGitilesCredentials checks that the provided Gitiles instance has read
// permissions.
func checkGitilesCredentials(ctx context.Context, gitilesConfig *gitiles.Gitiles) error {
output, err := gitilesConfig.ListFiles(ctx, "HEAD", "")
if err != nil {
return err
}
if len(output) == 0 {
return errors.New("Did not get back any data from Gitiles")
}
return nil
}
// checkResultDBCredentils checks that the provided BigQueryClient can
// successfully query ResultDB data.
func checkResultDBCredentials(ctx context.Context, client *resultsdb.BigQueryClient) error {
return client.CheckIfResultDBCanBeQueried(ctx)
}