diff --git a/GEMINI.md b/GEMINI.md
index 0932e50e4..b3506edb9 100644
--- a/GEMINI.md
+++ b/GEMINI.md
@@ -218,3 +218,4 @@ Modify one existing README example (do not add a new one) to demonstrate context
- Always break down complex requests into small, iterative tasks.
- For each task, propose the necessary edits and explicitly wait for user confirmation or discussion before proceeding.
- Always use the `replace` tool to both perform and cleanly display the proposed text modifications. Do not silently overwrite files or use shell commands for text edits.
+- **CRITICAL:** NEVER use shell redirections (like `cat << 'EOF' > file` or `echo "text" > file`) or `sed`/`awk` scripts for editing files. Always use the `replace` tool for targeted edits or the `write_file` tool for new/small files.
diff --git a/modules/net-vpc-factory/schemas/vpc.schema.md b/modules/net-vpc-factory/schemas/vpc.schema.md
deleted file mode 100644
index 1b70f1bea..000000000
--- a/modules/net-vpc-factory/schemas/vpc.schema.md
+++ /dev/null
@@ -1,119 +0,0 @@
-# VPC Configuration
-
-
-
-## Properties
-
-*additional properties: false*
-
-- ⁺**project_id**: *string*
-- ⁺**name**: *string*
-- **description**: *string*
-- **auto_create_subnetworks**: *boolean*
-- **delete_default_routes_on_create**: *boolean*
-- **mtu**: *number*
-- **routing_mode**: *string*
-
*enum: ['GLOBAL', 'REGIONAL']*
-- **firewall_policy_enforcement_order**: *string*
-
*enum: ['BEFORE_CLASSIC_FIREWALL', 'AFTER_CLASSIC_FIREWALL']*
-- **create_googleapis_routes**: *reference([create_googleapis_routes](#refs-create_googleapis_routes))*
-- **dns_policy**: *reference([dns_policy](#refs-dns_policy))*
-- **ipv6_config**: *reference([ipv6_config](#refs-ipv6_config))*
-- **network_attachments**: *reference([network_attachments](#refs-network_attachments))*
-- **routers**: *reference([routers](#refs-routers))*
-- **peering_config**: *reference([peering_config](#refs-peering_config))*
-- **psa_configs**: *array*
- - items: *reference([psa_config](#refs-psa_config))*
-- **subnets**: *array*
- - items: *reference([subnet](#refs-subnet))*
-- **subnets_private_nat**: *array*
- - items: *reference([simple_subnet](#refs-simple_subnet))*
-- **subnets_proxy_only**: *array*
- - items: *reference([proxy_only_subnet](#refs-proxy_only_subnet))*
-- **subnets_psc**: *array*
- - items: *reference([simple_subnet](#refs-simple_subnet))*
-- **nat_config**: *reference([nat_config](#refs-nat_config))*
-- **ncc_config**: *reference([ncc_config](#refs-ncc_config))*
-- **routes**: *object*
-- **policy_based_routes**: *object*
-- **vpn_config**: *object*
-
-## Definitions
-
-- **create_googleapis_routes**: *object*
- - **directpath**: *boolean*
- - **directpath-6**: *boolean*
- - **private**: *boolean*
- - **private-6**: *boolean*
- - **restricted**: *boolean*
- - **restricted-6**: *boolean*
-- **dns_policy**: *object*
- - **inbound**: *boolean*
- - **logging**: *boolean*
- - **outbound**: *object*
- - **private_ns**: *array*
- - items: *string*
- - **public_ns**: *array*
- - items: *string*
-- **ipv6_config**: *object*
- - **enable_ula_internal**: *boolean*
- - **internal_range**: *string*
-- **nat_config**: *object*
- - **`^[a-z0-9-]+$`**: *object*
- - ⁺**region**: *string*
-- **ncc_config**: *object*
- - ⁺**hub**: *string*
- - **group**: *string*
-- **network_attachments**: *object*
- - **`^[a-z0-9-]+$`**: *object*
- - **subnet**: *string*
- - **automatic_connection**: *boolean*
- - **description**: *string*
- - **producer_accept_lists**: *array*
- - items: *string*
- - **producer_reject_lists**: *array*
- - items: *string*
-- **peering_config**: *object*
- - **peer_vpc_self_link**: *string*
- - **create_remote_peer**: *boolean*
- - **export_routes**: *boolean*
- - **import_routes**: *boolean*
-- **psa_config**: *object*
- - **deletion_policy**: *string*
- - **ranges**: *object*
- - **`^[a-z0-9-]+$`**: *string*
- - **export_routes**: *boolean*
- - **import_routes**: *boolean*
- - **peered_domains**: *array*
- - items: *string*
- - **range_prefix**: *string*
- - **service_producer**: *string*
-- **routers**: *object*
- - **`^[a-z0-9-]+$`**: *object*
-
*additional properties: false*
- - ⁺**region**: *string*
- - ⁺**asn**: *number*
- - **custom_advertise**: *object*
- - **all_subnets**: *boolean*
- - **ip_ranges**: *object*
- - **`.*`**: *string*
-- **simple_subnet**: *object*
- - ⁺**name**: *string*
- - ⁺**ip_cidr_range**: *string*
- - ⁺**region**: *string*
- - **description**: *string*
-- **subnet**: *object*
- - ⁺**name**: *string*
- - **ip_cidr_range**: *string*
- - ⁺**region**: *string*
- - **description**: *string*
- - **enable_private_access**: *boolean*
- - **allow_subnet_cidr_routes_overlap**: *boolean*
- - **reserved_internal_range**: *string*
-- **proxy_only_subnet**: *object*
- - ⁺**name**: *string*
- - ⁺**ip_cidr_range**: *string*
- - ⁺**region**: *string*
- - **description**: *string*
- - **active**: *boolean*
- - **global**: *boolean*
diff --git a/modules/vpc-sc/schemas/perimeters.schema.md b/modules/vpc-sc/schemas/perimeters.schema.md
deleted file mode 100644
index d77c8c0f2..000000000
--- a/modules/vpc-sc/schemas/perimeters.schema.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# perimeters
-
-
-
-## Properties
-
-*additional properties: false*
-
-- **description**: *string*
-- **ignore_resource_changes**: *boolean*
-- **spec**: *object*
-
*additional properties: false*
- - **access_levels**: *array*
- - items: *string*
- - **egress_policies**: *array*
- - items: *string*
- - **ingress_policies**: *array*
- - items: *string*
- - **restricted_services**: *array*
- - items: *string*
- - **resources**: *array*
- - items: *string*
- - **vpc_accessible_services**: *reference([VpcAccessibleServices](#refs-VpcAccessibleServices))*
-- **status**: *object*
-
*additional properties: false*
- - **access_levels**: *array*
- - items: *string*
- - **egress_policies**: *array*
- - items: *string*
- - **ingress_policies**: *array*
- - items: *string*
- - **resources**: *array*
- - items: *string*
- - **restricted_services**: *array*
- - items: *string*
- - **vpc_accessible_services**: *reference([VpcAccessibleServices](#refs-VpcAccessibleServices))*
-- **title**: *string*
-- **use_explicit_dry_run_spec**: *boolean*
-
-## Definitions
-
-- **VpcAccessibleServices**: *object*
-
*additional properties: false*
- - ⁺**allowed_services**: *array*
- - items: *string*
- - **enable_restriction**: *boolean*
diff --git a/tools/check_schema_docs.py b/tools/check_schema_docs.py
index 67837511c..a43d9687a 100755
--- a/tools/check_schema_docs.py
+++ b/tools/check_schema_docs.py
@@ -42,6 +42,7 @@ class State(enum.IntEnum):
OK = enum.auto()
FAIL_STALE_DOC = enum.auto()
FAIL_MISSING_DOC = enum.auto()
+ FAIL_ORPHAN_DOC = enum.auto()
@property
def failed(self):
@@ -54,12 +55,16 @@ class State(enum.IntEnum):
State.OK: '✓ ',
State.FAIL_STALE_DOC: '✗D',
State.FAIL_MISSING_DOC: '✗M',
+ State.FAIL_ORPHAN_DOC: '✗O',
}[self.value]
def _check_dir(dir_name):
'Invoke schema_docs on folder, using the relevant options.'
dir_path = BASEDIR / dir_name
+ existing_docs = set(
+ p for p in dir_path.glob('**/*.schema.md') if '.terraform' not in str(p))
+
for schema_path in sorted(dir_path.glob('**/*.schema.json')):
if '.terraform' in str(schema_path):
continue
@@ -67,6 +72,7 @@ def _check_dir(dir_name):
diff = None
schema_rel = str(schema_path.relative_to(BASEDIR))
doc_path = schema_path.with_suffix('.md')
+ existing_docs.discard(doc_path)
try:
schema = json.load(schema_path.open())
@@ -98,6 +104,11 @@ def _check_dir(dir_name):
yield schema_rel, state, diff
+ for doc_path in sorted(existing_docs):
+ doc_rel = str(doc_path.relative_to(BASEDIR))
+ diff = f'----- {doc_rel} orphan doc -----\nFile {doc_rel} does not have a matching schema.'
+ yield doc_rel, State.FAIL_ORPHAN_DOC, diff
+
@click.command()
@click.argument('dirs', type=str, nargs=-1)