# -*- coding: utf-8 -*- # # Copyright 2017 Google LLC. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Flags for binauthz command group.""" from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals from googlecloudsdk.calliope.concepts import concepts from googlecloudsdk.command_lib.container.binauthz import arg_parsers from googlecloudsdk.command_lib.kms import flags as kms_flags from googlecloudsdk.command_lib.util.concepts import concept_parsers from googlecloudsdk.command_lib.util.concepts import presentation_specs as presentation_specs_lib def _GetNoteResourceSpec(): return concepts.ResourceSpec( 'containeranalysis.projects.notes', resource_name='note', projectsId=concepts.ResourceParameterAttributeConfig( name='project', help_text='The Container Analysis project for the {resource}.', ), notesId=concepts.ResourceParameterAttributeConfig( name='note', help_text='The Container Analysis Note ID for the {resource}.', ), ) def _FormatArgName(base_name, positional): if positional: return base_name.replace('-', '_').upper() else: return '--' + base_name.replace('_', '-').lower() def GetNotePresentationSpec( group_help, base_name='note', required=True, positional=True, use_global_project_flag=False, ): """Construct a resource spec for a Container Analysis note flag.""" flag_overrides = None if not use_global_project_flag: flag_overrides = { 'project': _FormatArgName('{}-project'.format(base_name), positional), } return presentation_specs_lib.ResourcePresentationSpec( name=_FormatArgName(base_name, positional), concept_spec=_GetNoteResourceSpec(), group_help=group_help, required=required, flag_name_overrides=flag_overrides, ) def _GetAttestorResourceSpec(): return concepts.ResourceSpec( 'binaryauthorization.projects.attestors', resource_name='attestor', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, attestorsId=concepts.ResourceParameterAttributeConfig( name='name', help_text='The ID of the {resource}.', ), ) def GetAttestorPresentationSpec( group_help, base_name='attestor', required=True, positional=True, use_global_project_flag=True, ): """Construct a resource spec for an attestor flag.""" flag_overrides = None if not use_global_project_flag: flag_overrides = { 'project': _FormatArgName('{}-project'.format(base_name), positional), } return presentation_specs_lib.ResourcePresentationSpec( name=_FormatArgName(base_name, positional), concept_spec=_GetAttestorResourceSpec(), group_help=group_help, required=required, flag_name_overrides=flag_overrides, ) def _GetCryptoKeyVersionResourceSpec(): return concepts.ResourceSpec( kms_flags.CRYPTO_KEY_VERSION_COLLECTION, resource_name='CryptoKeyVersion', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, locationsId=concepts.ResourceParameterAttributeConfig( name='location', help_text='The location of the {resource}.', ), keyRingsId=concepts.ResourceParameterAttributeConfig( name='keyring', help_text='The keyring of the {resource}.', ), cryptoKeysId=concepts.ResourceParameterAttributeConfig( name='key', help_text='The key of the {resource}.', ), cryptoKeyVersionsId=concepts.ResourceParameterAttributeConfig( name='version', help_text='The key version of the {resource}.', ), ) def GetCryptoKeyVersionPresentationSpec( group_help, base_name='keyversion', required=True, positional=True, use_global_project_flag=True, ): """Construct a resource spec for a CryptoKeyVersion flag.""" flag_overrides = None if not use_global_project_flag: flag_overrides = { 'project': _FormatArgName('{}-project'.format(base_name), positional), } return presentation_specs_lib.ResourcePresentationSpec( name=_FormatArgName(base_name, positional), concept_spec=_GetCryptoKeyVersionResourceSpec(), group_help=group_help, required=required, prefixes=not use_global_project_flag, flag_name_overrides=flag_overrides, ) def AddConcepts(parser, *presentation_specs): concept_parsers.ConceptParser(presentation_specs).AddToParser(parser) def AddArtifactUrlFlag(parser, required=True): parser.add_argument( '--artifact-url', required=required, type=str, help=( 'Container URL. May be in the `gcr.io/repository/image` format,' ' or may optionally contain the `http` or `https` scheme' ), ) def _GetPlatformResourceSpec(): return concepts.ResourceSpec( 'binaryauthorization.projects.platforms', resource_name='platform', api_version='v1', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, platformsId=concepts.ResourceParameterAttributeConfig( name='platform', help_text='The platform.' ), ) def AddPlatformResourceArg(parser, verb): """Add a resource argument for a platform (containing platform policies). Args: parser: the parser for the command. verb: str, the verb to describe the resource, such as 'to list'. (No other values besides 'to list' are expected.) """ # Note: "resource arguments" (go/gcloud-creating-commands#resource-arguments) # requires the main resource to be a positional argument, not a keyword, so # --platform is not allowed when the main resource is a platform, even though # it is allowed when the main resource is a policy. concept_parsers.ConceptParser.ForResource( 'platform_resource_name', _GetPlatformResourceSpec(), 'The platform whose policies {}.'.format(verb), required=True, ).AddToParser(parser) def _GetPlatformPolicyResourceSpec(): return concepts.ResourceSpec( 'binaryauthorization.projects.platforms.policies', resource_name='policy', api_version='v1', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, platformsId=concepts.ResourceParameterAttributeConfig( name='platform', help_text=( 'The platform that the {resource} belongs to. ' 'PLATFORM must be one of the following: cloudRun, gke.' ), ), policyId=concepts.ResourceParameterAttributeConfig( name='policy', help_text='The ID of the {resource}.' ), ) def AddPlatformPolicyResourceArg(parser, verb): """Add a resource argument for a policy. Args: parser: the parser for the command. verb: str, the verb to describe the resource, such as 'to update'. """ concept_parsers.ConceptParser.ForResource( 'policy_resource_name', _GetPlatformPolicyResourceSpec(), 'The resource name of the policy {}.'.format(verb), required=True, ).AddToParser(parser) def AddEvaluationUnitArg(parser): """Adds a resource argument from file or from one or more images.""" evaluation_unit_group = parser.add_group(mutex=True, required=True) evaluation_unit_group.add_argument( '--resource', required=False, type=arg_parsers.ResourceFileName, help=( 'The JSON or YAML file containing the Kubernetes resource to' ' evaluate.' ), ) evaluation_unit_group.add_argument( '--image', required=False, action='append', help=( 'The image to evaluate. If the policy being evaluated has scoped' ' checksets, this mode of evaluation will always use the default' ' (unscoped) checkset.' ), ) def AddNoUploadArg(parser): """Adds a --no-upload flag to parser.""" parser.add_argument( '--no-upload', action='store_true', default=False, help=( 'Do not upload the generated attestations to the image registry' ' (using Sigstore tag conventions). Note, attestations are never' ' uploaded to the transparency log.' ), ) def AddOutputFileArg(parser): """Adds the output file argument to parser.""" parser.add_argument( '--output-file', help=( 'If a resource is provided and deemed to be conformant, attestations' ' will be added as annotations on the resource and writen back to' ' this file path in the same format as the input file.' ), ) def AddDockerCredsArgs(parser): """Adds the docker creds args to parser.""" docker_args_group = parser.add_group(mutex=False, required=False) docker_args_group.add_argument( '--use-docker-creds', required=False, action='store_true', default=False, help=( 'Whether to use the configuration file where Docker saves' ' authentication credentials when uploading attestations to the' ' registry. If this flag is not passed, or valid credentials are not' ' found, an OAuth2 token for the active gcloud account is used. See' ' https://cloud.google.com/artifact-registry/docs/docker/authentication' ' for more information.' ), ) docker_args_group.add_argument( '--docker-config-dir', required=False, help=( 'Override the directory where the Docker configuration file is' ' searched for. Credentials are pulled from the config.json file' ' under this directory. Defaults to $HOME/.docker.' ), )