OCI Policy Analysis Common Components

Data Models

class oci_policy_analysis.common.models.Compartment[source]

Bases: TypedDict

Model representing an OCI compartment (identity and metadata). Captures id, name, parent, description, path, lifecycle, and tags where available. Adds optional analysis/derived fields for policy statement counts.

Optional/derived fields (set after loading and analysis):
  • statement_count_direct: Number of policy statements directly in this compartment.

  • statement_count_cumulative: Cumulative policy statements (this + all ancestors in path).

id: Annotated[str, 'Compartment OCID']
name: Annotated[str, 'Display name of the compartment']
parent_id: Annotated[str, 'Parent compartment OCID']
hierarchy_path: Annotated[str, 'Full compartment hierarchy path, e.g., "ROOT/HR/Payroll"']
description: NotRequired[Annotated[str, 'Description of the compartment']]
lifecycle_state: NotRequired[Annotated[str, 'Lifecycle state (e.g., ACTIVE, DELETED)']]
tags: NotRequired[Annotated[dict[str, str], 'Optional. All freeform and defined tags associated with the compartment.']]
statement_count_direct: NotRequired[Annotated[int, 'Number of policy statements directly in this compartment (analysis-derived, optional)']]
statement_count_cumulative: NotRequired[Annotated[int, 'Cumulative number of policy statements including all ancestors (analysis-derived, optional)']]
class oci_policy_analysis.common.models.Group[source]

Bases: TypedDict

Model representing an OCI IAM group (identity and metadata). A group is uniquely identified by domain and group name.

domain_name: NotRequired[Annotated[str, 'The domain of the group. If not provided, the default domain.']]
group_name: Annotated[str, 'The name of the group.']
group_id: NotRequired[Annotated[str, 'The ID of the group. Not required for filters.']]
group_ocid: NotRequired[Annotated[str, 'The OCID of the group. Not required for filters.']]
description: NotRequired[Annotated[str, 'The description of the group. Not required for filters.']]
class oci_policy_analysis.common.models.User[source]

Bases: TypedDict

Model representing an OCI IAM user. Only username and domain are required to uniquely identify a user.

domain_name: NotRequired[Annotated[str, 'The domain of the user. If not provided, the default domain.']]
user_name: Annotated[str, 'The user name. Required']
user_ocid: NotRequired[Annotated[str, 'The user OCID. Not required for filters.']]
display_name: NotRequired[Annotated[str, 'The display name. Not required for filters.']]
email: NotRequired[Annotated[str, 'The primary email address. Not required for filters.']]
user_id: NotRequired[Annotated[str, 'The user ID. Not required for filters.']]
groups: NotRequired[Annotated[list[str], 'List of group OCIDs the user belongs to. Not required for filters.']]
class oci_policy_analysis.common.models.DynamicGroup[source]

Bases: TypedDict

Model representing an OCI IAM dynamic group. Dynamic groups are collections of principals defined by rules; unique by domain and name.

domain_name: NotRequired[Annotated[str, 'The domain of the group. If not provided, the default domain.']]
domain_ocid: NotRequired[Annotated[str, 'The OCID of the domain. Not required for filters.']]
dynamic_group_name: Annotated[str, 'The name of the dynamic group.']
dynamic_group_ocid: NotRequired[Annotated[str, 'The OCID of the dynamic group. Not required for filters.']]
dynamic_group_id: NotRequired[Annotated[str, 'The ID of the dynamic group. Not required for filters.']]
matching_rule: NotRequired[Annotated[str, 'The matching rule expression for the dynamic group. Not required for filters.']]
description: NotRequired[Annotated[str | None, 'The description of the dynamic group. Not required for filters.']]
in_use: NotRequired[Annotated[bool, 'True if the dynamic group is referenced by any policies. Not required for filters.']]
creation_time: NotRequired[Annotated[str, 'The creation time of the dynamic group. Not required for filters.']]
created_by_ocid: NotRequired[Annotated[str, 'The OCID of the user who created the dynamic group. Not required for filters.']]
created_by_name: NotRequired[Annotated[str, 'The name of the user who created the dynamic group. Not required for filters.']]
class oci_policy_analysis.common.models.BasePolicy[source]

Bases: TypedDict

Model representing an OCI IAM policy. Captures policy identity and metadata but omits policy statements themselves. Policies are unique by their name within a compartment.

  • compartment_path: String with full path, e.g. “ROOT/DeptA/PolicyOne” (filled during loading).

Optionally includes tags if available.

