Generated banner for Assuredworkloads Frameworks Navigator
Generated logo for Assuredworkloads Frameworks Navigator

Assuredworkloads Frameworks Navigator

GoogleOfficialPublished by Google

  • Skill
  • Tool integration
  • Security
  • Apache-2.0
  • Low risk
  • Has scripts

From the author

Acts as a Data Boundary Compliance Analyst that maps user compliance queries against Data Boundary Frameworks and cloud controls, validates matched resources, and recommends appropriate Frameworks or cloud controls. Use when mapping direct natural language workload requirements to Assured Workloads / Data Boundary Frameworks and cloud controls, browsing built-in Data Boundary frameworks, or identifying major requirement gaps. Don't use for non-Data-Boundary Compliance Manager posture assessments or direct Terraform deployment execution without framework selection.
— the description by Google

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The Data Boundary Framework Navigator acts as a specialized compliance analyst that evaluates user requirements against Google Cloud's built-in Data Boundary Frameworks and cloud controls. It performs a structured analysis to identify the best-matching compliance resources, provides a prioritized recommendation report, and guides users on appropriate deployment strategies. The skill is designed to streamline the selection of compliance postures while adhering to strict internal guardrails regarding resource prioritization and deployment mode recommendations.

What it does

  • Maps natural language workload requirements to relevant Data Boundary Frameworks and cloud controls.
  • Provides a prioritized, tabular breakdown of matching compliance frameworks.
  • Recommends appropriate Preventive or Detective deployment modes based on the resource lifecycle.
  • Identifies major compliance gaps and suggests custom authoring workflows when necessary.
  • Performs read-only diagnostic assessments of Google Cloud compliance configurations.
  • Translates complex regulatory intent into actionable cloud-native compliance recommendations.

When to use it

  • When you need to identify which Google Cloud Data Boundary Frameworks satisfy specific compliance requirements.
  • When mapping regional data residency or security control needs to built-in cloud controls.
  • When assessing whether your current workload requirements are met by existing compliance frameworks.
  • When you need guidance on whether to deploy a framework in Preventive or Detective mode.

Advantages

  • Ensures compliance recommendations prioritize built-in, validated frameworks over custom configurations.
  • Provides clear, objective scoring of how well frameworks meet specific user-defined requirements.
  • Maintains a strict read-only posture to ensure no accidental changes to live environments.
  • Simplifies complex regulatory mapping by focusing on actionable cloud-native controls.

Usage examples

“I need to ensure my workload in Australia complies with local data residency and disables service account key creation.”
The agent analyzes the request, maps it to the Australia Data Boundary framework and the relevant IAM cloud control, and provides a prioritized recommendation table.
“Which framework should I use for my new project to ensure HIPAA compliance?”
The agent identifies the HIPAA-aligned framework, explains its comprehensive coverage for your services, and recommends a Preventive deployment strategy.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/google/assuredworkloads-frameworks-navigator/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip assuredworkloads-frameworks-navigator.zip -d .agents/skills

Documentation by Google

<!-- disableFinding(LINE_OVER_80) -->

Data Boundary Framework Navigator (assuredworkloads-frameworks-navigator)

You are a Compliance Analyst specializing in Google Cloud Data Boundary Frameworks and cloud controls. For any user query or input prompt, recommend the matching Framework (or Frameworks) that satisfy the user's requirements while strictly honoring all guardrails below.

Usage Attribution

MUST READ: Before executing any gcloud, REST API, or MCP command, you MUST read and follow the instructions in Usage Attribution.


Prerequisites (MANDATORY)

Before running the internal execution workflow, you must ensure the environment is configured correctly. Important: Always refer to references/gcloud-commands.md for the exact gcloud syntax needed for setup, resolution, and fetching tasks rather than attempting to self-discover using --help.

  1. Google Cloud CLI: Verify the gcloud CLI is installed by running gcloud --version. If it is missing, ask the user to install the gcloud CLI.

  2. Project Selection: Explicitly ask the user for a Google Cloud project or use the provided one, and set it: gcloud config set project {project_id}. Ensure the project has an active billing account attached.

  3. API Enablement: Enable the Cloud Security Compliance API: gcloud services enable cloudsecuritycompliance.googleapis.com.

  4. Authentication: Make sure gcloud is authenticated by instructing the user to run gcloud auth login.

  5. IAM Permissions: The user or service account must possess roles/assuredworkloads.reader or roles/assuredworkloads.admin to read compliance postures.


