From 66165aa17be03d3ea617c1eb2cade7d74139d9be Mon Sep 17 00:00:00 2001 From: James Troup Date: Thu, 20 Aug 2026 03:29:14 +0100 Subject: [PATCH 1/2] chore: gcp(cloud-run) - drop non-schema fields from label mutations --- tools/c7n_gcp/c7n_gcp/resources/cloudrun.py | 59 ++++- ...loud-custodian-locations---services_1.json | 57 +++++ ...ocations-us-central1-services-hello_1.json | 52 +++++ tools/c7n_gcp/tests/test_cloudrun.py | 209 ++++++++++++++++++ 4 files changed, 373 insertions(+), 4 deletions(-) create mode 100644 tools/c7n_gcp/tests/data/flights/gcp-cloud-run-service-mark-for-op/get-v1-projects-cloud-custodian-locations---services_1.json create mode 100644 tools/c7n_gcp/tests/data/flights/gcp-cloud-run-service-mark-for-op/put-v1-projects-cloud-custodian-locations-us-central1-services-hello_1.json diff --git a/tools/c7n_gcp/c7n_gcp/resources/cloudrun.py b/tools/c7n_gcp/c7n_gcp/resources/cloudrun.py index 54f479b60d0..7941f7b746e 100644 --- a/tools/c7n_gcp/c7n_gcp/resources/cloudrun.py +++ b/tools/c7n_gcp/c7n_gcp/resources/cloudrun.py @@ -1,13 +1,64 @@ # Copyright The Cloud Custodian Authors. # SPDX-License-Identifier: Apache-2.0 -import copy - from c7n_gcp.provider import resources from c7n_gcp.query import QueryResourceManager, TypeInfo from c7n_gcp.filters import IamPolicyFilter from c7n_gcp.filters.iampolicy import IamPolicyValueFilter +from c7n.exceptions import PolicyExecutionError from c7n.utils import local_session, jmespath_search +# The only fields the Knative schema defines at the root of a Service or a Job. +KNATIVE_FIELDS = ('apiVersion', 'kind', 'metadata', 'spec', 'status') + +# Prefixes of the annotations c7n keeps on a resource. Only the colon form is +# written to a nested object; the dotted `c7n.metrics` is set at the root alone. +# Nesting matches on the colon form only, because kubernetes annotation keys - +# user controlled, and carried in `metadata.annotations` - may contain a dot but +# never a colon, and this is a whole object replace: a key dropped from the body +# is a key deleted from the service. +C7N_ANNOTATION = 'c7n:' +C7N_ROOT_ANNOTATIONS = (C7N_ANNOTATION, 'c7n.') + + +def _without_annotations(value): + "Copy a value, dropping any c7n annotation held anywhere beneath it." + if isinstance(value, dict): + return {k: _without_annotations(v) for k, v in value.items() + if not k.startswith(C7N_ANNOTATION)} + if isinstance(value, list): + return [_without_annotations(v) for v in value] + # everything else in a decoded api response is an immutable scalar + return value + + +def knative_body(resource): + """Copy a resource into a replace request body, dropping non schema fields. + + Cloud Run replaces the whole object, so the body is the resource itself + rather than a fragment, and the api rejects the request with a 400 on any + field it can't place. A resource carries two kinds it can't: the top level + `labels` key that augment() flattens out of the metadata, and the + annotations the policy's filters leave behind - at the root, and nested + within `spec` when a list-item filter matched on something there. + + A root field that is neither raises rather than being dropped. Under a + whole object replace a field left out of the body is deleted from the + service, so a field this doesn't recognize is one it cannot safely send + or safely omit. + """ + unrecognized = { + k for k in resource + if k not in KNATIVE_FIELDS and k != 'labels' + and not k.startswith(C7N_ROOT_ANNOTATIONS) + } + if unrecognized: + raise PolicyExecutionError( + '%s %s has fields absent from the cloud run schema: %s' % ( + resource.get('kind', 'resource'), + resource.get('metadata', {}).get('name'), + ', '.join(sorted(unrecognized)))) + return {k: _without_annotations(v) for k, v in resource.items() if k in KNATIVE_FIELDS} + @resources.register("cloud-run-service") class CloudRunService(QueryResourceManager): @@ -35,7 +86,7 @@ def get_label_params(resource, all_labels): location = metadata['labels']['cloud.googleapis.com/location'] namespace = metadata['namespace'] svc_name = metadata['name'] - body = copy.deepcopy(resource) + body = knative_body(resource) body['metadata']['labels'] = all_labels return { 'name': 'projects/{}/locations/{}/services/{}'.format( @@ -98,7 +149,7 @@ def get_label_params(resource, all_labels): metadata = resource['metadata'] namespace = metadata['namespace'] job_name = metadata['name'] - body = copy.deepcopy(resource) + body = knative_body(resource) body['metadata']['labels'] = all_labels return { 'name': 'namespaces/{}/jobs/{}'.format(namespace, job_name), diff --git a/tools/c7n_gcp/tests/data/flights/gcp-cloud-run-service-mark-for-op/get-v1-projects-cloud-custodian-locations---services_1.json b/tools/c7n_gcp/tests/data/flights/gcp-cloud-run-service-mark-for-op/get-v1-projects-cloud-custodian-locations---services_1.json new file mode 100644 index 00000000000..998083a29fb --- /dev/null +++ b/tools/c7n_gcp/tests/data/flights/gcp-cloud-run-service-mark-for-op/get-v1-projects-cloud-custodian-locations---services_1.json @@ -0,0 +1,57 @@ +{ + "headers": { + "content-type": "application/json; charset=UTF-8", + "status": "200" + }, + "body": { + "apiVersion": "serving.knative.dev/v1", + "kind": "ServiceList", + "items": [ + { + "apiVersion": "serving.knative.dev/v1", + "kind": "Service", + "metadata": { + "name": "hello", + "namespace": "cloud-custodian", + "selfLink": "/apis/serving.knative.dev/v1/namespaces/cloud-custodian/services/hello", + "uid": "46b28549-6c5c-4245-bc8d-9cec06d262b6", + "resourceVersion": "AAX4MAndusc", + "generation": 1, + "labels": { + "cloud.googleapis.com/location": "us-central1" + }, + "annotations": { + "run.googleapis.com/ingress": "all" + }, + "creationTimestamp": "2023-03-31T10:53:45.882066Z" + }, + "spec": { + "template": { + "metadata": { + "name": "hello-00001-tiv", + "annotations": {} + }, + "spec": { + "containerConcurrency": 80, + "timeoutSeconds": 300, + "containers": [ + { + "image": "us-docker.pkg.dev/cloudrun/container/hello", + "ports": [{"name": "http1", "containerPort": 8080}] + } + ] + } + }, + "traffic": [{"percent": 100, "latestRevision": true}] + }, + "status": { + "observedGeneration": 1, + "conditions": [ + {"type": "Ready", "status": "True"} + ], + "url": "https://hello-g3kdvpt64a-uc.a.run.app" + } + } + ] + } +} diff --git a/tools/c7n_gcp/tests/data/flights/gcp-cloud-run-service-mark-for-op/put-v1-projects-cloud-custodian-locations-us-central1-services-hello_1.json b/tools/c7n_gcp/tests/data/flights/gcp-cloud-run-service-mark-for-op/put-v1-projects-cloud-custodian-locations-us-central1-services-hello_1.json new file mode 100644 index 00000000000..b64a30335e2 --- /dev/null +++ b/tools/c7n_gcp/tests/data/flights/gcp-cloud-run-service-mark-for-op/put-v1-projects-cloud-custodian-locations-us-central1-services-hello_1.json @@ -0,0 +1,52 @@ +{ + "headers": { + "content-type": "application/json; charset=UTF-8", + "status": "200" + }, + "body": { + "apiVersion": "serving.knative.dev/v1", + "kind": "Service", + "metadata": { + "name": "hello", + "namespace": "cloud-custodian", + "selfLink": "/apis/serving.knative.dev/v1/namespaces/cloud-custodian/services/hello", + "uid": "46b28549-6c5c-4245-bc8d-9cec06d262b6", + "resourceVersion": "AAX4MBndusc", + "generation": 2, + "labels": { + "cloud.googleapis.com/location": "us-central1", + "custodian_status": "resource_policy-notify-2026_08_21__0_0" + }, + "annotations": { + "run.googleapis.com/ingress": "all" + }, + "creationTimestamp": "2023-03-31T10:53:45.882066Z" + }, + "spec": { + "template": { + "metadata": { + "name": "hello-00001-tiv", + "annotations": {} + }, + "spec": { + "containerConcurrency": 80, + "timeoutSeconds": 300, + "containers": [ + { + "image": "us-docker.pkg.dev/cloudrun/container/hello", + "ports": [{"name": "http1", "containerPort": 8080}] + } + ] + } + }, + "traffic": [{"percent": 100, "latestRevision": true}] + }, + "status": { + "observedGeneration": 2, + "conditions": [ + {"type": "Ready", "status": "True"} + ], + "url": "https://hello-g3kdvpt64a-uc.a.run.app" + } + } +} diff --git a/tools/c7n_gcp/tests/test_cloudrun.py b/tools/c7n_gcp/tests/test_cloudrun.py index 7483c0c7a95..f4f7061a1ef 100644 --- a/tools/c7n_gcp/tests/test_cloudrun.py +++ b/tools/c7n_gcp/tests/test_cloudrun.py @@ -1,9 +1,153 @@ # Copyright The Cloud Custodian Authors. # SPDX-License-Identifier: Apache-2.0 +import pytest + +from freezegun import freeze_time + from gcp_common import BaseTest +from c7n.exceptions import PolicyExecutionError from c7n.utils import yaml_load +from c7n_gcp.actions.core import MethodAction +from c7n_gcp.resources.cloudrun import CloudRunJob, CloudRunService, knative_body + +# The root fields the api accepts, independent of the module under test. +SCHEMA_FIELDS = {'apiVersion', 'kind', 'metadata', 'spec', 'status'} +LOCATION = {'cloud.googleapis.com/location': 'us-central1'} + + +def listed_resource(api_version, kind, name): + "A resource as augment() and a value filter leave it once listed." + return { + 'apiVersion': api_version, + 'kind': kind, + 'metadata': { + 'name': name, + 'namespace': 'cloud-custodian', + 'labels': dict(LOCATION), + }, + 'spec': {'template': {}}, + 'status': {'observedGeneration': 1}, + 'labels': dict(LOCATION), + 'c7n:MatchedFilters': ['metadata.name'], + } + + +def capture_api_params(test): + """Record the params of every api call the policy's actions make.""" + captured = [] + invoke_api = MethodAction.invoke_api + + def record(action, client, op_name, params): + captured.append((op_name, params)) + return invoke_api(action, client, op_name, params) + + test.patch(MethodAction, 'invoke_api', record) + return captured + + +def assert_replace_body(body, labels): + "A replace body holds the schema fields and the merged labels, nothing else." + assert set(body) == SCHEMA_FIELDS + assert 'labels' not in body + assert 'c7n:MatchedFilters' not in body + assert body['metadata']['labels'] == labels + + +def assert_label_params(model, resource, expected_name): + "get_label_params addresses the resource and leaves it fit to read again." + all_labels = dict(LOCATION, environment='test') + params = model.get_label_params(resource, all_labels) + + assert params['name'] == expected_name + assert_replace_body(params['body'], all_labels) + # the action reads its current label state from the resource, so both the + # synthetic key and the metadata it came from have to survive the call + assert resource['labels'] == LOCATION + assert resource['metadata']['labels'] == LOCATION + + +class KnativeBodyTest(BaseTest): + + def test_keeps_only_the_schema_fields(self): + body = knative_body({ + 'apiVersion': 'serving.knative.dev/v1', + 'kind': 'Service', + 'metadata': {'name': 'hello'}, + 'spec': {}, + 'status': {}, + 'labels': {'env': 'test'}, + 'c7n:MatchedFilters': ['metadata.name'], + }) + assert set(body) == SCHEMA_FIELDS + + def test_drops_annotations_nested_in_spec(self): + # a list-item filter annotates the objects it matched in place + body = knative_body({ + 'metadata': {'name': 'hello'}, + 'spec': { + 'template': { + 'spec': { + 'containers': [{ + 'image': 'us-docker.pkg.dev/cloudrun/container/hello', + 'c7n:MatchedFilters': ['image'], + }], + }, + }, + }, + 'c7n.metrics': {'run.googleapis.com/request_count': []}, + }) + assert body['spec'] == { + 'template': { + 'spec': { + 'containers': [{ + 'image': 'us-docker.pkg.dev/cloudrun/container/hello'}], + }, + }, + } + + def test_keeps_user_annotations(self): + # a kubernetes annotation key may contain a dot, so only the colon form + # is recognized below the root - a replace deletes what the body omits + annotations = { + 'run.googleapis.com/ingress': 'all', + 'c7n.example.com/owner': 'platform-team', + } + body = knative_body({ + 'metadata': {'name': 'hello', 'annotations': dict(annotations)}, + 'spec': {'template': {'metadata': {'annotations': dict(annotations)}}}, + }) + assert body['metadata']['annotations'] == annotations + assert body['spec']['template']['metadata']['annotations'] == annotations + + def test_copies_rather_than_mutates(self): + resource = { + 'metadata': {'name': 'hello'}, + 'spec': {'containers': [{'c7n:MatchedFilters': ['image']}]}, + } + knative_body(resource)['metadata']['name'] = 'changed' + assert resource['metadata']['name'] == 'hello' + assert resource['spec']['containers'][0] == {'c7n:MatchedFilters': ['image']} + + def test_raises_on_fields_outside_the_schema(self): + with pytest.raises(PolicyExecutionError) as raised: + knative_body({ + 'kind': 'Service', + 'metadata': {'name': 'hello'}, + 'somethingNew': 'unrecognized', + }) + assert 'somethingNew' in str(raised.value) + assert 'hello' in str(raised.value) + + def test_accepts_the_synthetic_fields(self): + knative_body({ + 'metadata': {'name': 'hello'}, + 'labels': {'env': 'test'}, + 'c7n:MatchedFilters': ['metadata.name'], + 'c7n.metrics': {'run.googleapis.com/request_count': []}, + }) + class RunServiceTest(BaseTest): def test_query(self): @@ -28,11 +172,18 @@ def test_query_empty(self): resources = p.run() assert resources == [] + def test_label_params(self): + assert_label_params( + CloudRunService.resource_type, + listed_resource('serving.knative.dev/v1', 'Service', 'hello'), + 'projects/cloud-custodian/locations/us-central1/services/hello') + def test_set_labels(self): project_id = 'cloud-custodian' factory = self.replay_flight_data( "gcp-cloud-run-service-set-labels", project_id=project_id ) + captured = capture_api_params(self) p = self.load_policy( { 'name': 'cloud-run-svc-set-labels', @@ -53,6 +204,49 @@ def test_set_labels(self): assert len(resources) == 1 assert resources[0]['metadata']['name'] == 'hello' + assert len(captured) == 1 + op_name, params = captured.pop() + assert op_name == 'replaceService' + assert_replace_body(params['body'], { + 'cloud.googleapis.com/location': 'us-central1', + 'environment': 'test', + }) + + @freeze_time("2026-08-19") + def test_mark_for_op(self): + project_id = 'cloud-custodian' + factory = self.replay_flight_data( + "gcp-cloud-run-service-mark-for-op", project_id=project_id + ) + captured = capture_api_params(self) + p = self.load_policy( + { + 'name': 'cloud-run-svc-mark-for-op', + 'resource': 'gcp.cloud-run-service', + 'filters': [ + {'type': 'value', + 'key': 'metadata.name', + 'value': 'hello'} + ], + 'actions': [ + {'type': 'mark-for-op', + 'op': 'notify', + 'days': 2} + ] + }, + session_factory=factory, + ) + resources = p.run() + assert len(resources) == 1 + + assert len(captured) == 1 + op_name, params = captured.pop() + assert op_name == 'replaceService' + assert_replace_body(params['body'], { + 'cloud.googleapis.com/location': 'us-central1', + 'custodian_status': 'resource_policy-notify-2026_08_21__0_0', + }) + def test_filter(self): factory = self.replay_flight_data("gcp-cloud-run-service") @@ -103,11 +297,18 @@ def test_query(self): assert len(resources) == 1 assert resources[0]["metadata"]["name"] == "job" + def test_label_params(self): + assert_label_params( + CloudRunJob.resource_type, + listed_resource('run.googleapis.com/v1', 'Job', 'job'), + 'namespaces/cloud-custodian/jobs/job') + def test_set_labels(self): project_id = 'cloud-custodian' factory = self.replay_flight_data( "gcp-cloud-run-job-set-labels", project_id=project_id ) + captured = capture_api_params(self) p = self.load_policy( { 'name': 'cloud-run-job-set-labels', @@ -128,6 +329,14 @@ def test_set_labels(self): assert len(resources) == 1 assert resources[0]['metadata']['name'] == 'job' + assert len(captured) == 1 + op_name, params = captured.pop() + assert op_name == 'replaceJob' + assert_replace_body(params['body'], { + 'cloud.googleapis.com/location': 'us-central1', + 'environment': 'test', + }) + class RevisionServiceTest(BaseTest): def test_query(self): From b2a77f1c6bb1a846bba2a9abb5fc2cee53ddc833 Mon Sep 17 00:00:00 2001 From: James Troup Date: Thu, 20 Aug 2026 18:45:57 +0100 Subject: [PATCH 2/2] chore: bump version to post4 --- c7n/version.py | 2 +- pyproject.toml | 2 +- tools/c7n_awscc/pyproject.toml | 2 +- tools/c7n_azure/pyproject.toml | 2 +- tools/c7n_gcp/pyproject.toml | 2 +- tools/c7n_kube/pyproject.toml | 2 +- tools/c7n_left/pyproject.toml | 2 +- tools/c7n_mailer/pyproject.toml | 2 +- tools/c7n_oci/pyproject.toml | 2 +- tools/c7n_openstack/pyproject.toml | 2 +- tools/c7n_org/pyproject.toml | 2 +- tools/c7n_policystream/pyproject.toml | 2 +- tools/c7n_sphinxext/pyproject.toml | 2 +- tools/c7n_tencentcloud/pyproject.toml | 2 +- uv.lock | 26 +++++++++++++------------- 15 files changed, 27 insertions(+), 27 deletions(-) diff --git a/c7n/version.py b/c7n/version.py index 5e65d09ca8d..1449f7ca250 100644 --- a/c7n/version.py +++ b/c7n/version.py @@ -1,2 +1,2 @@ # Generated via tools/dev/devpkg.py -version = "0.9.52a3.post3" +version = "0.9.52a3.post4" diff --git a/pyproject.toml b/pyproject.toml index a09f8fc34bc..5012091cd14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ dependencies = [ "urllib3>2", ] name = "c7n" -version = "0.9.52a3.post3" +version = "0.9.52a3.post4" description = "Cloud Custodian - Policy Rules Engine" readme = "README.md" classifiers = [ diff --git a/tools/c7n_awscc/pyproject.toml b/tools/c7n_awscc/pyproject.toml index 689d88b9560..96f9a9e4fd6 100644 --- a/tools/c7n_awscc/pyproject.toml +++ b/tools/c7n_awscc/pyproject.toml @@ -10,7 +10,7 @@ dependencies = [ "jsonpatch<2.0,>=1.32", ] name = "c7n_awscc" -version = "0.1.37a3.post3" +version = "0.1.37a3.post4" readme = "readme.md" description = "Cloud Custodian - AWS Cloud Control Provider" classifiers = [ diff --git a/tools/c7n_azure/pyproject.toml b/tools/c7n_azure/pyproject.toml index 7ad9438733a..c9d3604121f 100644 --- a/tools/c7n_azure/pyproject.toml +++ b/tools/c7n_azure/pyproject.toml @@ -87,7 +87,7 @@ dependencies = [ "requests<3.0.0,>=2.22.0", ] name = "c7n_azure" -version = "0.7.51a3.post3" +version = "0.7.51a3.post4" description = "Cloud Custodian - Azure Support" readme = "readme.md" classifiers = [ diff --git a/tools/c7n_gcp/pyproject.toml b/tools/c7n_gcp/pyproject.toml index b25b9d912d9..8d613962ba9 100644 --- a/tools/c7n_gcp/pyproject.toml +++ b/tools/c7n_gcp/pyproject.toml @@ -15,7 +15,7 @@ dependencies = [ "retrying<2.0.0,>=1.3.3", ] name = "c7n_gcp" -version = "0.4.51a3.post3" +version = "0.4.51a3.post4" description = "Cloud Custodian - Google Cloud Provider" readme = "readme.md" classifiers = [ diff --git a/tools/c7n_kube/pyproject.toml b/tools/c7n_kube/pyproject.toml index f04ec3c8a4a..41d565adf47 100644 --- a/tools/c7n_kube/pyproject.toml +++ b/tools/c7n_kube/pyproject.toml @@ -10,7 +10,7 @@ dependencies = [ "kubernetes>=10.0.1", ] name = "c7n_kube" -version = "0.2.51a3.post3" +version = "0.2.51a3.post4" description = "Cloud Custodian - Kubernetes Provider" readme = "readme.md" classifiers = [ diff --git a/tools/c7n_left/pyproject.toml b/tools/c7n_left/pyproject.toml index d3513381f0a..177b1b8ae72 100644 --- a/tools/c7n_left/pyproject.toml +++ b/tools/c7n_left/pyproject.toml @@ -12,7 +12,7 @@ dependencies = [ "tfparse<1.0,>=0.6", ] name = "c7n_left" -version = "0.3.38a3.post3" +version = "0.3.38a3.post4" description = "Custodian policies for IAAC definitions" readme = "README.md" classifiers = [ diff --git a/tools/c7n_mailer/pyproject.toml b/tools/c7n_mailer/pyproject.toml index 662c632d3eb..a4403bdad01 100644 --- a/tools/c7n_mailer/pyproject.toml +++ b/tools/c7n_mailer/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ "types-six<2.0.0,>=1.16.10", ] name = "c7n_mailer" -version = "0.6.51a3.post3" +version = "0.6.51a3.post4" description = "Cloud Custodian - Reference Mailer" readme = "README.md" classifiers = [ diff --git a/tools/c7n_oci/pyproject.toml b/tools/c7n_oci/pyproject.toml index ad0673e3411..53742b65e20 100644 --- a/tools/c7n_oci/pyproject.toml +++ b/tools/c7n_oci/pyproject.toml @@ -13,7 +13,7 @@ dependencies = [ "pyopenssl>=24" ] name = "c7n_oci" -version = "0.1.26a3.post3" +version = "0.1.26a3.post4" description = "Cloud Custodian - OCI Support" readme = "readme.md" classifiers = [ diff --git a/tools/c7n_openstack/pyproject.toml b/tools/c7n_openstack/pyproject.toml index 1a5c0eabf8e..a8db030c2bc 100644 --- a/tools/c7n_openstack/pyproject.toml +++ b/tools/c7n_openstack/pyproject.toml @@ -9,7 +9,7 @@ dependencies = [ "openstacksdk==0.52.0", ] name = "c7n_openstack" -version = "0.1.42a3.post3" +version = "0.1.42a3.post4" description = "Cloud Custodian - OpenStack Provider" readme = "readme.md" classifiers = [ diff --git a/tools/c7n_org/pyproject.toml b/tools/c7n_org/pyproject.toml index 38b43732f27..a0009abda76 100644 --- a/tools/c7n_org/pyproject.toml +++ b/tools/c7n_org/pyproject.toml @@ -9,7 +9,7 @@ dependencies = [ "click>=8.0", ] name = "c7n_org" -version = "0.6.51a3.post3" +version = "0.6.51a3.post4" description = "Cloud Custodian - Parallel Execution" readme = "README.md" classifiers = [ diff --git a/tools/c7n_policystream/pyproject.toml b/tools/c7n_policystream/pyproject.toml index 4031ffd2ba6..92d29771bd2 100644 --- a/tools/c7n_policystream/pyproject.toml +++ b/tools/c7n_policystream/pyproject.toml @@ -13,7 +13,7 @@ dependencies = [ "requests<3.0.0,>=2.22.0", ] name = "c7n_policystream" -version = "0.4.51a3.post3" +version = "0.4.51a3.post4" description = "Cloud Custodian - Git Commits as Logical Policy Changes" readme = "README.md" classifiers = [ diff --git a/tools/c7n_sphinxext/pyproject.toml b/tools/c7n_sphinxext/pyproject.toml index b5c229be693..81429a5e750 100644 --- a/tools/c7n_sphinxext/pyproject.toml +++ b/tools/c7n_sphinxext/pyproject.toml @@ -15,7 +15,7 @@ dependencies = [ "sphinx-rtd-theme>=1.0.0", ] name = "c7n_sphinxext" -version = "1.1.51a3.post3" +version = "1.1.51a3.post4" description = "Cloud Custodian - Sphinx Extensions" classifiers = [ "License :: OSI Approved :: Apache Software License", diff --git a/tools/c7n_tencentcloud/pyproject.toml b/tools/c7n_tencentcloud/pyproject.toml index 29742892990..f14e58bb33a 100644 --- a/tools/c7n_tencentcloud/pyproject.toml +++ b/tools/c7n_tencentcloud/pyproject.toml @@ -12,7 +12,7 @@ dependencies = [ "tencentcloud-sdk-python<4.0.0,>=3.0.783", ] name = "c7n_tencentcloud" -version = "0.1.34a3.post3" +version = "0.1.34a3.post4" description = "Cloud Custodian - Tencent Cloud Provider" readme = "readme.md" diff --git a/uv.lock b/uv.lock index a2fdad4944a..b7bba0ac7e3 100644 --- a/uv.lock +++ b/uv.lock @@ -1330,7 +1330,7 @@ wheels = [ [[package]] name = "c7n" -version = "0.9.52a3.post3" +version = "0.9.52a3.post4" source = { editable = "." } dependencies = [ { name = "argcomplete" }, @@ -1419,7 +1419,7 @@ lint = [ [[package]] name = "c7n-awscc" -version = "0.1.37a3.post3" +version = "0.1.37a3.post4" source = { editable = "tools/c7n_awscc" } dependencies = [ { name = "boto3" }, @@ -1444,7 +1444,7 @@ dev = [{ name = "pytest" }] [[package]] name = "c7n-azure" -version = "0.7.51a3.post3" +version = "0.7.51a3.post4" source = { editable = "tools/c7n_azure" } dependencies = [ { name = "adal" }, @@ -1627,7 +1627,7 @@ dev = [ [[package]] name = "c7n-gcp" -version = "0.4.51a3.post3" +version = "0.4.51a3.post4" source = { editable = "tools/c7n_gcp" } dependencies = [ { name = "c7n" }, @@ -1668,7 +1668,7 @@ dev = [ [[package]] name = "c7n-kube" -version = "0.2.51a3.post3" +version = "0.2.51a3.post4" source = { editable = "tools/c7n_kube" } dependencies = [ { name = "c7n" }, @@ -1697,7 +1697,7 @@ dev = [ [[package]] name = "c7n-left" -version = "0.3.38a3.post3" +version = "0.3.38a3.post4" source = { editable = "tools/c7n_left" } dependencies = [ { name = "c7n" }, @@ -1730,7 +1730,7 @@ dev = [ [[package]] name = "c7n-mailer" -version = "0.6.51a3.post3" +version = "0.6.51a3.post4" source = { editable = "tools/c7n_mailer" } dependencies = [ { name = "boto3" }, @@ -1796,7 +1796,7 @@ dev = [ [[package]] name = "c7n-oci" -version = "0.1.26a3.post3" +version = "0.1.26a3.post4" source = { editable = "tools/c7n_oci" } dependencies = [ { name = "c7n" }, @@ -1821,7 +1821,7 @@ dev = [{ name = "pytest" }] [[package]] name = "c7n-openstack" -version = "0.1.42a3.post3" +version = "0.1.42a3.post4" source = { editable = "tools/c7n_openstack" } dependencies = [ { name = "c7n" }, @@ -1848,7 +1848,7 @@ dev = [ [[package]] name = "c7n-org" -version = "0.6.51a3.post3" +version = "0.6.51a3.post4" source = { editable = "tools/c7n_org" } dependencies = [ { name = "c7n" }, @@ -1871,7 +1871,7 @@ dev = [{ name = "pytest" }] [[package]] name = "c7n-policystream" -version = "0.4.51a3.post3" +version = "0.4.51a3.post4" source = { editable = "tools/c7n_policystream" } dependencies = [ { name = "boto3" }, @@ -1907,7 +1907,7 @@ dev = [ [[package]] name = "c7n-sphinxext" -version = "1.1.51a3.post3" +version = "1.1.51a3.post4" source = { editable = "tools/c7n_sphinxext" } dependencies = [ { name = "c7n" }, @@ -1934,7 +1934,7 @@ requires-dist = [ [[package]] name = "c7n-tencentcloud" -version = "0.1.34a3.post3" +version = "0.1.34a3.post4" source = { editable = "tools/c7n_tencentcloud" } dependencies = [ { name = "c7n" },