cloudsmith-cli 1.20.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. cloudsmith_cli/__init__.py +10 -0
  2. cloudsmith_cli/__main__.py +8 -0
  3. cloudsmith_cli/cli/__init__.py +1 -0
  4. cloudsmith_cli/cli/command.py +160 -0
  5. cloudsmith_cli/cli/commands/__init__.py +33 -0
  6. cloudsmith_cli/cli/commands/auth.py +173 -0
  7. cloudsmith_cli/cli/commands/check.py +129 -0
  8. cloudsmith_cli/cli/commands/copy.py +98 -0
  9. cloudsmith_cli/cli/commands/credential_helper/__init__.py +39 -0
  10. cloudsmith_cli/cli/commands/credential_helper/docker.py +66 -0
  11. cloudsmith_cli/cli/commands/credential_helper/manage.py +299 -0
  12. cloudsmith_cli/cli/commands/delete.py +67 -0
  13. cloudsmith_cli/cli/commands/dependencies.py +108 -0
  14. cloudsmith_cli/cli/commands/docs.py +16 -0
  15. cloudsmith_cli/cli/commands/download.py +620 -0
  16. cloudsmith_cli/cli/commands/entitlements.py +819 -0
  17. cloudsmith_cli/cli/commands/help_.py +12 -0
  18. cloudsmith_cli/cli/commands/list_.py +317 -0
  19. cloudsmith_cli/cli/commands/login.py +99 -0
  20. cloudsmith_cli/cli/commands/logout.py +151 -0
  21. cloudsmith_cli/cli/commands/main.py +73 -0
  22. cloudsmith_cli/cli/commands/mcp.py +523 -0
  23. cloudsmith_cli/cli/commands/metadata.py +503 -0
  24. cloudsmith_cli/cli/commands/metrics/__init__.py +2 -0
  25. cloudsmith_cli/cli/commands/metrics/command.py +20 -0
  26. cloudsmith_cli/cli/commands/metrics/entitlements.py +148 -0
  27. cloudsmith_cli/cli/commands/metrics/packages.py +134 -0
  28. cloudsmith_cli/cli/commands/move.py +111 -0
  29. cloudsmith_cli/cli/commands/policy/__init__.py +3 -0
  30. cloudsmith_cli/cli/commands/policy/command.py +20 -0
  31. cloudsmith_cli/cli/commands/policy/deny.py +248 -0
  32. cloudsmith_cli/cli/commands/policy/license.py +335 -0
  33. cloudsmith_cli/cli/commands/policy/vulnerability.py +322 -0
  34. cloudsmith_cli/cli/commands/push.py +1323 -0
  35. cloudsmith_cli/cli/commands/quarantine.py +148 -0
  36. cloudsmith_cli/cli/commands/quota/__init__.py +2 -0
  37. cloudsmith_cli/cli/commands/quota/command.py +20 -0
  38. cloudsmith_cli/cli/commands/quota/history.py +122 -0
  39. cloudsmith_cli/cli/commands/quota/quota.py +107 -0
  40. cloudsmith_cli/cli/commands/repos.py +330 -0
  41. cloudsmith_cli/cli/commands/resync.py +90 -0
  42. cloudsmith_cli/cli/commands/status.py +92 -0
  43. cloudsmith_cli/cli/commands/tags.py +375 -0
  44. cloudsmith_cli/cli/commands/tokens.py +318 -0
  45. cloudsmith_cli/cli/commands/upstream.py +479 -0
  46. cloudsmith_cli/cli/commands/vulnerabilities.py +141 -0
  47. cloudsmith_cli/cli/commands/whoami.py +188 -0
  48. cloudsmith_cli/cli/config.py +635 -0
  49. cloudsmith_cli/cli/decorators.py +624 -0
  50. cloudsmith_cli/cli/exceptions.py +215 -0
  51. cloudsmith_cli/cli/metadata_common.py +146 -0
  52. cloudsmith_cli/cli/saml.py +109 -0
  53. cloudsmith_cli/cli/table.py +59 -0
  54. cloudsmith_cli/cli/types.py +14 -0
  55. cloudsmith_cli/cli/utils.py +267 -0
  56. cloudsmith_cli/cli/validators.py +378 -0
  57. cloudsmith_cli/cli/webserver.py +263 -0
  58. cloudsmith_cli/core/__init__.py +1 -0
  59. cloudsmith_cli/core/api/__init__.py +1 -0
  60. cloudsmith_cli/core/api/distros.py +31 -0
  61. cloudsmith_cli/core/api/entitlements.py +130 -0
  62. cloudsmith_cli/core/api/exceptions.py +57 -0
  63. cloudsmith_cli/core/api/files.py +131 -0
  64. cloudsmith_cli/core/api/init.py +109 -0
  65. cloudsmith_cli/core/api/metadata.py +217 -0
  66. cloudsmith_cli/core/api/metrics.py +78 -0
  67. cloudsmith_cli/core/api/orgs.py +201 -0
  68. cloudsmith_cli/core/api/packages.py +309 -0
  69. cloudsmith_cli/core/api/quota.py +64 -0
  70. cloudsmith_cli/core/api/rates.py +28 -0
  71. cloudsmith_cli/core/api/repos.py +81 -0
  72. cloudsmith_cli/core/api/status.py +27 -0
  73. cloudsmith_cli/core/api/upstreams.py +72 -0
  74. cloudsmith_cli/core/api/user.py +109 -0
  75. cloudsmith_cli/core/api/version.py +15 -0
  76. cloudsmith_cli/core/api/vulnerabilities.py +230 -0
  77. cloudsmith_cli/core/cache_utils.py +160 -0
  78. cloudsmith_cli/core/config.py +140 -0
  79. cloudsmith_cli/core/credentials/__init__.py +0 -0
  80. cloudsmith_cli/core/credentials/chain.py +69 -0
  81. cloudsmith_cli/core/credentials/models.py +44 -0
  82. cloudsmith_cli/core/credentials/oidc/__init__.py +6 -0
  83. cloudsmith_cli/core/credentials/oidc/cache.py +220 -0
  84. cloudsmith_cli/core/credentials/oidc/detectors/__init__.py +122 -0
  85. cloudsmith_cli/core/credentials/oidc/detectors/aws.py +85 -0
  86. cloudsmith_cli/core/credentials/oidc/detectors/azure_devops.py +70 -0
  87. cloudsmith_cli/core/credentials/oidc/detectors/base.py +26 -0
  88. cloudsmith_cli/core/credentials/oidc/detectors/bitbucket_pipelines.py +35 -0
  89. cloudsmith_cli/core/credentials/oidc/detectors/circleci.py +40 -0
  90. cloudsmith_cli/core/credentials/oidc/detectors/generic.py +42 -0
  91. cloudsmith_cli/core/credentials/oidc/detectors/github_actions.py +64 -0
  92. cloudsmith_cli/core/credentials/oidc/detectors/gitlab_ci.py +49 -0
  93. cloudsmith_cli/core/credentials/oidc/exchange.py +87 -0
  94. cloudsmith_cli/core/credentials/provider.py +17 -0
  95. cloudsmith_cli/core/credentials/providers/__init__.py +15 -0
  96. cloudsmith_cli/core/credentials/providers/cli_flag.py +24 -0
  97. cloudsmith_cli/core/credentials/providers/credentials_file.py +24 -0
  98. cloudsmith_cli/core/credentials/providers/env_var.py +24 -0
  99. cloudsmith_cli/core/credentials/providers/keyring_provider.py +59 -0
  100. cloudsmith_cli/core/credentials/providers/oidc_provider.py +115 -0
  101. cloudsmith_cli/core/download.py +594 -0
  102. cloudsmith_cli/core/keyring.py +171 -0
  103. cloudsmith_cli/core/mcp/__init__.py +0 -0
  104. cloudsmith_cli/core/mcp/data.py +17 -0
  105. cloudsmith_cli/core/mcp/server.py +786 -0
  106. cloudsmith_cli/core/pagination.py +131 -0
  107. cloudsmith_cli/core/ratelimits.py +88 -0
  108. cloudsmith_cli/core/rest.py +255 -0
  109. cloudsmith_cli/core/utils.py +95 -0
  110. cloudsmith_cli/core/version.py +20 -0
  111. cloudsmith_cli/credential_helpers/__init__.py +7 -0
  112. cloudsmith_cli/credential_helpers/backends.py +41 -0
  113. cloudsmith_cli/credential_helpers/common.py +111 -0
  114. cloudsmith_cli/credential_helpers/custom_domains.py +281 -0
  115. cloudsmith_cli/credential_helpers/docker/__init__.py +4 -0
  116. cloudsmith_cli/credential_helpers/docker/installer.py +349 -0
  117. cloudsmith_cli/credential_helpers/docker/runtime.py +117 -0
  118. cloudsmith_cli/credential_helpers/launchers.py +175 -0
  119. cloudsmith_cli/data/VERSION +1 -0
  120. cloudsmith_cli/data/config.ini +23 -0
  121. cloudsmith_cli/data/credentials.ini +14 -0
  122. cloudsmith_cli/templates/__init__.py +3 -0
  123. cloudsmith_cli/templates/auth_error.html +45 -0
  124. cloudsmith_cli/templates/auth_success.html +37 -0
  125. cloudsmith_cli-1.20.0.dist-info/METADATA +610 -0
  126. cloudsmith_cli-1.20.0.dist-info/RECORD +130 -0
  127. cloudsmith_cli-1.20.0.dist-info/WHEEL +5 -0
  128. cloudsmith_cli-1.20.0.dist-info/entry_points.txt +2 -0
  129. cloudsmith_cli-1.20.0.dist-info/licenses/LICENSE +201 -0
  130. cloudsmith_cli-1.20.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,134 @@