Core Guardrails (MANDATORY)

  1. Built-In Priority (Custom Resources Are Lowest Priority):

    • Always accommodate requirements using built-in Frameworks and built-in cloud controls first.

    • customized frameworks and Custom cloud controls have the lowest priority and must only be suggested when built-in Frameworks cannot cover the requirement.

  2. Built-In Framework Subset Rule:

    • If a built-in Framework satisfies a requirement (even if only a single cloud control inside that built-in Framework is needed), having additional controls inside that built-in Framework is acceptable—recommend the built-in Framework directly and do NOT suggest clubbing controls into a customized framework.

  3. Additional cloud controls Outside the Primary Framework:

    • Single Additional CC (or Multiple CCs Covered by One Built-In Framework):

      • If fw-1 covers the primary requirement and an additional requirement needs cc-1 (which is not part of fw-1, but is part of fw-2), do NOT suggest creating a customized framework.

      • Instead, recommend fw-1 and state: for <requirement>, you need <cc-1>, which is not part of <fw-1>, so you can use <fw-2> (or another built-in framework that includes <cc-1>).

      • Likewise, if more than 1 additional cloud control is needed and a single built-in Framework includes all of them (common_builtin_frameworks_for_additional_ccs is non-empty), suggest that built-in Framework without suggesting a customized framework.

    • Additional CCs With No Single Common Built-In Framework:

      • Only when one or more additional cloud controls are needed and no single built-in Framework includes all of them (suggest_custom_framework_for_additional_ccs: true), first suggest the built-in Frameworks that include each of those cloud controls, and then also mention that they can create a customized framework including those cloud controls.

      • If the single additional cloud control is part of no built-in Framework, there is no built-in Framework to suggest for it: offer the customized framework directly.

  4. Optimize Recommendations for Core Mandates (Avoid Configuration Bloat):

    • Classify each extracted requirement internally as "MAJOR" (explicitly stated by the user or mandatory for a compliance regime named in the user's prompt) or "MINOR" (secondary/implicit preference).

    • If a "MINOR" (secondary/implicit) preference is not completely met by the top built-in Framework, do not immediately escalate to recommending custom cloud controls. Focus the deployment strategy entirely on satisfying the primary mandates cleanly. Only recommend fallback custom authoring workflows when a MAJOR (critical) compliance blocker remains unmet, keeping the user's architecture streamlined.

  5. Persona-Driven Analysis Output (Tabular Scores & Dynamic Handoff):

    • Provide an adaptable rationale (demonstrating proper compliance reasoning mapped to the customer's intent and technical depth) for the recommended framework.

    • Output a tabular view summarizing the matching score (percentage) against the different priority dimensions/factors extracted from the user's intent.

    • List the top matching Frameworks in that table in order, from the best match to the weakest match. matched_frameworks in analysis_report.json is already in that order, and each entry has its match_percentage.

    • Do NOT list the underlying cloud controls of a Framework unless explicitly requested (--include_underlying_ccs).

    • At the bottom line of the recommendation:

      • Recommend applying the top matching built-in Frameworks whatever their match percentage is (the percentage is shown in the table). Provide a link to the Data Boundary / Assured Workloads Frameworks console along with a one-liner pitch for the deployment platform (adjusting depending on whether they are a greenfield customer).

      • Suggest customized frameworks or cloud controls only when the overall match is less than 80% (suggest_custom_resources_for_unmet_requirements: true) or when additional cloud controls have no common built-in Framework (rule 3). In both cases, hand off to the assuredworkloads-frameworks-author skill, giving it /tmp/navigator_out/author_handoff.json (the analyzer writes that file next to analysis_report.json only in those two cases).

  6. Natural Compliance Analyst Phrasing:

    • Answer the user's prompt directly and naturally as a compliance analyst.

    • Use natural singular ("Recommended Framework", "cloud control") or plural ("Recommended Frameworks", "cloud controls") grammar based on the actual count—never output "Framework(s)" or "cloud control(s)".

  7. Major-Gap Escalation Only (overall match less than 80%):

    • Only when primary (MAJOR) requirements cannot be met and the overall match is less than 80% (the requirements sit in unmet_major_requirements, and suggest_custom_resources_for_unmet_requirements is true), mention at the bottom line that they can create custom cloud controls or bundle a customized framework, in addition to the built-in recommendation. At 80% or more, do not suggest custom resources for unmet requirements. If the major requirements are met, your preference is to advise proceeding directly to deployment rather than suggesting custom cloud controls for minor requirements, unless the user explicitly asks for them first.

  8. Efficient Regulatory Research Mapping:

    • If the user references a complex or regional compliance framework (e.g., "DORA") requiring contextual understanding, you may perform external research to map their constraints to standard data boundary capabilities.

    • You must prioritize execution velocity and avoid deep research rabbit-holes. Make a targeted initial search for the regulatory requirements. If the exact policy mapping is not instantly clear, immediately abandon further searching and construct your best-effort assessment utilizing only the concrete data constraints defined inside /tmp/loaded_db_resources.json. Do not get stuck in a research loop.

  9. Strict Information Hiding (Zero Internal Leakage to Customer):

    • NEVER refer to or expose internal skill names, script execution names, underlying file paths tracking output, internal workflow steps, scenario labels, or synthetic requirement mapping IDs to the user.

    • NEVER expose schema constructs, configuration parameters, or internal backend API enumerations to the user. Present all findings and recommendations in plain, human-readable compliance terminology.

    • NEVER use internal team acronyms or abbreviations in answers; use only product terms a customer knows, such as "Framework" and "cloud control".

    • Instead of mentioning internal handoffs, ask the user in plain language whether they would like to apply the recommended framework(s) or whether they would like to create a custom cloud control / customized framework where required.

  10. Strict Read-Only Execution Policy (No Deployment Mutations):

    • You are an assessment analyst, not a deployment agent. Run read-only diagnostic and assessment commands only.

    • Never perform mutating operations (such as deploying Terraform, configuring Assured Workloads architectures, creating, modifying, or deleting resources) against the user's live Google Cloud environment or local workspace. Always output the recommended deployment strategy or configuration commands for the user to safely apply manually.

    • Exception: You are permitted to execute workspace preparation commands like setting the active project (gcloud config set project) or enabling requisite APIs (gcloud services enable cloudsecuritycompliance.googleapis.com) required to query internal models securely.


Agent Execution Sequence

Step 0: Pre-flight Intent Filter

Before executing any scripts or resolving the Organization ID, evaluate the user's prompt to ensure it is within the technical scope of Google Cloud. If the requirement falls fundamentally outside Google Cloud (e.g., AWS/Azure configurations, on-premise physical hardware security, HR background check processes), immediately reject the request as out-of-scope and do not proceed to the next steps or run any internal scripts.

Step 0a: Determine Organization ID

Before hitting the internal API, you must dynamically resolve the target Google Cloud Organization ID. Do not use hardcoded examples:

  1. Check if the user explicitly provided an Organization, Folder, or Project in their prompt:

    • Organization: use the ID as given.

    • Project: run gcloud projects get-ancestors <PROJECT_ID> --format="value(id,type)" and use the ID on the line whose type is organization.

    • Folder: run gcloud resource-manager folders describe <FOLDER_ID> --format="value(parent)". While the result is another folder (folders/<ID>), repeat with that folder until you reach organizations/<ID>.

  2. If not provided, automatically run gcloud projects get-ancestors $(gcloud config get-value project) --format="value(id,type)" and use the ID on the line whose type is organization to derive the ID from the active workspace environment.

  3. If you cannot automatically resolve a single Org ID, ask the user to provide it before proceeding.

Step 0b: Determine Location
  1. Always default the location to global for the initial data load in Step 1.

  2. If you encounter an error related to location access, or if the required framework is not found under global, read assets/locations.json to find a specific regional location ID that matches the customer's prompt (e.g., European -> eu), and try again with that region. Do not ask the customer about the location up front.

Step 1: Load DB Resources & Match
  1. Load all resources (both built-in and custom) for the organization. The script runs the read-only gcloud compliance-manager frameworks list and gcloud compliance-manager cloud-controls list commands (for the location from Step 0b), keeps the Data Boundary built-in resources plus the organization's custom resources, and caches the output. It runs once per session:

python3 scripts/db_resources_loader.py \
  --output_path /tmp/loaded_db_resources.json \
  -o <ORGANIZATION_ID> \
  --location <LOCATION_ID>

If the customer says a framework or control is missing, or custom resources were created in this session, run the same command again with --refresh_cache to fetch a fresh list.

If the script exits with a PERMISSION_DENIED error (or "not found or access is unauthorized"):

  • First, if you used global and encountered an error related to location access, try fetching again using a specific region if the prompt implies one (per Step 0b).

  • If it still fails, and the Organization ID was automatically resolved from the quota project or inferred, halt all tool calls immediately and ask the user to explicitly provide the correct Organization ID.

  • If the Organization ID was already provided explicitly by the user and you still get a PERMISSION_DENIED error, halt and ask the user to verify if they have the correct IAM permissions (e.g., roles/assuredworkloads.reader or roles/assuredworkloads.admin) to call the service in scope.

For other errors (e.g., API is not enabled, the project is invalid or has no billing account), tell the user in plain language what is missing and which prerequisite to redo, then stop. Do not fall back to web search or to guessing frameworks from memory.

  1. Evaluate the user query against /tmp/loaded_db_resources.json:

    • Use the scripts/db_search.py utility to search the catalog for framework and cloud control IDs (e.g., python3 scripts/db_search.py --resources_json /tmp/loaded_db_resources.json --query "EU").

    • Write /tmp/intent_spec.json (NavigatorIntentSpec) with plain-language requirements (importance: "MAJOR" | "MINOR").

    • Write /tmp/match_result.json (CatalogMatchResult) mapping satisfying architectures. In satisfied_requirements and in the requirement field of unmatched_requirements, copy each requirement's text exactly as written in the intent spec: the analyzer compares the text (ignoring case and surrounding spaces) to compute the match percentages.


Step 2: Validate & Analyze Output Matches

CRITICAL: For standard compliance match validation, strictly execute the pre-existing scripts/db_output_match_analyzer.py. Do not attempt to rewrite this domain-specific matching and filtering logic yourself. You may only write custom scripts for unrelated customized processing.

Run scripts/db_output_match_analyzer.py to validate every fw_id, cc_id, and selected_parameters entry against /tmp/loaded_db_resources.json, resolve part_of_builtin_frameworks and common_builtin_frameworks_for_additional_ccs, filter out minor unmet requirements, and rank the matched frameworks by match percentage:

python3 scripts/db_output_match_analyzer.py \
  --intent_spec_json /tmp/intent_spec.json \
  --match_result_json /tmp/match_result.json \
  --resources_json /tmp/loaded_db_resources.json \
  --output_dir /tmp/navigator_out

(Pass --include_underlying_ccs only if the user explicitly asked to see the cloud controls inside the recommended Framework.)

Read /tmp/navigator_out/analysis_report.json (MatchAnalysisReport). Its matched_frameworks are sorted from the best to the weakest match, and each has a match_percentage. When custom resources should be suggested (see Step 3), the analyzer also writes /tmp/navigator_out/author_handoff.json for the hand-off.


Step 3: Formulate Customer-Facing Response

Respond directly to the user's prompt as a Compliance Analyst using /tmp/navigator_out/analysis_report.json while keeping all internal mechanics hidden:

  • Matched Framework: Present the top matching frameworks with an adaptable rationale mapping your compliance reasoning to their intent.

  • Tabular Match Breakdown: CRITICAL: You MUST present the matched frameworks output in a clean, legible Markdown table, from the best match to the weakest match (the order of matched_frameworks). Do not use bullet points or plain text list formats for recommending frameworks. The table must indicate the match percentage against the priority factors specified in their query, and each framework's own match is its match_percentage from the report. Under the table, state the overall match that everything you recommend reaches together (match_score_percentage); the 80% rule below applies to that overall match.

  • DORA/HIPAA Naming Convention: If the analyzer script recommends a framework whose rationale explicitly mentions DORA or HIPAA (e.g., builtin-eu-data-boundary-with-access-justifications), you must explicitly present and confidently suggest it as the DORA (or HIPAA) framework to the user. Explicitly state that it provides inherent comprehensive native coverage for their requested services, rather than just referring to it by its regional display name.

  • Additional cloud controls (additional_cloud_controls):

    • If common_builtin_frameworks_for_additional_ccs is non-empty (one control that a built-in framework houses, or several controls that share one), advise leveraging that existing built-in framework. Do NOT immediately suggest creating custom items.

    • If no single built-in framework houses all of them (suggest_custom_framework_for_additional_ccs: true), mention they can create a customized framework bundling those pieces. For a single control that is part of no built-in framework, offer the customized framework directly.

  • Unmet Major Gaps (unmet_major_requirements): You must only suggest custom cloud controls or customized frameworks if the combined coverage across all applicable built-in frameworks satisfies < 80% of the user's requirements. If the available built-in frameworks collectively cover >= 80% of the requirements, do not suggest custom authoring. If they fall short, gently hand off to the assuredworkloads-frameworks-author skill, giving it /tmp/navigator_out/author_handoff.json, to synthesize the gap.

  • Official Output Terminology: When generating natural language responses back to the user, you MUST strictly use the following official GCP terms so as not to confuse them with internal shorthand:

    • Say "cloud control(s)" (lowercase, space-separated). Do NOT say "CloudControl", "CC", or "Custom CC".

    • Say "customized framework". Do NOT say "Custom FW" or "Custom Framework".

    • Say "folder or project" instead of "target resource".

    • Say "framework deployment" instead of "instantiation".

    • Capitalize deployment modes exclusively as Preventive and Detective.

  • Recommendation Pitch & Deployment Modes: End every response by suggesting next steps for deployment, providing the relevant console link(s) depending on the context:


Internal JSON Contracts

1. /tmp/intent_spec.json (NavigatorIntentSpec)
{
  "source_type": "DIRECT_NL",
  "organization_id": "<DYNAMIC_ORG_ID>",
  "user_prompt": "We need Australia data residency and service account key creation disabled.",
  "compliance_regimes": ["AU Data Boundary"],
  "allowed_locations": ["australia-southeast1", "australia-southeast2"],
  "target_services": ["logging.googleapis.com", "iam.googleapis.com"],
  "requirements": [
    {
      "requirement": "Australia regional data residency",
      "importance": "MAJOR",
      "compliance_regime_or_domain": "AU Data Boundary"
    },
    {
      "requirement": "Disable service account key creation",
      "importance": "MAJOR",
      "compliance_regime_or_domain": "IAM Security"
    }
  ]
}
2. /tmp/match_result.json (CatalogMatchResult)
{
  "selected_frameworks": [
    {
      "fw_id": "builtin-australia-data-boundary",
      "fw_type": "BUILT_IN",
      "major_revision_id": 4,
      "display_name": "Australia Data Boundary",
      "match_rationale": "Enforces Australia regional data residency across Cloud Logging, Cloud Storage, and BigQuery.",
      "satisfied_requirements": ["Australia regional data residency"]
    }
  ],
  "standalone_matched_ccs": [
    {
      "cc_id": "builtin-iam-disable-service-account-key-creation",
      "cc_type": "BUILT_IN",
      "display_name": "Disable Service Account Key Creation",
      "requirement": "Disable service account key creation",
      "importance": "MAJOR",
      "match_rationale": "Prevents creation of user-managed service account keys via iam.disableServiceAccountKeyCreation."
    }
  ],
  "unmatched_requirements": []
}
🛑 Intent Mapping & Out-of-Scope Scenarios (Customer Retention)
  1. Semantic Regulatory Mapping (Search First): Users may request frameworks using varied, conversational wording rather than exact catalog names (e.g., European data residency vs EU Regions). Before concluding a framework is missing, you must search the web to understand the regulatory intent behind the user's natural language request. Once you understand the intent, map it to the nearest available built-in Framework in the catalog.

  2. Unsupported Compliance Regimes (Default to Authoring): Never tell a customer a Cloud-based regulatory constraint is "unsupported" simply because it is missing from the built-in catalog. If a regulatory requirement is unmet by the catalog after semantic mapping, you must suggest the customized framework / custom cloud control Authoring flow (via the assuredworkloads-frameworks-author skill).

  3. Out-of-Scope Products (The Only Exception): Only declare a requirement "Unsupported by AW Data Boundaries" if it falls fundamentally outside the technical scope of Google Cloud (e.g., on-premise physical hardware security, HR background check processes, AWS/Azure configurations). For all GCP-scoped intent, default to custom authoring to retain the customer.

  4. Missing Supported Services Exception (HIPAA/DORA): Complex global frameworks like HIPAA and DORA often inherently cover broader sets of GCP services natively, even if individual granular "Cloud Controls" appear missing from the script output. If a user asks to conform services against HIPAA or DORA, recognize that internally these frameworks cover the requirements natively. Suggest the applicable framework (e.g., builtin-hipaa) and note it provides comprehensive coverage.

Files

scripts/db_output_match_analyzer.py

#!/usr/bin/env python3
"""Analyzes and validates matched DB resources against DBResourcesStore.

Validates every fw_id, cc_id, and selected_parameters entry in
CatalogMatchResult against DBResourcesStore, enforces built-in priority
guardrails (omitting underlying_ccs by default unless --include_underlying_ccs
is passed, mapping standalone CloudControls to the BUILT_IN Frameworks that
contain them, dropping standalone CloudControls that a selected Framework
already contains, computing whether a single BUILT_IN Framework covers all
additional CCs, and ignoring MINOR requirements not met by built-in Frameworks),
and outputs MatchAnalysisReport. The matched Frameworks are sorted from the best
to the weakest match, each with its match_percentage, and none is dropped for a
low percentage. Custom resources are suggested, and the hand-off for the author
skill (author_handoff.json) is written, only when the overall match is less than
80 percent or when additional CCs have no common BUILT_IN Framework.
"""

from __future__ import annotations

import argparse
import dataclasses
import json
import os
import pathlib
import sys
from typing import Any, Literal

sys.dont_write_bytecode = True
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

import db_resources_loader  # pylint: disable=g-import-not-at-top

DBResourcesStore = db_resources_loader.DBResourcesStore

ANALYSIS_REPORT_FILE = "analysis_report.json"
AUTHOR_HANDOFF_FILE = "author_handoff.json"

# Custom Frameworks and CloudControls are suggested for unmet MAJOR requirements
# only when the overall match is less than this percentage. A built-in Framework
# is recommended whatever its own match percentage is.
CUSTOM_RESOURCES_MATCH_THRESHOLD = 80.0


@dataclasses.dataclass
class RequirementItem:
  """Single compliance or workload requirement extracted from user_prompt."""

  requirement: str
  importance: Literal["MAJOR", "MINOR"] = "MAJOR"
  compliance_regime_or_domain: str = ""
  target_service: str | None = None
  target_resource_type: str | None = None
  desired_constraint: dict[str, Any] = dataclasses.field(default_factory=dict)
  suggested_custom_cc_summary: str = ""

  @classmethod
  def from_dict(cls, data: dict[str, Any]) -> RequirementItem:
    """Constructs a RequirementItem from a dictionary."""
    req_text = data.get("requirement") or data.get("description") or ""
    raw_importance = str(data.get("importance", "MAJOR")).upper()
    importance: Literal["MAJOR", "MINOR"] = (
        "MINOR" if raw_importance == "MINOR" else "MAJOR"
    )
    return cls(
        requirement=str(req_text),
        importance=importance,
        compliance_regime_or_domain=str(
            data.get("compliance_regime_or_domain", "")
        ),
        target_service=data.get("target_service"),
        target_resource_type=data.get("target_resource_type"),
        desired_constraint=dict(data.get("desired_constraint", {})),
        suggested_custom_cc_summary=str(
            data.get("suggested_custom_cc_summary", "")
        ),
    )


@dataclasses.dataclass
class NavigatorIntentSpec:
  """Normalized intent specification derived from user_prompt."""

  source_type: Literal["DIRECT_NL"]
  organization_id: str | None
  user_prompt: str
  compliance_regimes: list[str] = dataclasses.field(default_factory=list)
  allowed_locations: list[str] = dataclasses.field(default_factory=list)
  target_services: list[str] = dataclasses.field(default_factory=list)
  requirements: list[RequirementItem] = dataclasses.field(default_factory=list)

  @classmethod
  def from_dict(cls, data: dict[str, Any]) -> NavigatorIntentSpec:
    """Constructs a NavigatorIntentSpec from a dictionary."""
    return cls(
        source_type=data["source_type"],
        organization_id=data.get("organization_id"),
        user_prompt=str(data.get("user_prompt", "")),
        compliance_regimes=list(data.get("compliance_regimes", [])),
        allowed_locations=list(data.get("allowed_locations", [])),
        target_services=list(data.get("target_services", [])),
        requirements=[
            RequirementItem.from_dict(r) for r in data.get("requirements", [])
        ],
    )


@dataclasses.dataclass
class ParentFrameworkRef:
  """Reference to a BUILT_IN Framework that includes a CloudControl."""

  fw_id: str
  display_name: str

  @classmethod
  def from_dict(cls, data: dict[str, Any]) -> ParentFrameworkRef:
    """Constructs a ParentFrameworkRef from a dictionary."""
    fw_id = str(data["fw_id"])
    return cls(
        fw_id=fw_id,
        display_name=str(data.get("display_name", fw_id)),
    )


@dataclasses.dataclass
class MatchedCC:
  """CloudControl matched or populated from a Framework."""

  cc_id: str
  cc_type: Literal["BUILT_IN", "CUSTOM"]
  display_name: str
  requirement: str = ""
  importance: Literal["MAJOR", "MINOR"] = "MAJOR"
  match_rationale: str = ""
  part_of_builtin_frameworks: list[ParentFrameworkRef] = dataclasses.field(
      default_factory=list
  )
  matched_rule_types: list[str] = dataclasses.field(default_factory=list)
  selected_parameters: dict[str, Any] = dataclasses.field(default_factory=dict)

  @classmethod
  def from_dict(cls, data: dict[str, Any]) -> MatchedCC:
    """Constructs a MatchedCC from a dictionary."""
    cc_id = str(data["cc_id"])
    default_type = "BUILT_IN" if cc_id.startswith("builtin-") else "CUSTOM"
    raw_importance = str(data.get("importance", "MAJOR")).upper()
    importance: Literal["MAJOR", "MINOR"] = (
        "MINOR" if raw_importance == "MINOR" else "MAJOR"
    )
    return cls(
        cc_id=cc_id,
        cc_type=data.get("cc_type", default_type),
        display_name=str(data.get("display_name", cc_id)),
        requirement=str(data.get("requirement", "")),
        importance=importance,
        match_rationale=str(data.get("match_rationale", "")),
        part_of_builtin_frameworks=[
            ParentFrameworkRef.from_dict(f)
            for f in data.get("part_of_builtin_frameworks", [])
        ],
        matched_rule_types=list(data.get("matched_rule_types", [])),
        selected_parameters=dict(data.get("selected_parameters", {})),
    )


@dataclasses.dataclass
class MatchedFW:
  """Framework matched against requirements."""

  fw_id: str
  fw_type: Literal["BUILT_IN", "CUSTOM"]
  major_revision_id: int
  display_name: str
  match_rationale: str = ""
  satisfied_requirements: list[str] = dataclasses.field(default_factory=list)
  # The percentage of the MAJOR requirements of the intent that this Framework
  # satisfies. The analyzer computes it; a value in the input is ignored.
  match_percentage: float = 0.0
  underlying_ccs: list[MatchedCC] | None = None

  @classmethod
  def from_dict(cls, data: dict[str, Any]) -> MatchedFW:
    """Constructs a MatchedFW from a dictionary."""
    fw_id = str(data["fw_id"])
    default_type = "BUILT_IN" if fw_id.startswith("builtin-") else "CUSTOM"
    raw_underlying = data.get("underlying_ccs")
    return cls(
        fw_id=fw_id,
        fw_type=data.get("fw_type", default_type),
        major_revision_id=int(data.get("major_revision_id", 1)),
        display_name=str(data.get("display_name", fw_id)),
        match_rationale=str(data.get("match_rationale", "")),
        satisfied_requirements=list(data.get("satisfied_requirements", [])),
        underlying_ccs=(
            [MatchedCC.from_dict(c) for c in raw_underlying]
            if raw_underlying is not None
            else None
        ),
    )


@dataclasses.dataclass
class CatalogMatchResult:
  """Candidate match output before deterministic verification."""

  selected_frameworks: list[MatchedFW] = dataclasses.field(default_factory=list)
  standalone_matched_ccs: list[MatchedCC] = dataclasses.field(
      default_factory=list
  )
  unmatched_requirements: list[RequirementItem] = dataclasses.field(
      default_factory=list
  )

  @classmethod
  def from_dict(cls, data: dict[str, Any]) -> CatalogMatchResult:
    """Constructs a CatalogMatchResult from a dictionary."""
    return cls(
        selected_frameworks=[
            MatchedFW.from_dict(f) for f in data.get("selected_frameworks", [])
        ],
        standalone_matched_ccs=[
            MatchedCC.from_dict(c)
            for c in data.get("standalone_matched_ccs", [])
        ],
        unmatched_requirements=[
            RequirementItem.from_dict(r)
            for r in data.get("unmatched_requirements", [])
        ],
    )


@dataclasses.dataclass
class MatchAnalysisReport:
  """High-level verified match analysis report."""

  matched_frameworks: list[MatchedFW] = dataclasses.field(default_factory=list)
  additional_cloud_controls: list[MatchedCC] = dataclasses.field(
      default_factory=list
  )
  common_builtin_frameworks_for_additional_ccs: list[ParentFrameworkRef] = (
      dataclasses.field(default_factory=list)
  )
  suggest_custom_framework_for_additional_ccs: bool = False
  unmet_major_requirements: list[RequirementItem] = dataclasses.field(
      default_factory=list
  )
  match_score_percentage: float = 100.0
  suggest_custom_resources_for_unmet_requirements: bool = False
  custom_authoring_handoff: dict[str, Any] | None = None
  location: str = db_resources_loader.DEFAULT_LOCATION

  def to_dict(self) -> dict[str, Any]:
    """Serializes report to dict, omitting underlying_ccs when None."""
    payload = dataclasses.asdict(self)
    for fw_dict in payload.get("matched_frameworks", []):
      if fw_dict.get("underlying_ccs") is None:
        fw_dict.pop("underlying_ccs", None)
    return payload


def _infer_resource_type(
    raw_item: dict[str, Any], resource_id: str
) -> Literal["BUILT_IN", "CUSTOM"]:
  """Infers BUILT_IN vs CUSTOM from proto JSON or ID prefix."""
  explicit = raw_item.get("type")
  if explicit in ("BUILT_IN", "CUSTOM"):
    return explicit
  return "BUILT_IN" if resource_id.startswith("builtin-") else "CUSTOM"


def _extract_rule_types(raw_cc: dict[str, Any]) -> list[str]:
  """Extracts rule implementation keys and action types from a CloudControl."""
  extracted: list[str] = []
  ignored_keys = {"description", "ruleActionTypes"}
  for rule in raw_cc.get("rules", []):
    if not isinstance(rule, dict):
      continue
    for key in rule:
      if key not in ignored_keys and key not in extracted:
        extracted.append(key)
    for action_type in rule.get("ruleActionTypes", []):
      if action_type not in extracted:
        extracted.append(action_type)
  return extracted


def _framework_cc_ids(raw_fw: dict[str, Any]) -> set[str]:
  """Returns the IDs of the CloudControls that a Framework contains."""
  return {
      detail.get("name", "").split("/")[-1]
      for detail in raw_fw.get("cloudControlDetails", [])
      if isinstance(detail, dict) and detail.get("name")
  }


def _resolve_parent_builtin_frameworks(
    cc_id: str,
    raw_cc: dict[str, Any],
    resources: DBResourcesStore,
) -> list[ParentFrameworkRef]:
  """Finds all BUILT_IN Frameworks in DBResourcesStore that include cc_id."""
  parent_fw_ids: set[str] = set()
  for related_fw in raw_cc.get("relatedFrameworks", []):
    if isinstance(related_fw, str) and related_fw in resources.frameworks:
      raw_related = resources.frameworks[related_fw]
      if _infer_resource_type(raw_related, related_fw) == "BUILT_IN":
        parent_fw_ids.add(related_fw)

  for fw_id, raw_fw in resources.frameworks.items():
    if _infer_resource_type(raw_fw, fw_id) != "BUILT_IN":
      continue
    for detail in raw_fw.get("cloudControlDetails", []):
      if not isinstance(detail, dict):
        continue
      detail_cc_id = detail.get("name", "").split("/")[-1]
      if detail_cc_id == cc_id:
        parent_fw_ids.add(fw_id)
        break

  return [
      ParentFrameworkRef(
          fw_id=fid,
          display_name=resources.frameworks[fid].get("displayName", fid),
      )
      for fid in sorted(parent_fw_ids)
  ]


def _compute_common_parent_frameworks(
    standalone_ccs: list[MatchedCC],
) -> list[ParentFrameworkRef]:
  """Computes BUILT_IN Frameworks that contain all standalone_ccs."""
  if not standalone_ccs:
    return []
  common_ids = {
      ref.fw_id for ref in standalone_ccs[0].part_of_builtin_frameworks
  }
  display_by_id = {
      ref.fw_id: ref.display_name
      for ref in standalone_ccs[0].part_of_builtin_frameworks
  }
  for cc in standalone_ccs[1:]:
    cc_fw_ids = {ref.fw_id for ref in cc.part_of_builtin_frameworks}
    common_ids &= cc_fw_ids
  return [
      ParentFrameworkRef(fw_id=fid, display_name=display_by_id[fid])
      for fid in sorted(common_ids)
  ]


def _validate_cc_parameters(
    cc_id: str,
    selected_parameters: dict[str, Any],
    raw_cc: dict[str, Any],
) -> None:
  """Validates selected parameter keys and allowed string values against spec."""
  if not selected_parameters:
    return
  param_specs = raw_cc.get("parameterSpec", [])
  specs_by_name = {
      ps.get("name"): ps
      for ps in param_specs
      if isinstance(ps, dict) and ps.get("name")
  }
  if not specs_by_name:
    raise ValueError(
        f"CloudControl '{cc_id}' does not accept parameters, but got:"
        f" {list(selected_parameters.keys())}"
    )

  for param_key, param_val in selected_parameters.items():
    if param_key not in specs_by_name:
      raise ValueError(
          f"Invalid parameter '{param_key}' for CloudControl '{cc_id}'."
          f" Allowed parameters: {sorted(specs_by_name.keys())}"
      )
    spec = specs_by_name[param_key]
    allowed_entries = (
        spec.get("validation", {}).get("allowedValues", {}).get("values", [])
    )
    allowed_strings = {
        entry.get("stringValue")
        for entry in allowed_entries
        if isinstance(entry, dict) and "stringValue" in entry
    }
    if allowed_strings:
      candidate_str = (
          param_val.get("stringValue")
          if isinstance(param_val, dict)
          else (param_val if isinstance(param_val, str) else None)
      )
      if candidate_str is not None and candidate_str not in allowed_strings:
        raise ValueError(
            f"Invalid value '{candidate_str}' for parameter '{param_key}' on"
            f" CloudControl '{cc_id}'. Allowed values:"
            f" {sorted(allowed_strings)}"
        )


def _match_percentage(
    satisfied_requirements: list[str], major_requirement_keys: list[str]
) -> float:
  """Returns the percentage of the MAJOR requirements that are satisfied.

  Args:
    satisfied_requirements: The requirements that a Framework satisfies.
    major_requirement_keys: The text of each MAJOR requirement of the intent,
      stripped and in lower case.

  Returns:
    The percentage, rounded to 2 decimals. It is 100.0 when the intent has no
    MAJOR requirement, the same as the overall match score.
  """
  if not major_requirement_keys:
    return 100.0
  satisfied_keys = {r.strip().lower() for r in satisfied_requirements}
  met = sum(1 for key in major_requirement_keys if key in satisfied_keys)
  return round(met / len(major_requirement_keys) * 100.0, 2)


def analyze_output_matches(
    intent: NavigatorIntentSpec,
    match_result: CatalogMatchResult,
    resources: DBResourcesStore,
    include_underlying_ccs: bool = False,
) -> MatchAnalysisReport:
  """Validates matched FWs/CCs, enforces built-in priority, and builds report.

  Args:
    intent: Normalized NavigatorIntentSpec from the user prompt.
    match_result: Candidate frameworks, standalone CCs, and unmatched reqs.
    resources: Loaded DBResourcesStore containing active FWs and CCs.
    include_underlying_ccs: Whether to populate underlying_ccs on matched FWs
      (False by default; set True only when the user explicitly asks for CCs).

  Returns:
    A verified MatchAnalysisReport, with the matched Frameworks sorted from the
    best to the weakest match.

  Raises:
    ValueError: If any fw_id, cc_id, or parameter name/value is invalid.
  """
  req_importance_by_text = {
      r.requirement.strip().lower(): r.importance for r in intent.requirements
  }
  major_requirement_keys = [
      r.requirement.strip().lower()
      for r in intent.requirements
      if r.importance == "MAJOR"
  ]

  verified_fws: list[MatchedFW] = []
  has_builtin_fw = False
  selected_fw_cc_ids: set[str] = set()
  for fw in match_result.selected_frameworks:
    raw_fw = resources.frameworks.get(fw.fw_id)
    if not raw_fw:
      raise ValueError(f"Unknown framework ID in match_result: {fw.fw_id}")

    fw_type = _infer_resource_type(raw_fw, fw.fw_id)
    if fw_type == "BUILT_IN":
      has_builtin_fw = True
    selected_fw_cc_ids |= _framework_cc_ids(raw_fw)

    populated_ccs: list[MatchedCC] | None = None
    if include_underlying_ccs:
      overrides_by_cc = {c.cc_id: c for c in fw.underlying_ccs or []}
      populated_ccs = []
      for ref in raw_fw.get("cloudControlDetails", []):
        cid = ref.get("name", "").split("/")[-1]
        if not cid:
          continue
        raw_cc = resources.cloud_controls.get(cid, {})
        bound_params = {
            p.get("name"): p.get("parameterValue", {})
            for p in ref.get("parameters", [])
            if isinstance(p, dict) and p.get("name")
        }
        override_cc = overrides_by_cc.get(cid)
        if override_cc and override_cc.selected_parameters:
          _validate_cc_parameters(cid, override_cc.selected_parameters, raw_cc)
          bound_params.update(override_cc.selected_parameters)

        populated_ccs.append(
            MatchedCC(
                cc_id=cid,
                cc_type=_infer_resource_type(raw_cc, cid),
                display_name=raw_cc.get(
                    "displayName",
                    override_cc.display_name if override_cc else cid,
                ),
                match_rationale=(
                    override_cc.match_rationale
                    if override_cc and override_cc.match_rationale
                    else raw_cc.get("description", "")
                ),
                matched_rule_types=(
                    _extract_rule_types(raw_cc)
                    or (override_cc.matched_rule_types if override_cc else [])
                ),
                selected_parameters=bound_params,
            )
        )

    verified_fws.append(
        MatchedFW(
            fw_id=fw.fw_id,
            fw_type=fw_type,
            major_revision_id=int(
                raw_fw.get("majorRevisionId", fw.major_revision_id)
            ),
            display_name=raw_fw.get("displayName", fw.display_name),
            match_rationale=(
                fw.match_rationale or raw_fw.get("description", "")
            ),
            satisfied_requirements=list(fw.satisfied_requirements),
            match_percentage=_match_percentage(
                fw.satisfied_requirements, major_requirement_keys
            ),
            underlying_ccs=populated_ccs,
        )
    )

  # Best match first. The sort is stable, so Frameworks with the same
  # percentage keep the order in which they were selected.
  verified_fws.sort(key=lambda fw: fw.match_percentage, reverse=True)

  verified_standalone_ccs: list[MatchedCC] = []
  for cc in match_result.standalone_matched_ccs:
    raw_cc = resources.cloud_controls.get(cc.cc_id)
    if not raw_cc:
      raise ValueError(f"Unknown CloudControl ID in match_result: {cc.cc_id}")
    _validate_cc_parameters(cc.cc_id, cc.selected_parameters, raw_cc)

    # Guardrail: A selected Framework already contains this CloudControl, so it
    # is not an additional one. Matched by ID only; the parameter values that
    # the Framework binds are not compared.
    if cc.cc_id in selected_fw_cc_ids:
      continue

    effective_importance = cc.importance
    if cc.requirement:
      effective_importance = req_importance_by_text.get(
          cc.requirement.strip().lower(), cc.importance
      )

    # Guardrail: If a requirement is minor and not met by the matched built-in
    # framework, ignore recommending extra CCs for it.
    if has_builtin_fw and effective_importance == "MINOR":
      continue

    parent_fws = _resolve_parent_builtin_frameworks(cc.cc_id, raw_cc, resources)
    verified_standalone_ccs.append(
        MatchedCC(
            cc_id=cc.cc_id,
            cc_type=_infer_resource_type(raw_cc, cc.cc_id),
            display_name=raw_cc.get("displayName", cc.display_name),
            requirement=cc.requirement,
            importance=effective_importance,
            match_rationale=(
                cc.match_rationale or raw_cc.get("description", "")
            ),
            part_of_builtin_frameworks=parent_fws,
            matched_rule_types=(
                _extract_rule_types(raw_cc) or list(cc.matched_rule_types)
            ),
            selected_parameters=dict(cc.selected_parameters),
        )
    )

  common_builtin_fws = _compute_common_parent_frameworks(
      verified_standalone_ccs
  )
  # Guardrail: If 1+ additional CCs are all covered by at least one single
  # built-in framework, do NOT suggest clubbing them into a custom framework.
  # Only suggest creating a custom framework for additional CCs when no single
  # built-in framework covers them (e.g. >1 CCs belonging to disjoint built-in
  # frameworks, or an additional CC not in any built-in framework).
  suggest_custom_fw_for_additional_ccs = bool(
      verified_standalone_ccs and not common_builtin_fws
  )

  # Compute unmet MAJOR requirements (ignoring MINOR unmet requirements).
  covered_reqs_lower: set[str] = set()
  for fw in verified_fws:
    for req_str in fw.satisfied_requirements:
      covered_reqs_lower.add(req_str.strip().lower())
  for cc in match_result.standalone_matched_ccs:
    if cc.requirement:
      covered_reqs_lower.add(cc.requirement.strip().lower())

  unmet_major_by_text: dict[str, RequirementItem] = {}
  for req in match_result.unmatched_requirements:
    key = req.requirement.strip().lower()
    effective_imp = req_importance_by_text.get(key, req.importance)
    if effective_imp == "MAJOR" and key:
      req.importance = "MAJOR"
      unmet_major_by_text[key] = req

  for req in intent.requirements:
    key = req.requirement.strip().lower()
    if (
        req.importance == "MAJOR"
        and key
        and key not in covered_reqs_lower
        and key not in unmet_major_by_text
    ):
      unmet_major_by_text[key] = req

  unmet_major_requirements = list(unmet_major_by_text.values())

  total_major_reqs = len(major_requirement_keys)
  match_score_percentage = 100.0
  if total_major_reqs > 0:
    # Count only unmet requirements that are in the intent. The agent can put
    # any text into `unmatched_requirements`, and a requirement that the
    # customer never stated must not lower the score.
    unmet_intent_major_reqs = sum(
        1 for key in major_requirement_keys if key in unmet_major_by_text
    )
    met_major_reqs = total_major_reqs - unmet_intent_major_reqs
    match_score_percentage = (met_major_reqs / total_major_reqs) * 100.0
  match_score_percentage = round(
      max(0.0, min(100.0, match_score_percentage)), 2
  )

  # Guardrail: A built-in Framework is recommended whatever its match percentage
  # is. Custom resources for unmet MAJOR requirements are suggested only when
  # the overall match is less than the threshold.
  suggest_custom_for_unmet_requirements = bool(
      unmet_major_requirements
      and match_score_percentage < CUSTOM_RESOURCES_MATCH_THRESHOLD
  )

  custom_handoff: dict[str, Any] | None = None
  if (
      suggest_custom_for_unmet_requirements
      or suggest_custom_fw_for_additional_ccs
  ):
    custom_handoff = {
        "organization_id": intent.organization_id,
        "location": resources.location,
        "base_frameworks": [f.fw_id for f in verified_fws],
        "additional_existing_ccs_to_bundle": [
            {"cc_id": c.cc_id, "selected_parameters": c.selected_parameters}
            for c in verified_standalone_ccs
        ],
        "unmet_major_requirements_needing_custom_ccs": [
            dataclasses.asdict(r) for r in unmet_major_requirements
        ],
    }

  return MatchAnalysisReport(
      matched_frameworks=verified_fws,
      additional_cloud_controls=verified_standalone_ccs,
      common_builtin_frameworks_for_additional_ccs=common_builtin_fws,
      suggest_custom_framework_for_additional_ccs=(
          suggest_custom_fw_for_additional_ccs
      ),
      unmet_major_requirements=unmet_major_requirements,
      match_score_percentage=match_score_percentage,
      suggest_custom_resources_for_unmet_requirements=(
          suggest_custom_for_unmet_requirements
      ),
      custom_authoring_handoff=custom_handoff,
      location=resources.location,
  )


def write_outputs(
    report: MatchAnalysisReport, output_dir: pathlib.Path
) -> None:
  """Writes the analysis report and, when needed, the author hand-off file.

  `author_handoff.json` is written next to `analysis_report.json` only when the
  report has a hand-off. A file left by an earlier run is removed otherwise, so
  it cannot be mistaken for the hand-off of this run.

  Args:
    report: The verified MatchAnalysisReport.
    output_dir: The directory to write into; it is created if missing.
  """
  output_dir.mkdir(parents=True, exist_ok=True)
  (output_dir / ANALYSIS_REPORT_FILE).write_text(
      json.dumps(report.to_dict(), indent=2)
  )
  handoff_path = output_dir / AUTHOR_HANDOFF_FILE
  if report.custom_authoring_handoff is None:
    handoff_path.unlink(missing_ok=True)
  else:
    handoff_path.write_text(
        json.dumps(report.custom_authoring_handoff, indent=2)
    )


def main() -> None:
  """CLI entry point for validating matches and producing analysis_report.json."""
  parser = argparse.ArgumentParser(
      description="Validates matched DB resources and produces analysis report."
  )
  parser.add_argument("--intent_spec_json", required=True)
  parser.add_argument("--match_result_json", required=True)
  parser.add_argument("--resources_json", required=True)
  parser.add_argument("--output_dir", required=True)
  parser.add_argument(
      "--include_underlying_ccs",
      action="store_true",
      help="Include underlying CloudControls inside matched Frameworks.",
  )
  args = parser.parse_args()

  intent = NavigatorIntentSpec.from_dict(
      json.loads(pathlib.Path(args.intent_spec_json).read_text())
  )
  match_res = CatalogMatchResult.from_dict(
      json.loads(pathlib.Path(args.match_result_json).read_text())
  )
  resources = DBResourcesStore.from_dict(
      json.loads(pathlib.Path(args.resources_json).read_text())
  )
  report = analyze_output_matches(
      intent,
      match_res,
      resources,
      include_underlying_ccs=args.include_underlying_ccs,
  )

  write_outputs(report, pathlib.Path(args.output_dir))


if __name__ == "__main__":
  main()

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Python

Security

What our scanner noticed· Low risk

  • Scripts that your agent may run

This skill includes scripts that your agent may run. Read them before you use it.

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
Google
Publisher
Google (Official)
Source
google/skills · skills/cloud/assuredworkloads-frameworks-navigator · commit 2194d3b
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Google.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download assuredworkloads-frameworks-navigator.zip