policy_name: Annotated[str, 'The name of the policy.']
policy_ocid: Annotated[str, 'The OCID of the policy. Not required for filters.']
description: Annotated[str | None, 'The description of the policy. Not required for filters.']
compartment_ocid: Annotated[str, 'The OCID of the compartment containing the policy. Not required for filters.']
compartment_path: Annotated[str, 'Full compartment path string for the policy (e.g., "ROOT/CompA/CompB").']
creation_time: Annotated[str, 'The creation time of the policy. Not required for filters.']
tags: NotRequired[Annotated[dict[str, str], 'Optional. Flattened tag map for display only (freeform plus defined flattened as "namespace:key").']]
freeform_tags: NotRequired[Annotated[dict[str, str], 'Optional. Freeform tag map as stored in OCI.']]
defined_tags: NotRequired[Annotated[dict[str, dict[str, str]], 'Optional. Defined tag map as stored in OCI (namespace -> key -> value).']]
class oci_policy_analysis.common.models.GroupSearch[source]

Bases: TypedDict

Search model for OCI IAM groups. Used to filter and query cached group metadata by different attributes. Lists inside a field use OR; multiple fields use AND.

domain_name: Annotated[list[str], 'Domain name(s) to filter groups by. If provided, use the specified domain(s) to search. If not provided, the default domain is used.']
group_name: Annotated[list[str], 'Group display name(s) to match. Accepts full or partial names.']
group_ocid: Annotated[list[str], 'A list of OCIDs or partial OCIDs of the group.']
class oci_policy_analysis.common.models.UserSearch[source]

Bases: TypedDict

Search model for OCI IAM users. Used to filter and query cached user metadata by domain, username, or partial/display names. Lists inside a field use OR; multiple fields use AND.

domain_name: Annotated[list[str], 'Domain name(s) to filter users by. If provided, use the specified domain(s) to search. If not provided, the default domain is used.']
search: Annotated[list[str], 'User name(s) or Display Name(s) to match. Accepts full or partial names and matches display name or username.']
user_ocid: Annotated[str, 'A list of full or partial OCIDs of users to search on. The list will be treated as logical OR.']
class oci_policy_analysis.common.models.DynamicGroupSearch[source]

Bases: TypedDict

Search model for OCI IAM dynamic groups. Used to query dynamic groups based on domain, name, or matching rule criteria via MCP tools. Lists inside a field use OR; multiple fields use AND.

domain_name: NotRequired[Annotated[list[str], 'Domain name(s) associated with the dynamic group. If provided, use the specified domain(s) to search. If not provided, the default domain is used.']]
dynamic_group_name: NotRequired[Annotated[list[str], 'Dynamic group name(s) to filter by. Accepts full or partial names.']]
matching_rule: NotRequired[Annotated[list[str], "Matching rule expression(s) to search for (e.g., 'ALL {resource.type = instance, ...}'). Supports substring matches."]]
dynamic_group_ocid: Annotated[str, 'List of full or partial OCIDs of the dynamic group.']
in_use: NotRequired[Annotated[bool, 'If set to True, only return dynamic groups that are referenced by policies. If False, only those not in use. Not Required.']]
class oci_policy_analysis.common.models.PolicySearch[source]

Bases: TypedDict

Search/filter model for querying OCI IAM policy statements. Accepts many fields; lists use OR logic, multiple fields use AND. Used as input to policy filter tools provided by MCP.

action: Annotated[list[str], "Restrict results to statements of a given action: ['allow'], ['deny'], or both."]
exact_groups: Annotated[list[Group], 'Exact Group(s) to filter policies by. Requires full group_name.']
exact_users: Annotated[list[User], 'Exact User(s) to filter policies by. Requires full user_name.']
exact_dynamic_groups: Annotated[list[DynamicGroup], 'Exact Dynamic Group(s) to filter policies by. Requires full dynamic_group_name.']
search_groups: Annotated[GroupSearch, 'Fuzzy Search Group(s) to filter policies by. Accepts full or partial names.']
search_users: Annotated[UserSearch, 'Fuzzy Search User(s) to filter policies by. Accepts full or partial names.']
search_dynamic_groups: Annotated[DynamicGroupSearch, 'Fuzzy Search Dynamic Group(s) to filter policies by. Accepts full or partial names.']
verb: Annotated[list[Literal['inspect', 'read', 'use', 'manage']], 'One or more policy verbs to match. Each value filters by IAM verb type.']
statement_text: Annotated[list[str], 'Substring(s) of the policy statement text to match.']
policy_name: Annotated[list[str], 'Filter by policy display name(s).']
compartment_path: Annotated[list[str], "Compartment(s) that define the policy. Supports 'ROOTONLY' to restrict to root-level policies."]
resource: Annotated[list[str], "One or more OCI resources (e.g., 'instance', 'bucket') that this policy applies to."]
location: Annotated[list[str], "Relative compartment path(s) or OCIDs representing where the policy applies. Accepts 'tenancy' for top-level."]
effective_path: Annotated[list[str], 'Computed effective compartment path(s) for scope evaluation, used to determine inheritance of permissions. Always starts with ROOT  An example is ROOT/compartment1/sub-compThis filter can handle multiple paths as a list of strings. Supports partial paths, e.g., ROOT/compartment1', 'To match, this must be an exact match or a prefix(startswith) of the effective path of a policy statement.']
subject_type: Annotated[list[Literal['group', 'dynamic-group', 'any-user', 'any-group', 'service']], "Type of subject targeted by the policy. Must be one or more of 'group', 'dynamic-group', 'any-user', 'any-group', or 'service'."]
subject: Annotated[list[str], 'Subject identifier(s), usually user, group, or domain/name pairs.']
permission: Annotated[list[str], "List of specific permissions or actions (e.g., 'START_INSTANCE', 'READ_OBJECTS')."]
comments: Annotated[list[str], 'Comment text that appears at the end of policy statements (if any).']
conditions: Annotated[list[str], "Conditional clauses ('any', 'all', etc.) used within the policy statement."]
valid: Annotated[bool, 'If set to True, only return valid policy statements that parsed and passed validation. If False, only invalid statements.']
class oci_policy_analysis.common.models.PolicyOverlap[source]

