go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/gcloud/project_id.go (about)

     1  // Copyright 2021 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package gcloud
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  )
    21  
    22  // ValidateProjectID returns an error if the supplied string is not
    23  // a valid Google Cloud project ID.
    24  //
    25  // A valid project ID
    26  // - must be 6 to 30 lowercase ASCII letters, digits, or hyphens,
    27  // - must start with a letter, and
    28  // - must not have a trailing hyphen.
    29  //
    30  // See:
    31  // https://cloud.google.com/resource-manager/reference/rest/v3/projects#resource:-project
    32  func ValidateProjectID(p string) error {
    33  	if len(p) < 6 || len(p) > 30 {
    34  		return errors.New("must contain 6 to 30 ASCII letters, digits, or hyphens")
    35  	}
    36  	if p[0] < 'a' || p[0] > 'z' {
    37  		return errors.New("must start with a lowercase ASCII letter")
    38  	}
    39  	if p[len(p)-1] == '-' {
    40  		return errors.New("must not have a trailing hyphen")
    41  	}
    42  	for i := 1; i < len(p)-1; i++ {
    43  		switch {
    44  		case p[i] >= 'a' && p[i] <= 'z', p[i] >= '0' && p[i] <= '9', p[i] == '-':
    45  		default:
    46  			return fmt.Errorf("invalid letter at %d (%c)", i, p[i])
    47  		}
    48  	}
    49  	return nil
    50  }