Skip to content

Port Cheat Sheet

Overview

Port is an Internal Developer Platform (IDP) that creates a comprehensive developer portal for managing and visualizing your entire software catalog. It provides a unified interface for services, infrastructure, deployments, and developer workflows while enabling self-service capabilities and maintaining governance and compliance standards.

⚠️ Note: Free tier available for small teams. Paid plans start at $20/user/month for advanced features.

Getting Started

Account Setup

# Sign up process:
# 1. Visit getport.io
# 2. Create account with email or SSO
# 3. Set up your organization
# 4. Configure initial data model
# 5. Connect your first data sources

# Initial configuration:
# - Organization settings
# - User roles and permissions
# - Data model design
# - Integration setup
# - Team onboarding

Data Model Design

{
  "identifier": "service",
  "title": "Service",
  "icon": "Service",
  "schema": {
    "properties": {
      "name": {
        "title": "Name",
        "type": "string"
      },
      "description": {
        "title": "Description",
        "type": "string"
      },
      "owner": {
        "title": "Owner",
        "type": "string",
        "format": "team"
      },
      "language": {
        "title": "Language",
        "type": "string",
        "enum": ["Python", "JavaScript", "Java", "Go", "C#"]
      },
      "lifecycle": {
        "title": "Lifecycle",
        "type": "string",
        "enum": ["Production", "Staging", "Development", "Deprecated"]
      },
      "tier": {
        "title": "Tier",
        "type": "string",
        "enum": ["Mission Critical", "Customer Facing", "Internal", "Experimental"]
      }
    },
    "required": ["name", "owner", "lifecycle"]
  }
}

Blueprint Creation

{
  "identifier": "microservice",
  "title": "Microservice",
  "icon": "Microservice",
  "schema": {
    "properties": {
      "name": {
        "title": "Service Name",
        "type": "string"
      },
      "repository": {
        "title": "Repository",
        "type": "string",
        "format": "url"
      },
      "health_status": {
        "title": "Health Status",
        "type": "string",
        "enum": ["Healthy", "Warning", "Critical", "Unknown"]
      },
      "deployment_status": {
        "title": "Deployment Status",
        "type": "string",
        "enum": ["Deployed", "Deploying", "Failed", "Not Deployed"]
      },
      "cpu_usage": {
        "title": "CPU Usage (%)",
        "type": "number"
      },
      "memory_usage": {
        "title": "Memory Usage (%)",
        "type": "number"
      },
      "last_deployment": {
        "title": "Last Deployment",
        "type": "string",
        "format": "date-time"
      }
    }
  },
  "relations": {
    "team": {
      "title": "Team",
      "target": "team",
      "required": true,
      "many": false
    },
    "domain": {
      "title": "Domain",
      "target": "domain",
      "required": false,
      "many": false
    }
  }
}

Data Ingestion

REST API Integration

import requests
import json

# Port API configuration
PORT_API_URL = "https://api.getport.io/v1"
PORT_CLIENT_ID = "your-client-id"
PORT_CLIENT_SECRET = "your-client-secret"

# Get access token
def get_access_token():
    response = requests.post(
        f"{PORT_API_URL}/auth/access_token",
        json={
            "clientId": PORT_CLIENT_ID,
            "clientSecret": PORT_CLIENT_SECRET
        }
    )
    return response.json()["accessToken"]

# Create or update entity
def upsert_entity(blueprint_id, entity_data):
    token = get_access_token()
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    }

    response = requests.post(
        f"{PORT_API_URL}/blueprints/{blueprint_id}/entities",
        headers=headers,
        json=entity_data
    )
    return response.json()

# Example: Create service entity
service_data = {
    "identifier": "user-service",
    "title": "User Service",
    "properties": {
        "name": "User Service",
        "description": "Handles user authentication and management",
        "owner": "backend-team",
        "language": "Python",
        "lifecycle": "Production",
        "tier": "Customer Facing"
    },
    "relations": {
        "team": "backend-team",
        "domain": "authentication"
    }
}

result = upsert_entity("service", service_data)
print(json.dumps(result, indent=2))

Webhook Integration

from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

@app.route('/port-webhook', methods=['POST'])
def handle_port_webhook():
    """Handle incoming webhooks from Port"""
    data = request.json

    # Process different event types
    if data.get('eventType') == 'ENTITY_CREATED':
        handle_entity_created(data)
    elif data.get('eventType') == 'ENTITY_UPDATED':
        handle_entity_updated(data)
    elif data.get('eventType') == 'ENTITY_DELETED':
        handle_entity_deleted(data)

    return jsonify({"status": "success"})

def handle_entity_created(data):
    """Handle entity creation events"""
    entity = data.get('entity', {})
    blueprint = data.get('blueprint', {})

    print(f"New {blueprint.get('identifier')} created: {entity.get('identifier')}")

    # Trigger downstream processes
    if blueprint.get('identifier') == 'service':
        setup_monitoring(entity)
        create_alerts(entity)

def setup_monitoring(entity):
    """Set up monitoring for new service"""
    service_name = entity.get('identifier')
    # Configure monitoring tools
    print(f"Setting up monitoring for {service_name}")

def create_alerts(entity):
    """Create alerts for new service"""
    service_name = entity.get('identifier')
    # Configure alerting
    print(f"Creating alerts for {service_name}")

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

GitHub Integration

# .github/workflows/port-sync.yml
name: Sync with Port

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  sync-to-port:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Extract service metadata
      id: metadata
      run: |
        # Extract metadata from repository
        SERVICE_NAME=$(basename $GITHUB_REPOSITORY)
        LANGUAGE=$(find . -name "*.py" -o -name "*.js" -o -name "*.java" | head -1 | sed 's/.*\.//')

        echo "service_name=$SERVICE_NAME" >> $GITHUB_OUTPUT
        echo "language=$LANGUAGE" >> $GITHUB_OUTPUT

    - name: Update Port entity
      uses: port-labs/port-github-action@v1
      with:
        clientId: ${{ secrets.PORT_CLIENT_ID }}
        clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
        operation: UPSERT
        identifier: ${{ steps.metadata.outputs.service_name }}
        blueprint: service
        properties: |
          {
            "name": "${{ steps.metadata.outputs.service_name }}",
            "repository": "${{ github.repository }}",
            "language": "${{ steps.metadata.outputs.language }}",
            "lifecycle": "Production",
            "last_commit": "${{ github.sha }}"
          }

Kubernetes Integration

# Port Kubernetes exporter
apiVersion: apps/v1
kind: Deployment
metadata:
  name: port-k8s-exporter
  namespace: port-k8s-exporter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: port-k8s-exporter
  template:
    metadata:
      labels:
        app: port-k8s-exporter
    spec:
      serviceAccountName: port-k8s-exporter
      containers:
      - name: port-k8s-exporter
        image: ghcr.io/port-labs/port-k8s-exporter:latest
        env:
        - name: PORT_CLIENT_ID
          valueFrom:
            secretKeyRef:
              name: port-credentials
              key: clientId
        - name: PORT_CLIENT_SECRET
          valueFrom:
            secretKeyRef:
              name: port-credentials
              key: clientSecret
        - name: CONFIG_YAML
          value: |
            resources:
            - kind: v1/pods
              selector:
                query: .metadata.namespace | startswith("kube") | not
              port:
                entity:
                  mappings:
                  - identifier: .metadata.name + "-" + .metadata.namespace
                    title: .metadata.name
                    blueprint: '"k8s-pod"'
                    properties:
                      namespace: .metadata.namespace
                      status: .status.phase
                      node: .spec.nodeName
                      created: .metadata.creationTimestamp
            - kind: apps/v1/deployments
              port:
                entity:
                  mappings:
                  - identifier: .metadata.name + "-" + .metadata.namespace
                    title: .metadata.name
                    blueprint: '"k8s-deployment"'
                    properties:
                      namespace: .metadata.namespace
                      replicas: .spec.replicas
                      available_replicas: .status.availableReplicas
                      strategy: .spec.strategy.type

Self-Service Actions

Action Definition

{
  "identifier": "deploy_service",
  "title": "Deploy Service",
  "icon": "Deploy",
  "description": "Deploy a service to the specified environment",
  "trigger": {
    "type": "self-service",
    "operation": "CREATE",
    "userInputs": {
      "properties": {
        "environment": {
          "title": "Environment",
          "type": "string",
          "enum": ["development", "staging", "production"],
          "default": "development"
        },
        "version": {
          "title": "Version",
          "type": "string",
          "description": "Docker image tag to deploy"
        },
        "replicas": {
          "title": "Replicas",
          "type": "number",
          "default": 1,
          "minimum": 1,
          "maximum": 10
        },
        "cpu_limit": {
          "title": "CPU Limit",
          "type": "string",
          "default": "500m",
          "enum": ["100m", "250m", "500m", "1000m"]
        },
        "memory_limit": {
          "title": "Memory Limit",
          "type": "string",
          "default": "512Mi",
          "enum": ["256Mi", "512Mi", "1Gi", "2Gi"]
        }
      },
      "required": ["environment", "version"]
    },
    "blueprintIdentifier": "service"
  },
  "invocationMethod": {
    "type": "WEBHOOK",
    "url": "https://api.company.com/deploy",
    "method": "POST",
    "headers": {
      "Authorization": "Bearer {{ .secrets.DEPLOY_TOKEN }}"
    },
    "body": {
      "service": "{{ .entity.identifier }}",
      "environment": "{{ .inputs.environment }}",
      "version": "{{ .inputs.version }}",
      "replicas": "{{ .inputs.replicas }}",
      "resources": {
        "cpu": "{{ .inputs.cpu_limit }}",
        "memory": "{{ .inputs.memory_limit }}"
      }
    }
  }
}

GitHub Actions Integration

{
  "identifier": "create_repository",
  "title": "Create Repository",
  "icon": "Github",
  "description": "Create a new GitHub repository with template",
  "trigger": {
    "type": "self-service",
    "operation": "CREATE",
    "userInputs": {
      "properties": {
        "name": {
          "title": "Repository Name",
          "type": "string",
          "pattern": "^[a-z0-9-]+$"
        },
        "description": {
          "title": "Description",
          "type": "string"
        },
        "template": {
          "title": "Template",
          "type": "string",
          "enum": ["microservice", "frontend", "library", "documentation"]
        },
        "team": {
          "title": "Owning Team",
          "type": "string",
          "format": "team"
        },
        "visibility": {
          "title": "Visibility",
          "type": "string",
          "enum": ["private", "internal", "public"],
          "default": "private"
        }
      },
      "required": ["name", "template", "team"]
    }
  },
  "invocationMethod": {
    "type": "GITHUB",
    "org": "your-org",
    "repo": "platform-workflows",
    "workflow": "create-repository.yml",
    "workflowInputs": {
      "repository_name": "{{ .inputs.name }}",
      "description": "{{ .inputs.description }}",
      "template": "{{ .inputs.template }}",
      "team": "{{ .inputs.team }}",
      "visibility": "{{ .inputs.visibility }}"
    }
  }
}

Terraform Integration

{
  "identifier": "provision_infrastructure",
  "title": "Provision Infrastructure",
  "icon": "Terraform",
  "description": "Provision cloud infrastructure using Terraform",
  "trigger": {
    "type": "self-service",
    "operation": "CREATE",
    "userInputs": {
      "properties": {
        "environment": {
          "title": "Environment",
          "type": "string",
          "enum": ["dev", "staging", "prod"]
        },
        "instance_type": {
          "title": "Instance Type",
          "type": "string",
          "enum": ["t3.micro", "t3.small", "t3.medium", "t3.large"]
        },
        "region": {
          "title": "AWS Region",
          "type": "string",
          "enum": ["us-east-1", "us-west-2", "eu-west-1"]
        },
        "auto_scaling": {
          "title": "Enable Auto Scaling",
          "type": "boolean",
          "default": false
        }
      },
      "required": ["environment", "instance_type", "region"]
    }
  },
  "invocationMethod": {
    "type": "WEBHOOK",
    "url": "https://terraform-api.company.com/provision",
    "method": "POST",
    "headers": {
      "Authorization": "Bearer {{ .secrets.TERRAFORM_TOKEN }}",
      "Content-Type": "application/json"
    },
    "body": {
      "workspace": "{{ .entity.identifier }}-{{ .inputs.environment }}",
      "variables": {
        "environment": "{{ .inputs.environment }}",
        "instance_type": "{{ .inputs.instance_type }}",
        "region": "{{ .inputs.region }}",
        "auto_scaling": "{{ .inputs.auto_scaling }}",
        "service_name": "{{ .entity.identifier }}"
      }
    }
  }
}

Scorecards and Standards

Scorecard Definition

{
  "identifier": "production_readiness",
  "title": "Production Readiness",
  "description": "Measures how ready a service is for production deployment",
  "filter": {
    "combinator": "and",
    "rules": [
      {
        "property": "$blueprint",
        "operator": "=",
        "value": "service"
      },
      {
        "property": "lifecycle",
        "operator": "in",
        "value": ["Production", "Staging"]
      }
    ]
  },
  "rules": [
    {
      "identifier": "has_readme",
      "title": "Has README",
      "description": "Service repository contains a README file",
      "level": "Bronze",
      "query": {
        "combinator": "and",
        "rules": [
          {
            "property": "has_readme",
            "operator": "=",
            "value": true
          }
        ]
      }
    },
    {
      "identifier": "has_tests",
      "title": "Has Tests",
      "description": "Service has automated tests with >80% coverage",
      "level": "Silver",
      "query": {
        "combinator": "and",
        "rules": [
          {
            "property": "test_coverage",
            "operator": ">=",
            "value": 80
          }
        ]
      }
    },
    {
      "identifier": "has_monitoring",
      "title": "Has Monitoring",
      "description": "Service has monitoring and alerting configured",
      "level": "Gold",
      "query": {
        "combinator": "and",
        "rules": [
          {
            "property": "has_monitoring",
            "operator": "=",
            "value": true
          },
          {
            "property": "has_alerts",
            "operator": "=",
            "value": true
          }
        ]
      }
    }
  ]
}

Quality Gates

{
  "identifier": "security_compliance",
  "title": "Security Compliance",
  "description": "Ensures services meet security standards",
  "filter": {
    "combinator": "and",
    "rules": [
      {
        "property": "$blueprint",
        "operator": "=",
        "value": "service"
      }
    ]
  },
  "rules": [
    {
      "identifier": "vulnerability_scan",
      "title": "No Critical Vulnerabilities",
      "description": "Service has no critical security vulnerabilities",
      "level": "Bronze",
      "query": {
        "combinator": "and",
        "rules": [
          {
            "property": "critical_vulnerabilities",
            "operator": "=",
            "value": 0
          }
        ]
      }
    },
    {
      "identifier": "secrets_management",
      "title": "Proper Secrets Management",
      "description": "Service uses proper secrets management",
      "level": "Silver",
      "query": {
        "combinator": "and",
        "rules": [
          {
            "property": "uses_secrets_manager",
            "operator": "=",
            "value": true
          },
          {
            "property": "hardcoded_secrets",
            "operator": "=",
            "value": 0
          }
        ]
      }
    },
    {
      "identifier": "security_review",
      "title": "Security Review Completed",
      "description": "Service has completed security review",
      "level": "Gold",
      "query": {
        "combinator": "and",
        "rules": [
          {
            "property": "security_review_status",
            "operator": "=",
            "value": "approved"
          }
        ]
      }
    }
  ]
}

Dashboards and Visualization

Custom Dashboard

{
  "identifier": "engineering_overview",
  "title": "Engineering Overview",
  "description": "High-level view of engineering metrics",
  "widgets": [
    {
      "id": "services_by_team",
      "title": "Services by Team",
      "type": "pie-chart",
      "dataset": {
        "combinator": "and",
        "rules": [
          {
            "property": "$blueprint",
            "operator": "=",
            "value": "service"
          }
        ]
      },
      "property": "team"
    },
    {
      "id": "deployment_frequency",
      "title": "Deployment Frequency",
      "type": "line-chart",
      "dataset": {
        "combinator": "and",
        "rules": [
          {
            "property": "$blueprint",
            "operator": "=",
            "value": "deployment"
          }
        ]
      },
      "property": "$createdAt",
      "timeframe": "last30days"
    },
    {
      "id": "production_readiness",
      "title": "Production Readiness Score",
      "type": "number",
      "dataset": {
        "combinator": "and",
        "rules": [
          {
            "property": "$blueprint",
            "operator": "=",
            "value": "service"
          },
          {
            "property": "lifecycle",
            "operator": "=",
            "value": "Production"
          }
        ]
      },
      "calculation": "average",
      "property": "$scorecard.production_readiness.level"
    }
  ]
}

Team Dashboard

{
  "identifier": "team_dashboard",
  "title": "Team Dashboard",
  "description": "Team-specific metrics and services",
  "filters": [
    {
      "property": "team",
      "operator": "=",
      "value": "{{ user.team }}"
    }
  ],
  "widgets": [
    {
      "id": "my_services",
      "title": "My Services",
      "type": "table",
      "dataset": {
        "combinator": "and",
        "rules": [
          {
            "property": "$blueprint",
            "operator": "=",
            "value": "service"
          },
          {
            "property": "team",
            "operator": "=",
            "value": "{{ user.team }}"
          }
        ]
      },
      "columns": ["title", "lifecycle", "health_status", "last_deployment"]
    },
    {
      "id": "incident_count",
      "title": "Open Incidents",
      "type": "number",
      "dataset": {
        "combinator": "and",
        "rules": [
          {
            "property": "$blueprint",
            "operator": "=",
            "value": "incident"
          },
          {
            "property": "status",
            "operator": "=",
            "value": "open"
          },
          {
            "property": "assigned_team",
            "operator": "=",
            "value": "{{ user.team }}"
          }
        ]
      }
    }
  ]
}

Advanced Features

Custom Properties with Calculations

{
  "identifier": "service",
  "title": "Service",
  "schema": {
    "properties": {
      "name": {
        "title": "Name",
        "type": "string"
      },
      "cpu_requests": {
        "title": "CPU Requests",
        "type": "number"
      },
      "cpu_limits": {
        "title": "CPU Limits",
        "type": "number"
      },
      "cpu_utilization": {
        "title": "CPU Utilization (%)",
        "type": "number",
        "calculation": {
          "type": "formula",
          "formula": "(cpu_requests / cpu_limits) * 100"
        }
      },
      "cost_per_month": {
        "title": "Monthly Cost",
        "type": "number",
        "format": "currency"
      },
      "cost_per_request": {
        "title": "Cost per Request",
        "type": "number",
        "calculation": {
          "type": "formula",
          "formula": "cost_per_month / (requests_per_month || 1)"
        }
      }
    }
  }
}

Automation Rules

{
  "identifier": "auto_assign_team",
  "title": "Auto-assign Team Based on Repository",
  "description": "Automatically assign team ownership based on repository path",
  "trigger": {
    "type": "entity-created",
    "blueprintIdentifier": "service"
  },
  "conditions": [
    {
      "property": "repository",
      "operator": "contains",
      "value": "/backend/"
    }
  ],
  "actions": [
    {
      "type": "update-entity",
      "properties": {
        "team": "backend-team"
      }
    },
    {
      "type": "send-notification",
      "channel": "slack",
      "message": "New backend service {{ entity.title }} has been registered and assigned to backend-team"
    }
  ]
}

Data Enrichment

# Port data enrichment webhook
from flask import Flask, request, jsonify
import requests
import json

app = Flask(__name__)

@app.route('/enrich-service', methods=['POST'])
def enrich_service():
    """Enrich service data with external information"""
    data = request.json
    entity = data.get('entity', {})

    # Get repository information from GitHub
    repo_url = entity.get('properties', {}).get('repository')
    if repo_url:
        github_data = get_github_metrics(repo_url)

        # Update entity with enriched data
        enriched_properties = {
            **entity.get('properties', {}),
            'stars': github_data.get('stargazers_count', 0),
            'forks': github_data.get('forks_count', 0),
            'open_issues': github_data.get('open_issues_count', 0),
            'last_commit': github_data.get('pushed_at'),
            'primary_language': github_data.get('language')
        }

        # Update Port entity
        update_port_entity(entity['identifier'], enriched_properties)

    return jsonify({"status": "success"})

def get_github_metrics(repo_url):
    """Fetch metrics from GitHub API"""
    # Extract owner/repo from URL
    parts = repo_url.replace('https://github.com/', '').split('/')
    owner, repo = parts[0], parts[1]

    response = requests.get(
        f"https://api.github.com/repos/{owner}/{repo}",
        headers={"Authorization": f"token {GITHUB_TOKEN}"}
    )

    return response.json() if response.status_code == 200 else {}

def update_port_entity(identifier, properties):
    """Update Port entity with enriched data"""
    token = get_port_access_token()

    response = requests.patch(
        f"{PORT_API_URL}/blueprints/service/entities/{identifier}",
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        },
        json={"properties": properties}
    )

    return response.json()

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Monitoring and Observability

Health Checks Integration

import requests
import json
from datetime import datetime

def check_service_health():
    """Check health of all services and update Port"""
    services = get_port_entities("service")

    for service in services:
        health_url = service.get('properties', {}).get('health_endpoint')
        if health_url:
            try:
                response = requests.get(health_url, timeout=10)
                health_status = "Healthy" if response.status_code == 200 else "Unhealthy"
                response_time = response.elapsed.total_seconds() * 1000

                # Update Port entity
                update_port_entity(service['identifier'], {
                    'health_status': health_status,
                    'response_time_ms': response_time,
                    'last_health_check': datetime.utcnow().isoformat()
                })

            except requests.RequestException:
                update_port_entity(service['identifier'], {
                    'health_status': 'Unreachable',
                    'last_health_check': datetime.utcnow().isoformat()
                })

def get_port_entities(blueprint):
    """Fetch entities from Port"""
    token = get_port_access_token()

    response = requests.get(
        f"{PORT_API_URL}/blueprints/{blueprint}/entities",
        headers={"Authorization": f"Bearer {token}"}
    )

    return response.json().get('entities', [])

# Run health checks every 5 minutes
if __name__ == '__main__':
    import schedule
    import time

    schedule.every(5).minutes.do(check_service_health)

    while True:
        schedule.run_pending()
        time.sleep(1)

Metrics Collection

import requests
import json
from prometheus_client.parser import text_string_to_metric_families

def collect_prometheus_metrics():
    """Collect metrics from Prometheus and update Port"""
    services = get_port_entities("service")

    for service in services:
        service_name = service['identifier']

        # Query Prometheus for service metrics
        metrics = {
            'cpu_usage': query_prometheus(f'avg(cpu_usage{{service="{service_name}"}})'),
            'memory_usage': query_prometheus(f'avg(memory_usage{{service="{service_name}"}})'),
            'request_rate': query_prometheus(f'rate(http_requests_total{{service="{service_name}"}}[5m])'),
            'error_rate': query_prometheus(f'rate(http_requests_total{{service="{service_name}",status=~"5.."}[5m])'),
            'p95_latency': query_prometheus(f'histogram_quantile(0.95, http_request_duration_seconds{{service="{service_name}"}})'),
        }

        # Update Port entity with metrics
        update_port_entity(service['identifier'], {
            'cpu_usage_percent': metrics['cpu_usage'],
            'memory_usage_percent': metrics['memory_usage'],
            'requests_per_second': metrics['request_rate'],
            'error_rate_percent': metrics['error_rate'] * 100,
            'p95_latency_ms': metrics['p95_latency'] * 1000,
            'metrics_last_updated': datetime.utcnow().isoformat()
        })

def query_prometheus(query):
    """Query Prometheus for metrics"""
    response = requests.get(
        f"{PROMETHEUS_URL}/api/v1/query",
        params={'query': query}
    )

    data = response.json()
    if data['status'] == 'success' and data['data']['result']:
        return float(data['data']['result'][0]['value'][1])
    return 0

Security and Compliance

RBAC Configuration

{
  "roles": [
    {
      "identifier": "developer",
      "title": "Developer",
      "description": "Standard developer access",
      "permissions": [
        {
          "action": "read",
          "resource": "entity",
          "condition": {
            "property": "team",
            "operator": "=",
            "value": "{{ user.team }}"
          }
        },
        {
          "action": "execute",
          "resource": "action",
          "condition": {
            "property": "identifier",
            "operator": "in",
            "value": ["deploy_service", "restart_service"]
          }
        }
      ]
    },
    {
      "identifier": "team_lead",
      "title": "Team Lead",
      "description": "Team lead with additional permissions",
      "permissions": [
        {
          "action": "*",
          "resource": "entity",
          "condition": {
            "property": "team",
            "operator": "=",
            "value": "{{ user.team }}"
          }
        },
        {
          "action": "execute",
          "resource": "action",
          "condition": {
            "property": "approval_required",
            "operator": "=",
            "value": false
          }
        }
      ]
    },
    {
      "identifier": "platform_admin",
      "title": "Platform Admin",
      "description": "Full platform access",
      "permissions": [
        {
          "action": "*",
          "resource": "*"
        }
      ]
    }
  ]
}

Audit Logging

import json
from datetime import datetime
import logging

# Configure audit logger
audit_logger = logging.getLogger('port_audit')
audit_handler = logging.FileHandler('port_audit.log')
audit_formatter = logging.Formatter('%(asctime)s - %(message)s')
audit_handler.setFormatter(audit_formatter)
audit_logger.addHandler(audit_handler)
audit_logger.setLevel(logging.INFO)

def log_audit_event(event_type, user, entity, action, details=None):
    """Log audit events for compliance"""
    audit_event = {
        'timestamp': datetime.utcnow().isoformat(),
        'event_type': event_type,
        'user': {
            'id': user.get('id'),
            'email': user.get('email'),
            'team': user.get('team')
        },
        'entity': {
            'identifier': entity.get('identifier'),
            'blueprint': entity.get('blueprint'),
            'title': entity.get('title')
        },
        'action': action,
        'details': details or {},
        'ip_address': get_client_ip(),
        'user_agent': get_user_agent()
    }

    audit_logger.info(json.dumps(audit_event))

# Example usage in webhook handler
@app.route('/port-action', methods=['POST'])
def handle_port_action():
    data = request.json

    # Log the action execution
    log_audit_event(
        event_type='action_executed',
        user=data.get('trigger', {}).get('by', {}),
        entity=data.get('entity', {}),
        action=data.get('action', {}).get('identifier'),
        details={
            'inputs': data.get('payload', {}).get('inputs', {}),
            'run_id': data.get('run', {}).get('id')
        }
    )

    # Process the action
    result = process_action(data)

    # Log the result
    log_audit_event(
        event_type='action_completed',
        user=data.get('trigger', {}).get('by', {}),
        entity=data.get('entity', {}),
        action=data.get('action', {}).get('identifier'),
        details={
            'status': result.get('status'),
            'duration': result.get('duration'),
            'output': result.get('output')
        }
    )

    return jsonify(result)

Best Practices

Data Model Design

# Best practices for blueprint design:
# 1. Start with core entities (services, teams, environments)
# 2. Use consistent naming conventions
# 3. Define clear relationships between entities
# 4. Include metadata for governance (owner, lifecycle, tier)
# 5. Plan for scalability and evolution
# 6. Use enums for standardized values
# 7. Include validation rules
# 8. Design for automation and self-service

Integration Strategy

# Integration best practices:
# 1. Start with read-only integrations
# 2. Implement gradual data ingestion
# 3. Use webhooks for real-time updates
# 4. Implement proper error handling and retries
# 5. Monitor integration health
# 6. Use batch processing for large datasets
# 7. Implement data validation and cleansing
# 8. Plan for data migration and evolution

Self-Service Design

# Self-service action design:
# 1. Design for common use cases first
# 2. Provide clear input validation
# 3. Include helpful descriptions and examples
# 4. Implement proper approval workflows
# 5. Provide feedback and status updates
# 6. Include rollback capabilities
# 7. Monitor action usage and success rates
# 8. Iterate based on user feedback

Governance and Compliance

# Governance best practices:
# 1. Implement proper RBAC from the start
# 2. Enable comprehensive audit logging
# 3. Define clear ownership models
# 4. Implement quality gates and scorecards
# 5. Regular compliance reviews
# 6. Automate policy enforcement
# 7. Provide training and documentation
# 8. Monitor and measure adoption

Troubleshooting

Common Issues

# API authentication issues
# 1. Verify client ID and secret
# 2. Check token expiration
# 3. Validate API permissions
# 4. Review rate limiting

# Data ingestion problems
# 1. Check webhook endpoints
# 2. Validate JSON schema
# 3. Review entity relationships
# 4. Check for duplicate identifiers

# Performance issues
# 1. Optimize API queries
# 2. Implement proper caching
# 3. Use batch operations
# 4. Monitor rate limits

Debug Tools

# Port API debugging utility
import requests
import json

def debug_port_api(endpoint, method='GET', data=None):
    """Debug Port API calls with detailed logging"""
    token = get_port_access_token()

    headers = {
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    }

    print(f"Making {method} request to: {PORT_API_URL}{endpoint}")
    print(f"Headers: {json.dumps(headers, indent=2)}")

    if data:
        print(f"Request body: {json.dumps(data, indent=2)}")

    response = requests.request(
        method=method,
        url=f"{PORT_API_URL}{endpoint}",
        headers=headers,
        json=data
    )

    print(f"Response status: {response.status_code}")
    print(f"Response headers: {dict(response.headers)}")
    print(f"Response body: {json.dumps(response.json(), indent=2)}")

    return response

# Example usage
debug_port_api('/blueprints/service/entities')

Resources

Documentation

Community

Training