1
+ """CLI/Commands - retrieve metrics."""
2
+
3
+ import click
4
+
5
+ from ....core.api import metrics as api
6
+ from ... import decorators, utils, validators
7
+ from ...exceptions import handle_api_exceptions
8
+ from ...utils import maybe_spinner
9
+ from .command import metrics
10
+
11
+
12
+ def _print_activity_table(opts, data):
13
+ """Print token activity as a table."""
14
+ utils.pretty_print_table(
15
+ headers=["Active", "Inactive", "Total"],
16
+ rows=[
17
+ [
18
+ click.style(str(getattr(data, k, 0)), fg="green")
19
+ for k in ("active", "inactive", "total")
20
+ ]
21
+ ],
22
+ title="Activity Summary (Active = Has Downloads)",
23
+ )
24
+
25
+ click.echo()
26
+
27
+
28
+ def _print_metrics_table(opts, data):
29
+ """Print metrics as a table."""
30
+ category_keys = {"Bandwidth": "bandwidth", "Downloads": "downloads"}
31
+
32
+ metrics_keys = {
33
+ "Average": "average",
34
+ "Lowest": "lowest",
35
+ "Highest": "highest",
36
+ "Total": "total",
37
+ }
38
+
39
+ headers = ["Metric"]
40
+ headers.extend(metrics_keys.keys())
41
+ rows = []
42
+
43
+ for category_header, category_key in category_keys.items():
44
+ category_data = getattr(data, category_key)
45
+ cols = [category_header]
46
+ for metric_key in metrics_keys.values():
47
+ metric_data = getattr(category_data, metric_key, {})
48
+ if hasattr(metric_data, "display"):
49
+ value = getattr(metric_data, "display")
50
+ else:
51
+ value = getattr(metric_data, "value")
52
+ value = str(value or 0)
53
+ cols.append(click.style(value, fg="green"))
54
+ rows.append(cols)
55
+
56
+ utils.pretty_print_table(headers=headers, rows=rows, title="Entitlement Metrics")
57
+
58
+ click.echo()
59
+
60
+
61
+ @metrics.command(name="packages", aliases=["pkgs"])
62
+ @decorators.common_cli_config_options
63
+ @decorators.common_cli_output_options
64
+ @decorators.common_api_auth_options
65
+ @decorators.initialise_api
66
+ @click.argument(
67
+ "owner_repo",
68
+ metavar="OWNER/REPO",
69
+ callback=validators.validate_owner_repo,
70
+ required=True,
71
+ )
72
+ @click.option(
73
+ "--packages",
74
+ type=str,
75
+ required=False,
76
+ help=(
77
+ "A comma separated list of package identifiers (i.e. slug_perm). "
78
+ "If a list is not specified then all package will be included for "
79
+ "a given repository."
80
+ ),
81
+ )
82
+ @click.option(
83
+ "--start",
84
+ type=str,
85
+ required=False,
86
+ help=(
87
+ "Include metrics from and including this UTC date or UTC datetime. "
88
+ "For example '2020-12-31' or '2021-12-13T00:00:00Z'."
89
+ ),
90
+ )
91
+ @click.option(
92
+ "--finish",
93
+ type=str,
94
+ required=False,
95
+ help=(
96
+ "Include metrics up to and including this UTC date or UTC datetime. "
97
+ "For example '2020-12-31' or '2021-12-13T00:00:00Z'."
98
+ ),
99
+ )
100
+ @click.pass_context
101
+ def usage(ctx, opts, owner_repo, packages, start, finish):
102
+ """
103
+ Retrieve package usage metrics.
104
+
105
+ OWNER/REPO: Specify the OWNER namespace (i.e user or org) and repository to retrieve the
106
+ metrics for that namespace/repository combination.
107
+ """
108
+ # Use stderr for messages if the output is something else (e.g. # JSON)
109
+ use_stderr = utils.should_use_stderr(opts)
110
+
111
+ click.echo("Getting usage metrics ... ", nl=False, err=use_stderr)
112
+
113
+ owner = None
114
+ repo = None
115
+ # owner/repo are required arguments
116
+ if isinstance(owner_repo, list) and len(owner_repo) == 2:
117
+ owner, repo = owner_repo
118
+
119
+ context_msg = "Failed to get list of metrics!"
120
+ with handle_api_exceptions(ctx, opts=opts, context_msg=context_msg):
121
+ with maybe_spinner(opts):
122
+ data = api.get_repository_packages_metrics(
123
+ owner=owner, repo=repo, packages=packages, start=start, finish=finish
124
+ )
125
+
126
+ click.secho("OK", fg="green", err=use_stderr)
127
+
128
+ if utils.maybe_print_as_json(opts, data):
129
+ return
130
+
131
+ click.echo()
132
+
133
+ _print_activity_table(opts, data)
134
+ _print_metrics_table(opts, data)
@@ -0,0 +1,111 @@
1
+ """CLI/Commands - List objects."""
2
+
3
+ import click
4
+
5
+ from ...core.api.packages import move_package
6
+ from .. import decorators, utils, validators
7
+ from ..exceptions import handle_api_exceptions
8
+ from ..utils import maybe_spinner
9
+ from .main import main
10
+ from .push import wait_for_package_sync
11
+
12
+
13
+ @main.command(aliases=["mv", "promote"])
14
+ @decorators.common_cli_config_options
15
+ @decorators.common_cli_output_options
16
+ @decorators.common_package_action_options
17
+ @decorators.common_api_auth_options
18
+ @decorators.initialise_api
19
+ @click.argument(
20
+ "owner_repo_package",
21
+ metavar="OWNER/REPO/PACKAGE",
22
+ callback=validators.validate_owner_repo_package,
23
+ )
24
+ @click.argument("destination", metavar="DEST")
25
+ @click.option(
26
+ "-y",
27
+ "--yes",
28
+ default=False,
29
+ is_flag=True,
30
+ help="Assume yes as default answer to questions (this is dangerous!)",
31
+ )
32
+ @click.pass_context
33
+ def move(
34
+ ctx,
35
+ opts,
36
+ owner_repo_package,
37
+ destination,
38
+ skip_errors,
39
+ wait_interval,
40
+ no_wait_for_sync,
41
+ sync_attempts,
42
+ yes,
43
+ ):
44
+ """
45
+ Move (promote) a package to another repo.
46
+
47
+ This requires appropriate permissions for both the source
48
+ repository/package and the destination repository.
49
+
50
+ - OWNER/REPO/PACKAGE: Specify the OWNER namespace (i.e. user or org), the
51
+ REPO name where the package is stored, and the PACKAGE name (slug) of the
52
+ package itself. All separated by a slash.
53
+
54
+ Example: 'your-org/awesome-repo/better-pkg'.
55
+
56
+ - DEST: Specify the DEST (destination) repository to move the package to.
57
+ This *must* be in the same namespace as the source repository.
58
+
59
+ Example: 'other-repo'
60
+
61
+ Full CLI example:
62
+
63
+ $ cloudsmith mv your-org/awesome-repo/better-pkg other-repo
64
+ """
65
+ owner, source, slug = owner_repo_package
66
+
67
+ move_args = {
68
+ "slug": click.style(slug, bold=True),
69
+ "source": click.style(source, bold=True),
70
+ "dest": click.style(destination, bold=True),
71
+ }
72
+
73
+ use_stderr = utils.should_use_stderr(opts)
74
+
75
+ prompt = "move the %(slug)s from %(source)s to %(dest)s" % move_args
76
+ if not utils.confirm_operation(prompt, assume_yes=yes, err=use_stderr):
77
+ return
78
+
79
+ click.echo(
80
+ "Moving %(slug)s package from %(source)s to %(dest)s ... " % move_args,
81
+ nl=False,
82
+ err=use_stderr,
83
+ )
84
+
85
+ context_msg = "Failed to move package!"
86
+ with handle_api_exceptions(
87
+ ctx, opts=opts, context_msg=context_msg, reraise_on_error=skip_errors
88
+ ):
89
+ with maybe_spinner(opts):
90
+ _, new_slug = move_package(
91
+ owner=owner, repo=source, identifier=slug, destination=destination
92
+ )
93
+
94
+ click.secho("OK", fg="green", err=use_stderr)
95
+
96
+ if no_wait_for_sync:
97
+ utils.maybe_print_status_json(opts, {"slug": new_slug, "status": "OK"})
98
+ return
99
+
100
+ wait_for_package_sync(
101
+ ctx=ctx,
102
+ opts=opts,
103
+ owner=owner,
104
+ repo=destination,
105
+ slug=new_slug,
106
+ wait_interval=wait_interval,
107
+ skip_errors=skip_errors,
108
+ attempts=sync_attempts,
109
+ )
110
+
111
+ utils.maybe_print_status_json(opts, {"slug": new_slug, "status": "OK"})
@@ -0,0 +1,3 @@
1
+ from .deny import deny_policy as policy_deny
2
+ from .license import licence as policy_license
3
+ from .vulnerability import vulnerability as policy_vulnerability
@@ -0,0 +1,20 @@
1
+ """CLI/Commands - Import all policy commands."""
2
+
3
+ import click
4
+
5
+ from ... import command, decorators
6
+ from ..main import main
7
+
8
+
9
+ @main.group(cls=command.AliasGroup, name="policy", aliases=[])
10
+ @decorators.common_cli_config_options
11
+ @decorators.common_cli_output_options
12
+ @decorators.common_api_auth_options
13
+ @decorators.initialise_api
14
+ @click.pass_context
15
+ def policy(ctx, opts): # pylink: disable=unused-argument
16
+ """
17
+ Manage policies for an organization.
18
+
19
+ See the help for subcommands for more information on each.
20
+ """
@@ -0,0 +1,248 @@
1
+ """Commands for deny policies."""
2
+
3
+ import click
4
+
5
+ from ....core.api import orgs
6
+ from ....core.pagination import paginate_results
7
+ from ... import command, decorators, utils
8
+ from ...exceptions import handle_api_exceptions
9
+ from ...utils import fmt_datetime, maybe_spinner
10
+ from .command import policy
11
+
12
+
13
+ def print_deny_policies(policies):
14
+ """Print deny policies as a table."""
15
+ headers = [
16
+ "Name",
17
+ "Description",
18
+ "Package Query",
19
+ "Enabled",
20
+ "Created",
21
+ "Updated",
22
+ "Identifier",
23
+ ]
24
+
25
+ rows = [
26
+ [
27
+ click.style(policy["name"], fg="cyan"),
28
+ click.style(policy["description"], fg="yellow"),
29
+ click.style(policy.get("package_query_string", ""), fg="yellow"),
30
+ click.style(
31
+ "Yes" if policy.get("enabled") else "No",
32
+ fg="green" if policy.get("enabled") else "red",
33
+ ),
34
+ click.style(fmt_datetime(policy["created_at"]), fg="blue"),
35
+ click.style(fmt_datetime(policy["updated_at"]), fg="blue"),
36
+ click.style(policy["slug_perm"], fg="green"),
37
+ ]
38
+ for policy in policies
39
+ ]
40
+
41
+ click.echo()
42
+ utils.pretty_print_table(headers, rows)
43
+ click.echo()
44
+
45
+
46
+ @policy.group(cls=command.AliasGroup, name="deny", aliases=[])
47
+ @decorators.common_cli_config_options
48
+ @decorators.common_cli_output_options
49
+ @decorators.common_api_auth_options
50
+ @decorators.initialise_api
51
+ @click.pass_context
52
+ def deny_policy(*args, **kwargs):
53
+ """Manage deny policies for an organization."""
54
+
55
+
56
+ @deny_policy.command(name="list", aliases=["ls"])
57
+ @decorators.common_cli_config_options
58
+ @decorators.common_cli_list_options
59
+ @decorators.common_cli_output_options
60
+ @decorators.common_api_auth_options
61
+ @decorators.initialise_api
62
+ @click.argument("owner")
63
+ @click.pass_context
64
+ def list_deny_policies(ctx, opts, owner, page, page_size, page_all):
65
+ """List deny policies for an organization."""
66
+ use_stderr = utils.should_use_stderr(opts)
67
+ click.echo("Getting deny policies ... ", nl=False, err=use_stderr)
68
+
69
+ context_msg = "Failed to get deny policies!"
70
+ with handle_api_exceptions(ctx, opts=opts, context_msg=context_msg):
71
+ with maybe_spinner(opts):
72
+ data, page_info = paginate_results(
73
+ orgs.list_deny_policies, page_all, page, page_size, owner=owner
74
+ )
75
+
76
+ click.secho("OK", fg="green", err=use_stderr)
77
+
78
+ if utils.maybe_print_as_json(opts, data, page_info):
79
+ return
80
+
81
+ print_deny_policies(data)
82
+
83
+ click.echo()
84
+
85
+ num_results = len(data)
86
+ list_suffix = "deny polic%s" % ("y" if num_results == 1 else "ies")
87
+ utils.pretty_print_list_info(
88
+ num_results=num_results,
89
+ page_info=None if page_all else page_info,
90
+ suffix=list_suffix,
91
+ page_all=page_all,
92
+ )
93
+
94
+
95
+ @deny_policy.command(name="create", aliases=["new"])
96
+ @decorators.common_cli_config_options
97
+ @decorators.common_cli_output_options
98
+ @decorators.common_api_auth_options
99
+ @decorators.initialise_api
100
+ @click.argument("owner")
101
+ @click.argument("policy_config_file", type=click.File("rb"))
102
+ @click.pass_context
103
+ def create_deny_policy(ctx, opts, owner, policy_config_file):
104
+ """Create a deny policy for an organization."""
105
+ import json
106
+
107
+ use_stderr = utils.should_use_stderr(opts)
108
+ policy_config = json.load(policy_config_file)
109
+
110
+ policy_name = policy_config.get("name")
111
+ if not policy_name:
112
+ raise click.BadParameter(
113
+ "Name is required for creating a deny policy.", param="name"
114
+ )
115
+
116
+ click.secho(
117
+ "Creating %(name)s deny policy for the %(owner)s namespace ..."
118
+ % {
119
+ "name": click.style(policy_name, bold=True),
120
+ "owner": click.style(owner, bold=True),
121
+ },
122
+ nl=False,
123
+ err=use_stderr,
124
+ )
125
+
126
+ context_msg = "Failed to create the deny policy!"
127
+ with handle_api_exceptions(ctx, opts=opts, context_msg=context_msg):
128
+ with maybe_spinner(opts):
129
+ data = orgs.create_deny_policy(owner=owner, policy_config=policy_config)
130
+
131
+ click.secho("OK", fg="green", err=use_stderr)
132
+
133
+ if utils.maybe_print_as_json(opts, [data]):
134
+ return
135
+
136
+ print_deny_policies([data])
137
+
138
+
139
+ @deny_policy.command(name="get")
140
+ @decorators.common_cli_config_options
141
+ @decorators.common_cli_output_options
142
+ @decorators.common_api_auth_options
143
+ @decorators.initialise_api
144
+ @click.argument("owner")
145
+ @click.argument("identifier")
146
+ @click.pass_context
147
+ def get_deny_policy(ctx, opts, owner, identifier):
148
+ """Get a deny policy for an organization."""
149
+ use_stderr = utils.should_use_stderr(opts)
150
+ click.echo("Getting deny policy ... ", nl=False, err=use_stderr)
151
+
152
+ context_msg = "Failed to get deny policy!"
153
+ with handle_api_exceptions(ctx, opts=opts, context_msg=context_msg):
154
+ with maybe_spinner(opts):
155
+ data = orgs.get_deny_policy(owner=owner, slug_perm=identifier)
156
+
157
+ click.secho("OK", fg="green", err=use_stderr)
158
+
159
+ if utils.maybe_print_as_json(opts, [data]):
160
+ return
161
+
162
+ print_deny_policies([data])
163
+
164
+
165
+ @deny_policy.command(name="update", aliases=["set"])
166
+ @decorators.common_cli_config_options
167
+ @decorators.common_cli_output_options
168
+ @decorators.common_api_auth_options
169
+ @decorators.initialise_api
170
+ @click.argument("owner")
171
+ @click.argument("identifier")
172
+ @click.argument("policy_config_file", type=click.File("rb"))
173
+ @click.pass_context
174
+ def update_deny_policy(ctx, opts, owner, identifier, policy_config_file):
175
+ """Update a deny policy for an organization."""
176
+ import json
177
+
178
+ use_stderr = utils.should_use_stderr(opts)
179
+ policy_config = json.load(policy_config_file)
180
+
181
+ click.secho(
182
+ "Updating %(identifier)s deny policy in the %(owner)s namespace ..."
183
+ % {
184
+ "identifier": click.style(identifier, bold=True),
185
+ "owner": click.style(owner, bold=True),
186
+ },
187
+ nl=False,
188
+ err=use_stderr,
189
+ )
190
+
191
+ context_msg = "Failed to update the deny policy!"
192
+ with handle_api_exceptions(ctx, opts=opts, context_msg=context_msg):
193
+ with maybe_spinner(opts):
194
+ data = orgs.update_deny_policy(
195
+ owner=owner, slug_perm=identifier, policy_config=policy_config
196
+ )
197
+
198
+ click.secho("OK", fg="green", err=use_stderr)
199
+
200
+ if utils.maybe_print_as_json(opts, [data]):
201
+ return
202
+
203
+ print_deny_policies([data])
204
+
205
+
206
+ @deny_policy.command(name="delete", aliases=["rm"])
207
+ @decorators.common_cli_config_options
208
+ @decorators.common_cli_output_options
209
+ @decorators.common_api_auth_options
210
+ @decorators.initialise_api
211
+ @click.argument("owner")
212
+ @click.argument("identifier")
213
+ @click.option(
214
+ "-y",
215
+ "--yes",
216
+ default=False,
217
+ is_flag=True,
218
+ help="Assume yes as default answer to questions (this is dangerous!)",
219
+ )
220
+ @click.pass_context
221
+ def delete_deny_policy(ctx, opts, owner, identifier, yes):
222
+ """Delete a deny policy for an organization."""
223
+ delete_args = {
224
+ "namespace": click.style(owner, bold=True),
225
+ "identifier": click.style(identifier, bold=True),
226
+ }
227
+
228
+ prompt = (
229
+ "delete the %(identifier)s deny policy from the %(namespace)s namespace"
230
+ % delete_args
231
+ )
232
+
233
+ use_stderr = utils.should_use_stderr(opts)
234
+ if not utils.confirm_operation(prompt, assume_yes=yes, err=use_stderr):
235
+ return
236
+
237
+ click.secho(
238
+ "Deleting %(identifier)s from the %(namespace)s namespace ... " % delete_args,
239
+ nl=False,
240
+ err=use_stderr,
241
+ )
242
+
243
+ context_msg = "Failed to delete the deny policy!"
244
+ with handle_api_exceptions(ctx, opts=opts, context_msg=context_msg):
245
+ with maybe_spinner(opts):
246
+ orgs.delete_deny_policy(owner=owner, slug_perm=identifier)
247
+
248
+ click.secho("OK", fg="green", err=use_stderr)