Bases: TypedDict

Model for representing overlap/conflict analysis between policy statements. Useful for reporting risk and redundancy in IAM policy analysis tools.

superseded_by: Annotated[str, 'The policy name that supersedes this statement']
confidence: Annotated[str, 'Confidence level of the overlap (e.g., "high", "medium", "low")']
reason: Annotated[str, 'Explanation for the overlap detection']
statement_text: Annotated[str, 'The statement text of the superseding statement']
internal_id: Annotated[str, 'The internal ID of the superseding statement']
permission_overlap: Annotated[list[str], 'List of specific permissions that overlap between the two statements']
additional_notes: NotRequired[Annotated[str, 'Any additional notes about the overlap analysis.']]
class oci_policy_analysis.common.models.BasePolicyStatement[source]

Bases: TypedDict

Base model for all OCI policy statement types, containing shared fields. All statement models inherit from this and add statement-type-specific data.

policy_name: Annotated[str, 'Display name of the policy containing this statement.']
policy_ocid: Annotated[str, 'Unique OCID identifier of the policy.']
compartment_ocid: Annotated[str, 'OCID of the compartment where this policy is defined.']
compartment_path: Annotated[str, 'Path of the compartment that owns this policy.']
statement_text: Annotated[str, 'The full, raw text of the policy statement as defined in OCI.']
creation_time: Annotated[str, 'Timestamp (ISO-8601) of the policy creation in OCI.']
internal_id: Annotated[str, 'Unique internal hash identifier for this statement.']
parsed: Annotated[bool, 'True if the parser successfully interpreted this statement and extracted its components.']
class oci_policy_analysis.common.models.DefineStatement[source]

Bases: BasePolicyStatement

Parsed OCI IAM ‘define’ policy statement with optional metadata.

valid: Annotated[bool, 'True if the statement passed parsing and validation']
defined_type: Annotated[str, 'Type of object defined (user, group, dynamic-group, etc.)']
defined_name: Annotated[str, 'Name of the defined object']
ocid_alias: Annotated[str, 'Alias assigned for this definition, if any']
comment: NotRequired[Annotated[str, 'Trailing policy statement comment if present']]
policy_name: Annotated[str, 'Display name of the policy containing this statement.']
policy_ocid: Annotated[str, 'Unique OCID identifier of the policy.']
compartment_ocid: Annotated[str, 'OCID of the compartment where this policy is defined.']
compartment_path: Annotated[str, 'Path of the compartment that owns this policy.']
statement_text: Annotated[str, 'The full, raw text of the policy statement as defined in OCI.']
creation_time: Annotated[str, 'Timestamp (ISO-8601) of the policy creation in OCI.']
internal_id: Annotated[str, 'Unique internal hash identifier for this statement.']
parsed: Annotated[bool, 'True if the parser successfully interpreted this statement and extracted its components.']
class oci_policy_analysis.common.models.EndorseStatement[source]

Bases: BasePolicyStatement

Parsed OCI IAM ‘endorse’ cross-tenancy policy statement with optional metadata.

