feat(site_domain): restore access_key enforcement for FQDN lookups

- api_crud_v3: strip falsy access_key values; restrict keyless queries
  to public domains (both site_access_key and site_domain_access_key
  must be NULL/empty); 75-line recursive block replaced with ~16 lines
- lib_sql_search: expand virtual 'access_key' field into priority SQL —
  site_access_key first, site_domain_access_key as fallback
- cms.py: add site_domain_access_key to site_domain searchable_fields
- docs: update frontend guide with access key behavior and examples
- e2e test: expand to cover all valid/invalid access key scenarios (15/15)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-31 14:46:33 -04:00
parent 1f9cbb0a1f
commit 4629e1ec63
5 changed files with 167 additions and 35 deletions

View File

@@ -199,7 +199,11 @@ def sql_search_qry_part(
if hasattr(item, 'field'):
clause, item_data = process_filter(item)
node_clauses.append(clause); data.update(item_data)
else: node_clauses.append(f"({process_node(item, current_depth + 1)})")
else:
# Recurse into nested SearchQuery; only append if non-empty
sub_clause = process_node(item, current_depth + 1)
if sub_clause:
node_clauses.append(f"({sub_clause})")
if node_clauses:
joiner = ' AND ' if 'and' in filter_attr else ' OR '
clauses.append(f"({joiner.join(node_clauses)})")
@@ -261,6 +265,18 @@ def sql_search_qry_part(
except Exception as e:
log.warning(f"Failed to resolve random ID for field {target_field}: {e}")
# site_domain: 'access_key' is a virtual field.
# site_access_key (site-level) takes priority; fall back to site_domain_access_key
# when site_access_key is not set (NULL or empty).
if target_field == 'access_key' and table_name and 'site_domain' in table_name:
sql_op = operator_map.get(f.op.lower())
if not sql_op: raise HTTPException(status_code=400, detail=f"Unsupported operator: {f.op}")
p1, p2 = get_param_name(), get_param_name()
return (
f"(site_access_key {sql_op} :{p1} OR "
f"((site_access_key IS NULL OR site_access_key = '') AND site_domain_access_key {sql_op} :{p2}))"
), {p1: f.value, p2: f.value}
if searchable_fields is not None and target_field not in searchable_fields:
# Fallback check for original field just in case
if f.field not in searchable_fields: