# Project-Scoped Resource Validation Flow in connection.py: OpenStack Multi-Tenant Security

> Secure your OpenStack multi-tenant environment. Discover the project-scoped resource validation flow in connection.py preventing cross-project data leakage and ensuring strict tenant isolation.

- Repository: [JungJungIn/mcp-openstack-ops](https://github.com/call518/mcp-openstack-ops)
- Tags: internals
- Published: 2026-02-26

---

**The project-scoped resource validation flow guarantees strict tenant isolation by verifying that every requested OpenStack resource either belongs to the authenticated project or is explicitly marked as public, thereby preventing cross-project data leakage.**

The `mcp-openstack-ops` repository implements a robust security layer to ensure multi-tenant isolation when interacting with OpenStack APIs. At the heart of this implementation lies the **project-scoped resource validation flow**, a comprehensive pipeline defined in [`src/mcp_openstack_ops/connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/connection.py) that filters all resource access through project ownership verification.

## Core Components of the Validation Pipeline

The validation architecture consists of four interconnected helpers that form a defensive perimeter around resource operations:

1. **`get_current_project_id()`** – Resolves the authenticated session's project identifier.
2. **`validate_resource_ownership()`** – Inspects individual resources for ownership or public visibility.
3. **`find_resource_by_name_or_id()`** – Locates specific resources while applying ownership filters.
4. **`get_project_scoped_resources()`** – Retrieves and sanitizes entire service collections.

These functions work sequentially to ensure that tools in the `tools/` package cannot accidentally expose resources from other tenants.

## Resolving the Current Project Context

The foundation of the project-scoped resource validation flow rests on accurately identifying the active project. The `get_current_project_id()` function (lines 43-73 of [`connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/connection.py)) implements a resilient discovery mechanism:

```python
def get_current_project_id() -> str:
    ...

```

**Token inspection** forms the primary resolution strategy. The function retrieves the authentication token via `conn.identity.get_token()` and extracts the `project_id` field (falling back to legacy `tenant_id` when necessary). If the token lacks this metadata, the implementation executes a **name-based fallback**, iterating through `conn.identity.projects()` to locate a project matching the `OS_PROJECT_NAME` environment variable. This dual-strategy approach ensures compatibility across different OpenStack identity configurations.

## Enforcing Single-Resource Ownership Boundaries

Once the current project is established, the `validate_resource_ownership()` function (lines 78-112) serves as the gatekeeper for individual resource access. This helper accepts any resource object and determines whether it belongs to the current project or qualifies as publicly accessible:

```python
def validate_resource_ownership(resource: Any, resource_type: str = "resource") -> bool:
    ...

```

**Public resource shortcuts** optimize the validation process. If a resource carries an `is_public` flag set to true, the function immediately returns `True`. **Flavor handling** receives special treatment—flavors typically lack `project_id` attributes and are treated as public resources by default. For **image visibility**, the logic recognizes `public`, `community`, and `shared` visibility states as valid bypass conditions.

When public shortcuts don't apply, the function performs **project ID extraction** by checking multiple attribute names: `project_id`, `tenant_id`, and `owner`. If none exist, the resource is classified as a **system resource** and permitted. Finally, the extracted identifier is compared against the current project ID; mismatches generate warnings and return `False`, effectively blocking unauthorized access.

## Scoped Resource Discovery and Retrieval

For operations requiring specific resource lookup, `find_resource_by_name_or_id()` (lines 135-176) combines search functionality with ownership validation:

```python
def find_resource_by_name_or_id(resources, name_or_id: str, resource_type: str = "resource") -> Optional[Any]:
    ...

```

The implementation iterates through the supplied `resources` iterable, collecting candidates where either `name` or `id` matches the query parameter. Each candidate then passes through `validate_resource_ownership()`. The function returns `None` if no owned matches exist, or the first valid match when multiple candidates are found (logging a warning about ambiguity).

For bulk operations, `get_project_scoped_resources()` (lines 188-207) provides comprehensive collection filtering:

```python
def get_project_scoped_resources(conn, service_attr: str, resource_type: str = "resource") -> list:
    ...

```

This helper obtains the service object via `getattr(conn, service_attr)` (e.g., `"compute"` for Nova), converts the service iterator to a list, and builds a filtered result set containing only resources passing the ownership validation.

## Practical Implementation Examples

### Retrieving a Server by Name with Project Scoping

When searching for a specific instance, tools combine connection establishment with the validation flow:

```python
from mcp_openstack_ops.connection import get_openstack_connection, find_resource_by_name_or_id

def get_my_server(name_or_id):
    conn = get_openstack_connection()
    all_servers = conn.compute.servers()
    server = find_resource_by_name_or_id(
        all_servers,
        name_or_id,
        resource_type="server"
    )
    if server:
        print(f"Found server {server.id} in current project")
    else:
        print("Server not found or not owned by this project")

```

This pattern ensures that even if another project contains a server with an identical name, only the current project's resources are returned.

### Listing All Project-Scoped Networks

To enumerate network resources without cross-project leakage:

```python
from mcp_openstack_ops.connection import get_openstack_connection, get_project_scoped_resources

def list_my_networks():
    conn = get_openstack_connection()
    networks = get_project_scoped_resources(conn, "network", "network")
    for net in networks:
        print(f"{net.id}: {net.name}")

```

The function automatically excludes networks owned by other tenants while preserving public networks when applicable.

### Pre-Deletion Ownership Verification

Before executing destructive operations, explicit validation provides an additional safety layer:

```python
from mcp_openstack_ops.connection import get_openstack_connection, validate_resource_ownership

def delete_my_volume(volume_id):
    conn = get_openstack_connection()
    volume = conn.block_storage.get_volume(volume_id)
    if validate_resource_ownership(volume, "volume"):
        conn.block_storage.delete_volume(volume, ignore_missing=False)
        print("Volume deleted")
    else:
        print("Cannot delete: volume belongs to another project")

```

## Summary

The project-scoped resource validation flow in [`connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/connection.py) provides a comprehensive security framework for OpenStack automation:

- **Token-based project resolution** ensures accurate identification of the authenticated context through `get_current_project_id()`.
- **Multi-factor ownership checks** in `validate_resource_ownership()` handle public resources, flavors, images, and system objects appropriately.
- **Integrated search and filter** operations via `find_resource_by_name_or_id()` and `get_project_scoped_resources()` prevent cross-project data exposure.
- **Verbose warning logs** alert operators when ownership mismatches occur, aiding in debugging without breaking execution flows.

## Frequently Asked Questions

### How does the validation flow handle public images in OpenStack?

Public images bypass project ownership checks through the visibility attribute. The `validate_resource_ownership()` function recognizes images with `visibility` set to `public`, `community`, or `shared` as valid resources regardless of their `owner` field, allowing tools to discover and utilize shared infrastructure images while maintaining isolation for private assets.

### What happens when a resource lacks a project_id attribute?

Resources without `project_id`, `tenant_id`, or `owner` attributes are classified as system resources and permitted by default. This design accommodates OpenStack service objects like public flavors and certain system images that exist outside standard project ownership models but are intended for universal access.

### Can the validation flow be bypassed for administrative operations?

The validation flow cannot be bypassed through the provided helper functions in [`connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/connection.py). Administrative tools requiring cross-project visibility must use the raw OpenStack SDK connection methods directly rather than the `find_resource_by_name_or_id()` or `get_project_scoped_resources()` wrappers, ensuring that standard operations maintain strict project isolation by default.

### Where is the project-scoped validation logic located in the codebase?

The core validation logic resides in [`src/mcp_openstack_ops/connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/connection.py), specifically lines 43-207, implementing the four primary helper functions. Consumer tools throughout `src/mcp_openstack_ops/tools/` import these functions to enforce project isolation, with test coverage provided in [`test_project_isolation.py`](https://github.com/call518/mcp-openstack-ops/blob/main/test_project_isolation.py) to verify the isolation mechanisms function correctly across different resource types.