valid: Annotated[bool, 'True if the statement passed parsing and validation']
action_type: Annotated[Literal['endorse', 'deny endorse'], 'Type of endorse action: either "endorse" or "deny endorse"']
endorsed_principal_type: Annotated[Literal['group', 'dynamic-group', 'any-user', 'any-group', 'service'], 'Type of principal: group, dynamic-group, any-user, service.']
endorsed_principal: Annotated[str, 'Name of the principal being endorsed (group, dynamic-group, etc.)']
endorsed_principal_tenancy: Annotated[str, 'The tenancy of the endorsed group or dynamic-group']
endorse_action: Annotated[str, 'Verb or permission for the endorse statement (e.g., associate, use, etc.)']
endorse_resource: Annotated[str, 'Target OCI resource of the endorse statement (e.g., instance-family, bucket, etc.)']
endorse_permissions: NotRequired[Annotated[list[str], 'List of explicit permissions being endorsed']]
endorse_tenancy: Annotated[str, 'Defined name of the endorsed tenancy']
endorse_associate_resource: NotRequired[Annotated[str, 'Resource being associated (resource_a)']]
endorse_associate_tenancy: NotRequired[Annotated[str, 'Location of resource being associated']]
endorse_associate_with_resource: NotRequired[Annotated[str, 'Remote resource being associated (resource_b)']]
endorse_associate_with_tenancy: NotRequired[Annotated[str, 'Location of second resource being associated']]
where_clause: NotRequired[Annotated[str, 'Optional where clause (all {...}) attached']]
comment: NotRequired[Annotated[str, 'Trailing policy statement comment if present']]
policy_name: Annotated[str, 'Display name of the policy containing this statement.']
policy_ocid: Annotated[str, 'Unique OCID identifier of the policy.']
compartment_ocid: Annotated[str, 'OCID of the compartment where this policy is defined.']
compartment_path: Annotated[str, 'Path of the compartment that owns this policy.']
statement_text: Annotated[str, 'The full, raw text of the policy statement as defined in OCI.']
creation_time: Annotated[str, 'Timestamp (ISO-8601) of the policy creation in OCI.']
internal_id: Annotated[str, 'Unique internal hash identifier for this statement.']
parsed: Annotated[bool, 'True if the parser successfully interpreted this statement and extracted its components.']
class oci_policy_analysis.common.models.AdmitStatement[source]

Bases: BasePolicyStatement

Parsed OCI IAM ‘admit’ cross-tenancy policy statement with parsed metadata.

valid: Annotated[bool, 'True if the statement passed parsing and validation']
action_type: Annotated[Literal['admit', 'deny admit'], 'Type of admit action: either "admit" or "deny admit"']
admitted_principal_type: Annotated[Literal['group', 'dynamic-group', 'any-user', 'any-group', 'service'], 'Type of principal: group, dynamic-group, any-user, etc.']
admitted_principal: Annotated[str, 'Name of the principal being admitted (group, dynamic-group, etc.)']
admitted_tenancy: Annotated[str, 'The tenancy of the admitted group or dynamic-group']
admit_action: Annotated[str, 'Verb or permission for the admit statement (e.g., read, manage, use, etc.)']
admit_resource: Annotated[str, 'Target OCI resource of the admit statement (e.g., all-resources, orm-stack, etc.)']
admit_permissions: NotRequired[Annotated[list[str], 'List of explicit permissions being admitted']]
admit_location_type: Annotated[str, 'tenancy or compartment or compartment id']
admit_location: Annotated[str, 'The actual location value (e.g., tenancy, compartment OCID, etc.)']
admit_associate_resource: NotRequired[Annotated[str, 'Resource being associated (resource_a)']]
admit_associate_tenancy: NotRequired[Annotated[str, 'Location of resource being associated']]
admit_associate_with_resource: NotRequired[Annotated[str, 'Remote resource being associated (resource_b)']]
admit_associate_with_tenancy: NotRequired[Annotated[str, 'Location of second resource being associated']]
where_clause: NotRequired[Annotated[str, 'Optional where clause (all {...}) attached']]
comment: NotRequired[Annotated[str, 'Trailing policy statement comment if present']]
policy_name: Annotated[str, 'Display name of the policy containing this statement.']
policy_ocid: Annotated[str, 'Unique OCID identifier of the policy.']
compartment_ocid: Annotated[str, 'OCID of the compartment where this policy is defined.']
compartment_path: Annotated[str, 'Path of the compartment that owns this policy.']
statement_text: Annotated[str, 'The full, raw text of the policy statement as defined in OCI.']
creation_time: Annotated[str, 'Timestamp (ISO-8601) of the policy creation in OCI.']
internal_id: Annotated[str, 'Unique internal hash identifier for this statement.']
parsed: Annotated[bool, 'True if the parser successfully interpreted this statement and extracted its components.']
class oci_policy_analysis.common.models.RegularPolicyStatement[source]

Bases: BasePolicyStatement

Represents a parsed OCI IAM policy statement.

Each field corresponds to a normalized component extracted from a raw OCI policy text line. These structures are produced during policy parsing and returned by filter tools.

