# -*- coding: utf-8 -*- # # Copyright 2019 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. """Common flags for artifacts print-settings commands.""" from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals import sys import textwrap from googlecloudsdk.api_lib.artifacts import exceptions as ar_exceptions from googlecloudsdk.calliope import actions from googlecloudsdk.calliope import arg_parsers from googlecloudsdk.calliope import base from googlecloudsdk.calliope.concepts import concepts from googlecloudsdk.calliope.concepts import deps from googlecloudsdk.command_lib.util.concepts import concept_parsers from googlecloudsdk.core import properties _PACKAGE_TYPE_CHOICES = { 'MAVEN': 'Maven package.', 'GO': 'Go standard library and third party packages.', 'NPM': 'NPM package.', 'PYTHON': 'Python package.', 'RUST': 'Rust package.', 'RUBYGEMS': 'RubyGems package.', 'COMPOSER': 'PHP Composer package.', 'NUGET': 'NuGet package.', } _EXPERIMENTAL_PACKAGE_TYPE_CHOICES = {} def RepoAttributeConfig(): fts = [deps.PropertyFallthrough(properties.VALUES.artifacts.repository)] return concepts.ResourceParameterAttributeConfig( name='repository', help_text='Repository of the {resource}.', fallthroughs=fts) def LocationAttributeConfig(): fts = [deps.PropertyFallthrough(properties.VALUES.artifacts.location)] return concepts.ResourceParameterAttributeConfig( name='location', help_text='Location of the {resource}.', fallthroughs=fts) def PackageAttributeConfig(): return concepts.ResourceParameterAttributeConfig( name='package', help_text='Package of the {resource}.') def GetRepoResourceSpec(): return concepts.ResourceSpec( 'artifactregistry.projects.locations.repositories', resource_name='repository', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, locationsId=LocationAttributeConfig(), repositoriesId=RepoAttributeConfig()) def GetBetaRepoResourceSpec(): return concepts.ResourceSpec( 'artifactregistry.projects.locations.repositories', resource_name='repository', api_version='v1beta1', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, locationsId=LocationAttributeConfig(), repositoriesId=RepoAttributeConfig()) def GetLocationResourceSpec(): return concepts.ResourceSpec( 'artifactregistry.projects.locations', resource_name='location', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, locationsId=LocationAttributeConfig()) def GetFileResourceSpec(): return concepts.ResourceSpec( 'artifactregistry.projects.locations.repositories.files', resource_name='file', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, locationsId=LocationAttributeConfig(), repositoriesId=RepoAttributeConfig()) def GetAttachmentResourceSpec(): return concepts.ResourceSpec( 'artifactregistry.projects.locations.repositories.attachments', resource_name='attachment', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, locationsId=LocationAttributeConfig(), repositoriesId=RepoAttributeConfig(), ) def GetPackageResourceSpec(): return concepts.ResourceSpec( 'artifactregistry.projects.locations.repositories.packages', resource_name='package', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, locationsId=LocationAttributeConfig(), repositoriesId=RepoAttributeConfig(), ) def GetVersionResourceSpec(): return concepts.ResourceSpec( 'artifactregistry.projects.locations.repositories.packages.versions', resource_name='version', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, locationsId=LocationAttributeConfig(), repositoriesId=RepoAttributeConfig(), packagesId=PackageAttributeConfig(), ) def GetTagResourceSpec(): return concepts.ResourceSpec( 'artifactregistry.projects.locations.repositories.packages.tags', resource_name='tag', projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG, locationsId=LocationAttributeConfig(), repositoriesId=RepoAttributeConfig(), packagesId=PackageAttributeConfig(), ) def GetScopeFlag(): return base.Argument( '--scope', help=('The scope to associate with the Artifact Registry registry. ' 'If not specified, Artifact Registry is set as the default ' 'registry.')) def GetImagePathOptionalArg(): """Gets IMAGE_PATH optional positional argument.""" help_txt = textwrap.dedent("""\ An Artifact Registry repository or a container image. If not specified, default config values are used. A valid docker repository has the format of LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY-ID A valid image has the format of LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY-ID/IMAGE_PATH """) return base.Argument('IMAGE_PATH', help=help_txt, nargs='?') def GetImageRequiredArg(): """Gets IMAGE required positional argument.""" help_txt = textwrap.dedent("""\ A container image. A valid container image has the format of LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY-ID/IMAGE A valid container image that can be referenced by tag or digest, has the format of LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY-ID/IMAGE:tag LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY-ID/IMAGE@sha256:digest """) return base.Argument('IMAGE', help=help_txt) def GetDockerImageRequiredArg(): help_txt = textwrap.dedent("""\ Docker image - The container image that you want to tag. A valid container image can be referenced by tag or digest, has the format of LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY-ID/IMAGE:tag LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY-ID/IMAGE@sha256:digest """) return base.Argument('DOCKER_IMAGE', help=help_txt) def GetTagRequiredArg(): help_txt = textwrap.dedent("""\ Image tag - The container image tag. A valid Docker tag has the format of LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY-ID/IMAGE:tag """) return base.Argument('DOCKER_TAG', help=help_txt) def GetRepoFlag(): return concept_parsers.ConceptParser.ForResource( '--repository', GetRepoResourceSpec(), ('The Artifact Registry repository. If not specified, ' 'the current artifacts/repository is used.'), required=False) def GetRequiredRepoFlag(): return concept_parsers.ConceptParser.ForResource( '--repository', GetRepoResourceSpec(), ('The Artifact Registry repository. If not specified, ' 'the current artifacts/repository is used.'), required=True) def GetLocationFlag(): return concept_parsers.ConceptParser.ForResource( '--location', GetLocationResourceSpec(), ('The Artifact Registry repository location. If not specified, ' 'the current artifacts/location is used.'), required=True) def GetRequiredFileFlag(): return concept_parsers.ConceptParser.ForResource( 'file', GetFileResourceSpec(), 'The Artifact Registry file name.', required=True, ) def GetRequiredAttachmentFlag(): return concept_parsers.ConceptParser.ForResource( 'attachment', GetAttachmentResourceSpec(), 'The Artifact Registry attachment name.', required=True, ) def GetOptionalAttachmentFlag(): return concept_parsers.ConceptParser.ForResource( 'attachment', GetAttachmentResourceSpec(), 'The Artifact Registry attachment name.', required=False, ) def GetRequiredVersionFlag(): return concept_parsers.ConceptParser.ForResource( 'version', GetVersionResourceSpec(), 'The Artifact Registry version name.', required=True, ) def GetRequiredTagFlag(): return concept_parsers.ConceptParser.ForResource( 'tag', GetTagResourceSpec(), 'The Artifact Registry tag name.', required=True, ) def GetAllowOverwriteFlag(): return base.Argument( '--allow-overwrite', action='store_true', default=False, help='If specified, the command overwrites an existing file', ) def GetRepoArg(): return concept_parsers.ConceptParser.ForResource( 'repository', GetRepoResourceSpec(), ('The Artifact Registry repository. If not specified, ' 'the current artifacts/repository is used.'), required=True) def GetRepoArgFromBeta(): return concept_parsers.ConceptParser.ForResource( 'repository', GetBetaRepoResourceSpec(), ('The Artifact Registry repository. If not specified, ' 'the current artifacts/repository is used.'), required=True) def GetOptionalLocationFlag(): return concept_parsers.ConceptParser.ForResource( '--location', GetLocationResourceSpec(), ('The Artifact Registry repository location. You can also set ' '--location=all to list repositories across all locations. ' 'If you omit this flag, the default location is used if you set the ' 'artifacts/location property. Otherwise, omitting this flag ' 'lists repositories across all locations.'), required=False) def GetOptionalAALocationFlag(): return base.Argument( '--location', help=('If specified, all requests to Artifact Analysis for occurrences' ' will go to location specified'), required=False, ) def GetIncludeTagsFlag(): return base.Argument( '--include-tags', help=( 'If specified, tags associated with each image digest are displayed' ' up to a maximum of 100 tags per version.' ), action='store_true', required=False, ) def GetDeleteTagsFlag(): return base.Argument( '--delete-tags', help='If specified, all tags associated with the image are deleted.', action='store_true', required=False) def GetGCRDomainArg(): return base.Argument( 'DOMAIN', help=( 'A Container Registry domain. Valid values are: [gcr.io, asia.gcr.io,' ' eu.gcr.io, us.gcr.io]' ), ) def GetJsonKeyFlag(tool): """Gets Json Key Flag text based on specified tool.""" if tool == 'pypi' or tool == 'python': return base.Argument( '--json-key', help=('Path to service account JSON key. If not specified, ' 'output returns either credentials for an active service account ' 'or a placeholder for the current user account.')) elif tool in ('gradle', 'maven', 'npm'): return base.Argument( '--json-key', help=('Path to service account JSON key. If not specified, ' 'current active service account credentials or a placeholder for ' 'gcloud credentials is used.')) else: raise ar_exceptions.ArtifactRegistryError( 'Invalid tool type: {}'.format(tool)) def GetShowAllMetadataFlag(): return base.Argument( '--show-all-metadata', action='store_true', help='Include all metadata in the output. Metadata will be grouped by ' 'Grafeas kind, with an additional section for intoto provenance ' 'metadata.') def GetShowDeploymentFlag(): return base.Argument( '--show-deployment', action='store_true', help='Include deployment metadata in the output.') def GetShowImageBasisFlag(): return base.Argument( '--show-image-basis', action='store_true', help='Include base image metadata in the output.') def GetShowPackageVulnerabilityFlag(): return base.Argument( '--show-package-vulnerability', action='store_true', help='Include vulnerability metadata in the output.') def GetShowBuildDetailsFlag(): return base.Argument( '--show-build-details', action='store_true', help='Include build metadata in the output.') def GetShowSbomReferencesFlag(): return base.Argument( '--show-sbom-references', action='store_true', help='Include SBOM metadata in the output.') def GetMetadataFilterFlag(): return base.Argument( '--metadata-filter', help=('Additional filter to fetch metadata for a given ' 'qualified image reference.')) def GetShowOccurrencesFlag(): return base.Argument( '--show-occurrences', action='store_true', help='Show summaries of the various occurrence types.') def GetShowOccurrencesFromFlag(): return base.Argument( '--show-occurrences-from', type=arg_parsers.BoundedInt(1, sys.maxsize, unlimited=True), default=10, help=('The number of the most recent images for which to ' 'summarize occurrences.')) def GetOccurrenceFilterFlag(): return base.Argument( '--occurrence-filter', default=( 'kind="BUILD" OR kind="IMAGE" OR kind="DISCOVERY" OR' ' kind="SBOM_REFERENCE"' ), help='A filter for the occurrences which will be summarized.') def GetVulnerabilitiesOccurrenceFilterFlag(): return base.Argument( '--occurrence-filter', help='A filter for the occurrences which will be summarized. See link for ' 'officially supported filters: ' 'https://cloud.google.com/container-analysis/docs/os-scanning-automatically#filtering') def GetShowProvenanceFlag(): return base.Argument( '--show-provenance', action='store_true', help='Include intoto provenance metadata in the output, in the ' 'provenance_summary section. To see all build metadata in the output, ' 'use --show-all-metadata or --show-build-details.') def GetResourceURIArg(): """Gets RESOURCE_URI required positional argument.""" return base.Argument( 'RESOURCE_URI', help=('A container image in a Google Cloud registry (Artifact Registry ' 'or Container Registry), or a local container image.')) def GetListURIArg(): """Gets list uri required positional argument.""" return base.Argument( 'URI', help=('An URI identifying a container image or package in ' 'Artifact Registry or Google Cloud Registry.')) def GetRemoteFlag(): return base.Argument( '--remote', action='store_true', default=False, help=('Whether the container image is located remotely or ' 'on your local machine.')) def GetOnDemandScanningLocationFlag(): return base.Argument( '--location', choices={ 'us': 'Perform analysis in the US', 'europe': 'Perform analysis in Europe', 'asia': 'Perform analysis in Asia', }, default='us', help=('The API location in which to perform package analysis. Consider ' 'choosing a location closest to where you are located. Proximity ' 'to the container image does not affect response time.')) def GetOnDemandScanningFakeExtractionFlag(): return base.Argument( '--fake-extraction', action='store_true', default=False, hidden=True, help=('Whether to use fake packages/versions instead of performing ' 'extraction. This flag is for test purposes only.')) def GetAdditionalPackageTypesFlag(): return base.Argument( '--additional-package-types', action=actions.DeprecationAction( '--additional-package-types', warn=( 'This flag is deprecated as scanning for all package types is ' 'now the default. To skip scanning for specific package types, ' 'use --skip-package-types.' ), ), type=arg_parsers.ArgList( choices=_PACKAGE_TYPE_CHOICES, element_type=lambda package_type: package_type.upper(), ), metavar='ADDITIONAL_PACKAGE_TYPES', help=( 'A comma-separated list of package types to scan in addition to OS' ' packages.' ), ) def GetExperimentalPackageTypesFlag(): return base.Argument( '--experimental-package-types', action=actions.DeprecationAction( '--experimental-package-types', warn=( 'This flag is deprecated as scanning for all package types is ' 'now the default. To skip scanning for specific package types, ' 'use --skip-package-types.' ), ), type=arg_parsers.ArgList( choices=_EXPERIMENTAL_PACKAGE_TYPE_CHOICES, element_type=lambda package_type: package_type.upper(), ), hidden=True, metavar='EXPERIMENTAL_PACKAGE_TYPES', help=( 'A comma-separated list of experimental package types to scan in' ' addition to OS packages and officially supported third party' ' packages.' ), ) def GetSkipPackageTypesFlag(): return base.Argument( '--skip-package-types', type=arg_parsers.ArgList( choices=_PACKAGE_TYPE_CHOICES, element_type=lambda package_type: package_type.upper(), ), metavar='SKIP_PACKAGE_TYPES', help='A comma-separated list of package types to skip when scanning.', ) def GetVerboseErrorsFlag(): return base.Argument( '--verbose-errors', action='store_true', default=False, hidden=True, help=('Log internal errors.')) def GetSkipExistingFlag(): return base.Argument( '--skip-existing', action='store_true', default=False, help=( 'If specified, skip uploading files that already exist in the' ' repository, and continue to upload the remaining files.' ), ) def GetChunkSize(): return base.Argument( '--chunk-size', help=( 'If specified, the chunk size (bytes) to use for downloading the' ' package.' ), ) def GetPlainRepoFlag(): """Gets a simple --repository flag.""" return base.Argument( '--repository', help=( 'The Artifact Registry repository. If not specified, the current' ' artifacts/repository is used.' ), ) def GetPlainLocationFlag(): """Gets a simple --location flag.""" return base.Argument( '--location', help=( 'The Artifact Registry repository location. If not specified, the' ' current artifacts/location is used.' ), ) def GetSeverityFlag(): """Gets the --severity flag for platform logs.""" return base.Argument( '--severity', type=lambda x: x.upper(), # Ensure value is uppercase for enum choices=[ 'INFO', 'ERROR', ], help=( 'The minimum severity level of logs to generate. This flag is only ' 'applicable when using --enable. Values are case-insensitive.' 'If omitted when --enable is true, it defaults to logging all ' 'severities.' ), )