action: Annotated[Literal['allow', 'deny'], "The IAM action specified in the policy statement: either 'allow' or 'deny'."]
valid: Annotated[bool, 'True if the statement successfully parsed and passed internal validation.']
invalid_reasons: Annotated[list[str], 'If invalid, the reasons why parsing or validation failed.']
subject_type: Annotated[str, "Type of subject targeted by the policy, such as 'group', 'dynamic-group', 'any-user', 'any-group', or 'service'."]
subject: Annotated[list[tuple[str | None, str]] | str, 'The subject(s) this policy applies to. May be a list of (domain, name) tuples or a simple string if unstructured.']
verb: Annotated[str, "The IAM verb granting the level of access: one of 'inspect', 'read', 'use', or 'manage'."]
resource: Annotated[str, "OCI resource type targeted by this statement (e.g., 'instance-family', 'bucket', 'compartment')."]
permission: Annotated[list[str], "Specific permissions or actions derived from the statement (e.g., 'START_INSTANCE', 'READ_OBJECTS')."]
location_type: Annotated[str, "Indicates how the location was resolved: 'explicit', 'root', 'derived', etc."]
location: Annotated[str, 'Human-readable compartment path or OCID representing where this policy applies.']
effective_compartment_ocid: Annotated[str | None, 'OCID of the effective compartment determined from policy scope analysis.']
effective_path: Annotated[str | None, 'Resolved compartment path string showing where the statement takes effect, including inherited scopes.']
conditions: Annotated[str, "Conditional logic (e.g., 'where any {request.user.id = ...}') if present in the statement."]
comments: Annotated[str, 'Comments or annotations appended to the policy statement text, if any.']
parsing_notes: Annotated[list[str], 'List of notes or warnings generated during parsing, such as unsupported constructs.']
policy_name: Annotated[str, 'Display name of the policy containing this statement.']
policy_ocid: Annotated[str, 'Unique OCID identifier of the policy.']
compartment_ocid: Annotated[str, 'OCID of the compartment where this policy is defined.']
compartment_path: Annotated[str, 'Path of the compartment that owns this policy.']
statement_text: Annotated[str, 'The full, raw text of the policy statement as defined in OCI.']
creation_time: Annotated[str, 'Timestamp (ISO-8601) of the policy creation in OCI.']
internal_id: Annotated[str, 'Unique internal hash identifier for this statement.']
parsed: Annotated[bool, 'True if the parser successfully interpreted this statement and extracted its components.']
class oci_policy_analysis.common.models.PolicySummary[source]

Bases: TypedDict

Model for lightweight summary reporting for policy statement queries. Used by APIs or UI when result set is too large to send full details.

response_type: Literal['summary']
total_statements: Annotated[int, 'Total number of policy statements that matched the filter']
truncated: Annotated[bool, 'True if results were truncated due to size limits']
truncation_point: Annotated[int, 'Number of statements included before truncation occurred']
policy_breakdown: Annotated[dict[str, int], 'Count of statements by policy name (e.g., {"CloudGuardPolicies": 29, "Arista-Policy": 7})']
action_breakdown: Annotated[dict[str, int], 'Count of statements by action (e.g., {"allow": 82, "deny": 33})']
compartment_breakdown: Annotated[dict[str, int], 'Count of statements by compartment (e.g., {"ROOT": 45, "ROOT/LZ-Top": 29})']
subject_type_breakdown: Annotated[dict[str, int], 'Count of statements by subject type (e.g., {"group": 250, "service": 50, "dynamic-group": 40})']
verb_breakdown: Annotated[dict[str, int], 'Count of statements by verb (e.g., {"manage": 120, "read": 100, "use": 80, "inspect": 40})']
sample_statements: Annotated[list[str], 'Sample of statement texts to give context (limited to first 10-20 statements)']
message: Annotated[str, 'Human-readable explanation of why summary was returned instead of full data']
class oci_policy_analysis.common.models.PolicyStatementFull[source]

Bases: TypedDict

Model for detailed/full reporting of policy statement queries. Only used when result set is small enough to return every statement.

response_type: Literal['full']
statements: Annotated[list[RegularPolicyStatement], 'Complete list of policy statements']
total_count: Annotated[int, 'Total number of statements returned']
class oci_policy_analysis.common.models.UserSummary[source]

Bases: TypedDict

Lightweight summary of user search results when full details are not shown. Used to communicate match counts and domain breakdowns for user searches.

response_type: Literal['summary']
total_users: Annotated[int, 'Total number of users that matched the search criteria']
truncated: Annotated[bool, 'True if results were truncated due to size limits']
truncation_point: Annotated[int, 'Number of users included before truncation occurred']
domain_breakdown: Annotated[dict[str, int], 'Count of users by domain (e.g., {"Default": 45, "federated": 29})']
sample_users: Annotated[list[str], 'Sample of user names to give context (limited to first 10-20 users)']
message: Annotated[str, 'Human-readable explanation of why summary was returned instead of full data']
class oci_policy_analysis.common.models.UserSearchFull[source]

Bases: TypedDict

Model representing a full user search result set (all users). Used if the user list is small enough to return fully.

response_type: Literal['full']
users: Annotated[list[User], 'Complete list of users']
total_count: Annotated[int, 'Total number of users returned']
class oci_policy_analysis.common.models.GroupSummary[source]

Bases: TypedDict

Lightweight summary of group search results. Used to summarize group matches, domain breakdowns, and sampling.

response_type: Literal['summary']
total_groups: Annotated[int, 'Total number of groups that matched the search criteria']
truncated: Annotated[bool, 'True if results were truncated due to size limits']
truncation_point: Annotated[int, 'Number of groups included before truncation occurred']
domain_breakdown: Annotated[dict[str, int], 'Count of groups by domain (e.g., {"Default": 45, "federated": 29})']
sample_groups: Annotated[list[str], 'Sample of group names to give context (limited to first 10-20 groups)']
message: Annotated[str, 'Human-readable explanation of why summary was returned instead of full data']
class oci_policy_analysis.common.models.GroupSearchFull[source]

Bases: TypedDict

Model representing a full group search result set (all groups). Used if the group list is small enough to return fully.

response_type: Literal['full']
groups: Annotated[list[Group], 'Complete list of groups']
total_count: Annotated[int, 'Total number of groups returned']
class oci_policy_analysis.common.models.DynamicGroupSummary[source]

Bases: TypedDict

Lightweight summary of dynamic group search results. Used to summarize matches, domain/in-use breakdowns, and sample listing.

response_type: Literal['summary']
total_dynamic_groups: Annotated[int, 'Total number of dynamic groups that matched the search criteria']
truncated: Annotated[bool, 'True if results were truncated due to size limits']
truncation_point: Annotated[int, 'Number of dynamic groups included before truncation occurred']
domain_breakdown: Annotated[dict[str, int], 'Count of dynamic groups by domain (e.g., {"Default": 45, "federated": 29})']
in_use_breakdown: Annotated[dict[str, int], 'Count of dynamic groups by usage status (e.g., {"in_use": 25, "not_in_use": 10})']
sample_dynamic_groups: Annotated[list[str], 'Sample of dynamic group names to give context (limited to first 10-20 dynamic groups)']
message: Annotated[str, 'Human-readable explanation of why summary was returned instead of full data']
class oci_policy_analysis.common.models.DynamicGroupSearchFull[source]

Bases: TypedDict

Model representing a full dynamic group search result set. Used if the dynamic group list is small enough to return fully.

response_type: Literal['full']
dynamic_groups: Annotated[list[DynamicGroup], 'Complete list of dynamic groups']
total_count: Annotated[int, 'Total number of dynamic groups returned']
class oci_policy_analysis.common.models.ReferenceDataDiffResult[source]

Bases: TypedDict

Result model describing the outcome of comparing two cached reference data sets. Used by tools diagnosing drift or state changes in cached OCI data.

response_type: Literal['reference_data_diff']
cache_a: Annotated[str, 'Name of older cache (file or key)']
cache_b: Annotated[str, 'Name of newer cache (file or key)']
diff_summary: Annotated[str, 'One-line or short summary of differences (added, changed, removed)']
diff_details: Annotated[dict, 'DeepDiff result details or filtered view suitable for UI display']
message: Annotated[str, 'Human-readable message about the diff result or info']
class oci_policy_analysis.common.models.PolicyIntelligence[source]

Bases: TypedDict

Model for high-level analytics and findings of policy analysis (IAM intelligence overlay). Reports overlaps, risk scores, recommendations, consolidation, unused resources, and other advanced data. Intended for UI or API overlays rather than core engine results.

overlaps: list[dict]
recommendations: list[dict]
risk_scores: list[dict]
consolidations: list[dict]
cleanup_items: NotRequired[dict]

Display Helper Functions

oci_policy_analysis.common.helpers.for_display_policy(statement: RegularPolicyStatement) dict[source]

Return a dictionary suitable for display purposes. The underlying dict has many fields, some of which may not be present depending on how the statement was parsed. Display dict includes all possible fields with display-friendly names.

Parameters:

statement (PolicyStatement) – The policy statement (dict) to format.

Returns:

A dictionary with keys and values formatted for display.

Return type:

dict

oci_policy_analysis.common.helpers.for_display_user(u: User) dict[source]

Return a dictionary suitable for display purposes. The underlying dict has many fields, some of which may not be present depending on how the statement was parsed. Display dict includes all possible fields with display-friendly names.

Parameters:

u (User) – The user (dict) to format.

Returns:

A dictionary with keys and values formatted for display.

Return type:

dict

oci_policy_analysis.common.helpers.for_display_group(g: Group) dict[source]

Return a dictionary suitable for display purposes. The underlying dict has many fields, some of which may not be present depending on how the statement was parsed. Display dict includes all possible fields with display-friendly names.

Parameters:

g (Group) – The group (dict) to format.

Returns:

A dictionary with keys and values formatted for display.

Return type:

dict

oci_policy_analysis.common.helpers.for_display_dynamic_group(dg: DynamicGroup) dict[source]

Return a dictionary suitable for display purposes. The underlying dict has many fields, some of which may not be present depending on how the statement was parsed. Display dict includes all possible fields with display-friendly names.

Parameters:

dg (DynamicGroup) – The dynamic group (dict) to format.

Returns:

A dictionary with keys and values formatted for display.

Return type:

dict

oci_policy_analysis.common.helpers.for_display_define(define: DefineStatement) dict[source]

Return a dictionary suitable for display purposes, including all available key/value fields for defines. :param define: The define statement (dict) to format. :type define: DefineStatement

Returns:

A dictionary with keys and values formatted for display.

Return type:

dict

oci_policy_analysis.common.helpers.for_display_admit(statement) dict[source]

Display-friendly dict for parsed AdmitStatement, mapped to all UI columns.

oci_policy_analysis.common.helpers.for_display_endorse(statement) dict[source]

Display-friendly dict for parsed EndorseStatement, mapped to all UI columns.

Cache Manager

class oci_policy_analysis.common.caching.CacheManager(cache_dir: Path = None)[source]

Bases: object

Handles saving and loading cached JSON data (IAM + AI). Also supports canonical consolidation session persistence: per-tenancy state files for protected_set + plan history. Each cache is tied to a tenancy name and date. The cache directory is ~/.oci-policy-analysis/cache by default, but can be overridden. Caches have the concept of being “preserved” to avoid automatic deletion during culling.

get_or_create_consolidation_state(tenancy_ocid) dict[source]

Load the canonical consolidation state file for this tenancy_ocid. If it does not exist, create a blank state (protected_set={}, history=[]). Returns the state dict; saves it if it was new.

save_consolidation_state(tenancy_ocid, state: dict)[source]

Overwrite the canonical consolidation state file for this tenancy_ocid.

get_protected_set(tenancy_ocid)[source]

Return the protected_set from consolidation state. Creates file if needed.

set_protected_set(tenancy_ocid, protected_set: dict)[source]

Update and persist the protected_set in the canonical consolidation state file.

get_history(tenancy_ocid)[source]

Return the list of run/plan history for this tenancy_ocid. If no tenancy_ocid, returns empty list (safe for new sessions).

add_run_record(tenancy_ocid, run_record: dict)[source]

Append a new run/plan record to history and save the canonical file.

update_run_record(tenancy_ocid: str, consolidation_effort_id: str, updates: dict) bool[source]

Update an existing run record in history by consolidation_effort_id.

Parameters:
  • tenancy_ocid – Tenancy OCID.

  • consolidation_effort_id – Run identifier (plan_id).

  • updates – Dict of fields to merge into the run record (e.g. status, step_status).

remove_run_record(tenancy_ocid: str, consolidation_effort_id: str) bool[source]

Remove a run record from history by consolidation_effort_id.

Parameters:
  • tenancy_ocid – Tenancy OCID.

  • consolidation_effort_id – Run identifier (plan_id) to remove.

list_consolidation_tenancy_ocids() list[str][source]

Return list of tenancy OCIDs that have consolidation state files.

list_all_consolidation_plans() list[dict][source]

Return a flat list of all consolidation plans across tenancies. Each item has tenancy_ocid, consolidation_effort_id, created_at, and run (full record).

save_consolidation_session(session_data: dict, plan_id: str = None, tenancy_ocid: str = None, preserved: bool = False) str[source]

Save a consolidation session (see models_consolidation.ConsolidationSession) to disk as JSON. Returns file name/path. :param session_data: The dict/TypedDict structure matching ConsolidationSession (pluggable, robust to version drift) :param plan_id: Optional label/ID for file naming, else uses timestamp. :param tenancy_ocid: Optional for nested cache structure. :param preserved: Mark this session as not-to-be-deleted.

Returns:

The output file path string.

load_consolidation_session(plan_id: str, tenancy_ocid: str = None) dict | None[source]

Load a consolidation session from cache. :param plan_id: Label/filename (w/o json) for the session/plan. :param tenancy_ocid: Optional subdir

Returns:

session_data (dict) or None

save_combined_cache(policy_analysis: PolicyAnalysisRepository, export_file=None, preserved: bool = False) str[source]

Save combined cache for policies and dynamic groups. Returns file name.

Parameters:
  • export_file – Optional file handle to export to instead of saving to cache directory

  • preserved – Whether to mark this cache as preserved (not auto-deleted)

Returns:

The name of the file saved

load_combined_cache(policy_analysis: PolicyAnalysisRepository, named_cache: str) str[source]

Load combined cache for policies and dynamic groups.

Given the name and data of a cache, loads the data into both of the centralized structures for Compartment/Policy JSON storage.

Parameters:

named_cache – The tenancy_date string of the cache name to load

Returns:

A string indicating the name of the file used

load_cache_from_json(policy_analysis: PolicyAnalysisRepository, loaded_json: dict) bool[source]

Load combined cache data from a given JSON dict. Given loaded JSON data, loads the data into both of the centralized structures for Compartment/Policy JSON storage.

Parameters:

loaded_json – The loaded JSON data as a dict

get_preserved_cache_set() set[source]

Get a set of cache names which are marked as preserved.

get_available_cache(tenancy_name: str | None) list[str][source]

Get available cache files for a given profile

If given no argument, simply return the list of all avialable cache files that exist in the cache directory. Entries will contain the tenancy name and date loaded.

Parameters:
  • tenancy_name – The name of an OCI tenancy, which will filter the cache list down to only

  • tenancy. (caches for that)

Returns:

a list of the available named caches

load_cache_into_local_json(cached_tenancy: str) dict[source]

Takes a named cache (tenancy_date) and returns the loaded JSON data as a dict. Used for exporting or other purposes.

Parameters:

cached_tenancy – The tenancy_date string of the cache name to load

Returns:

The loaded cache data as a dict

remove_cache_entry(named_cache: str) bool[source]

Remove specified cache file AND its entry from cache_entries.json.

Parameters:

named_cache – The tenancy_date string of the cache name to remove

Returns:

True if both file and entry were removed, False otherwise

rename_cache_entry(old_named_cache: str, new_named_cache: str) bool[source]

Rename both the cache file and its entry in cache_entries.json.

Parameters:
  • old_named_cache – The current tenancy_date string of the cache name

  • new_named_cache – The new tenancy_date string of the cache name

Returns:

True if both file and entry were renamed, False otherwise. Returns False (and does NOT rename) if a cache file or entry already exists with the new name.

preserve_cache_entry(named_cache: str, preserve: bool = True) bool[source]

Mark or unmark a cache entry as preserved in cache_entries.json.

Parameters:
  • named_cache – The tenancy_date string of the cache name to update

  • preserve – True to mark as preserved, False to unmark

Returns:

True if the entry was updated, False otherwise

update_policy_section(policy_analysis: PolicyAnalysisRepository, policy_data_reloaded: str | None)[source]

Update ONLY the policies, policy_statements, compartments, defined_aliases, and cross_tenancy_statements in the most recent cache file for a given tenancy, and set ‘policy_data_reloaded’ with the supplied timestamp. This preserves IAM/user/group data and other session metadata. No effect if no cache is present.

Parameters:
  • policy_analysis – PolicyAnalysisRepository with fresh policy/compartment data in memory

  • policy_data_reloaded – ISO timestamp string for reloaded policy data

Global Logger

class oci_policy_analysis.common.logger.ForceFlushStreamHandler(stream=None)[source]

Bases: StreamHandler

A stream handler that flushes after every emit, ensuring logs always show up immediately—even from threads.

emit(record)[source]

Emit a record.

If a formatter is specified, it is used to format the record. The record is then written to the stream with a trailing newline. If exception information is present, it is formatted using traceback.print_exception and appended to the stream. If the stream has an ‘encoding’ attribute, it is used to determine how to do the output to the stream.

oci_policy_analysis.common.logger.get_logger(component: str | None = None) Logger[source]

Return a component logger. No handlers added (propagate to root).

Parameters:

component – Component name (e.g., ‘cli’, ‘data_repo’). If None, uses base name.

Returns:

Logger instance.

oci_policy_analysis.common.logger.set_log_level(level: str | int) None[source]

Set root logger level (affects all non-overridden loggers).

  • Use for global (root) logging threshold, e.g., on app startup or when user changes global log level.

  • When –verbose is active, will force DEBUG everywhere (but UI always filters DEBUG).

  • Do not use to configure UI/ConsoleTab handler; that always filters at INFO+.

Options:
  • CRITICAL 50

  • ERROR 40

  • WARNING 30

  • INFO 20

  • DEBUG 10

Parameters:

level – Level name (e.g., ‘DEBUG’) or int.

oci_policy_analysis.common.logger.set_component_level(component: str, level: str | int) None[source]

Set level for a specific logger (app or third-party). Component can be full logger name (with dots) or just base name. Example: set_component_level(‘cli’, ‘DEBUG’)

Parameters:
  • component – Component/logger name (e.g., ‘cli’, ‘data_repo’, ‘requests’)

  • level – Level name (e.g., ‘DEBUG’) or int.