> ## Documentation Index
> Fetch the complete documentation index at: https://www.osohq.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Policy Management

> Deploy and manage Polar authorization policies in Oso Cloud. 

export const Languages = {
  JAVASCRIPT: "js",
  PYTHON: "py",
  RUBY: "rb",
  JAVA: "java",
  DOTNET: "dotnet",
  GO: "go",
  SHELL: "shell",
  MACOS: "macos",
  WINDOWS: "windows",
  BASH: "bash",
  CMD: "cmd",
  TYPESCRIPT: "ts",
  HTML: "html",
  CSS: "css",
  JSON: "json",
  YAML: "yaml",
  XML: "xml"
};

export const CodeTab = ({title, language, children, disabled = false}) => {
  const getLanguageDisplayName = language => {
    const displayNames = {
      [Languages.JAVASCRIPT]: "JavaScript",
      [Languages.PYTHON]: "Python",
      [Languages.RUBY]: "Ruby",
      [Languages.JAVA]: "Java",
      [Languages.DOTNET]: ".NET",
      [Languages.GO]: "Go",
      [Languages.SHELL]: "Shell",
      [Languages.MACOS]: "MacOS / Linux",
      [Languages.WINDOWS]: "Windows",
      [Languages.CMD]: "Command Prompt",
      [Languages.TYPESCRIPT]: "TypeScript",
      [Languages.HTML]: "HTML",
      [Languages.CSS]: "CSS",
      [Languages.JSON]: "JSON",
      [Languages.YAML]: "YAML",
      [Languages.XML]: "XML"
    };
    return displayNames[language] || language || "Code";
  };
  const displayTitle = title || getLanguageDisplayName(language);
  if (!displayTitle) {
    console.warn('CodeTab component requires either a title prop or language prop');
    return null;
  }
  if (language && typeof language !== 'string') {
    console.warn('CodeTab language prop must be a string');
  }
  if (title && typeof title !== 'string') {
    console.warn('CodeTab title prop must be a string');
  }
  if (disabled && typeof disabled !== 'boolean') {
    console.warn('CodeTab disabled prop must be a boolean');
  }
  return React.createElement(React.Fragment, null, children);
};

export const CodeTabs = ({children, defaultTab = 0, className = '', syncLanguages = true, onTabChange, 'aria-label': ariaLabel = 'Code examples'}) => {
  const {useState, useMemo, useEffect, useCallback, useId, Children, isValidElement} = React;
  const baseId = useId();
  const getLanguageDisplayName = useCallback(language => {
    const displayNames = {
      [Languages.JAVASCRIPT]: "JavaScript",
      [Languages.PYTHON]: "Python",
      [Languages.RUBY]: "Ruby",
      [Languages.JAVA]: "Java",
      [Languages.DOTNET]: ".NET",
      [Languages.GO]: "Go",
      [Languages.SHELL]: "Shell",
      [Languages.MACOS]: "MacOS / Linux",
      [Languages.WINDOWS]: "Windows",
      [Languages.CMD]: "Command Prompt",
      [Languages.TYPESCRIPT]: "TypeScript",
      [Languages.HTML]: "HTML",
      [Languages.CSS]: "CSS",
      [Languages.JSON]: "JSON",
      [Languages.YAML]: "YAML",
      [Languages.XML]: "XML"
    };
    return displayNames[language] || language || "Code";
  }, []);
  const LANGUAGE_PREF_KEY = useMemo(() => 'mintlify-tabs-language-preference', []);
  const LANGUAGE_CHANGE_EVENT = useMemo(() => 'mintlify-tabs-language-change', []);
  const findMatchingLanguageTab = useCallback((tabs, targetLanguage) => {
    if (!targetLanguage?.trim() || !Array.isArray(tabs) || tabs.length === 0) return -1;
    const normalizedTarget = targetLanguage.toLowerCase().trim();
    return tabs.findIndex(tab => tab?.language?.toLowerCase().trim() === normalizedTarget);
  }, []);
  const getLanguagePreference = useCallback(() => {
    if (typeof window === 'undefined' || !window.localStorage) return null;
    try {
      const stored = localStorage.getItem(LANGUAGE_PREF_KEY);
      if (!stored) return null;
      const parsed = JSON.parse(stored);
      if (typeof parsed === 'object' && parsed.language && typeof parsed.language === 'string') {
        return parsed;
      }
      return null;
    } catch (error) {
      console.warn('Failed to parse language preference:', error);
      return null;
    }
  }, [LANGUAGE_PREF_KEY]);
  const setLanguagePreference = useCallback(language => {
    if (typeof window === 'undefined' || !window.localStorage || !language?.trim()) return;
    try {
      const preference = {
        language: language.trim(),
        timestamp: Date.now()
      };
      localStorage.setItem(LANGUAGE_PREF_KEY, JSON.stringify(preference));
      if (window.CustomEvent && window.dispatchEvent) {
        const event = new CustomEvent(LANGUAGE_CHANGE_EVENT, {
          detail: preference,
          bubbles: false,
          cancelable: false
        });
        window.dispatchEvent(event);
      }
    } catch (error) {
      console.warn('Failed to save language preference:', error);
    }
  }, [LANGUAGE_PREF_KEY, LANGUAGE_CHANGE_EVENT]);
  const generateTabId = useCallback((title, index) => {
    const cleanTitle = title?.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '') || 'tab';
    return `${baseId}-${cleanTitle}-${index}`;
  }, [baseId]);
  const [announcement, setAnnouncement] = useState('');
  const announceToScreenReader = useCallback((message, duration = 1000) => {
    setAnnouncement(message);
    const timeoutId = setTimeout(() => setAnnouncement(''), duration);
    return () => clearTimeout(timeoutId);
  }, []);
  const processedTabs = useMemo(() => {
    if (!children) return [];
    const tabData = [];
    Children.forEach(children, (child, index) => {
      if (!isValidElement(child) || child.type !== CodeTab) {
        console.warn(`Invalid child at index ${index}. Expected CodeTab component.`);
        return;
      }
      const {title, language, disabled = false} = child.props || ({});
      const displayTitle = title || getLanguageDisplayName(language);
      if (!displayTitle || typeof displayTitle !== 'string') {
        console.warn(`CodeTab at index ${index} missing title and language props`);
        return;
      }
      tabData.push({
        title: displayTitle.trim(),
        language: language?.trim() || null,
        disabled: Boolean(disabled),
        content: child.props.children,
        id: generateTabId(displayTitle, index),
        index
      });
    });
    return tabData;
  }, [children, generateTabId]);
  const [activeIndex, setActiveIndex] = useState(0);
  useEffect(() => {
    if (processedTabs.length === 0) return;
    if (typeof defaultTab === 'number') {
      const clampedIndex = Math.max(0, Math.min(defaultTab, processedTabs.length - 1));
      setActiveIndex(clampedIndex);
      return;
    }
    if (typeof defaultTab === 'string' && defaultTab.trim()) {
      const matchIndex = processedTabs.findIndex(tab => tab.title?.toLowerCase() === defaultTab.toLowerCase().trim());
      if (matchIndex >= 0 && !processedTabs[matchIndex].disabled) {
        setActiveIndex(matchIndex);
        return;
      }
    }
    const firstEnabledIndex = processedTabs.findIndex(tab => !tab.disabled);
    setActiveIndex(firstEnabledIndex >= 0 ? firstEnabledIndex : 0);
  }, [processedTabs, defaultTab]);
  useEffect(() => {
    if (!syncLanguages || processedTabs.length === 0) return;
    const preference = getLanguagePreference();
    if (preference) {
      const matchIndex = findMatchingLanguageTab(processedTabs, preference.language);
      if (matchIndex >= 0) {
        setActiveIndex(matchIndex);
      }
    }
  }, [syncLanguages, processedTabs, getLanguagePreference, findMatchingLanguageTab]);
  const handleTabClick = useCallback(index => {
    const targetTab = processedTabs[index];
    if (!targetTab || targetTab.disabled || index === activeIndex) return;
    const previousIndex = activeIndex;
    setActiveIndex(index);
    const announcement = `${targetTab.title} tab selected. Tab ${index + 1} of ${processedTabs.length}.`;
    const cleanup = announceToScreenReader(announcement);
    if (syncLanguages && targetTab.language) {
      setLanguagePreference(targetTab.language);
    }
    onTabChange?.(index, targetTab, previousIndex);
    return cleanup;
  }, [processedTabs, activeIndex, syncLanguages, setLanguagePreference, onTabChange, announceToScreenReader]);
  useEffect(() => {
    if (!syncLanguages || typeof window === 'undefined') return;
    const handleLanguageChange = event => {
      try {
        const {language} = event.detail || ({});
        if (!language || typeof language !== 'string') return;
        const matchIndex = findMatchingLanguageTab(processedTabs, language);
        if (matchIndex >= 0 && matchIndex !== activeIndex && !processedTabs[matchIndex]?.disabled) {
          setActiveIndex(matchIndex);
          const currentTab = processedTabs[matchIndex];
          const announcement = `Synchronized to ${currentTab.title} tab. Tab ${matchIndex + 1} of ${processedTabs.length}.`;
          announceToScreenReader(announcement, 600);
          onTabChange?.(matchIndex, currentTab, activeIndex);
        }
      } catch (error) {
        console.warn('Error handling language change event:', error);
      }
    };
    window.addEventListener(LANGUAGE_CHANGE_EVENT, handleLanguageChange);
    return () => {
      window.removeEventListener(LANGUAGE_CHANGE_EVENT, handleLanguageChange);
    };
  }, [syncLanguages, processedTabs, activeIndex, findMatchingLanguageTab, LANGUAGE_CHANGE_EVENT, onTabChange, announceToScreenReader]);
  const handleKeyDown = useCallback((event, index) => {
    let targetIndex = -1;
    switch (event.key) {
      case 'ArrowLeft':
        event.preventDefault();
        targetIndex = index > 0 ? index - 1 : processedTabs.length - 1;
        break;
      case 'ArrowRight':
        event.preventDefault();
        targetIndex = index < processedTabs.length - 1 ? index + 1 : 0;
        break;
      case 'Enter':
      case ' ':
        event.preventDefault();
        handleTabClick(index);
        return;
      case 'Home':
        event.preventDefault();
        targetIndex = 0;
        break;
      case 'End':
        event.preventDefault();
        targetIndex = processedTabs.length - 1;
        break;
      default:
        return;
    }
    if (targetIndex !== -1) {
      setActiveIndex(targetIndex);
    }
  }, [processedTabs.length, handleTabClick]);
  if (processedTabs.length === 0) {
    return <div className="p-4 text-gray-500 italic text-center border border-gray-200 rounded-lg">
        No valid tabs found. Please check your CodeTab components.
      </div>;
  }
  const safeActiveIndex = Math.max(0, Math.min(activeIndex, processedTabs.length - 1));
  const activeTab = processedTabs[safeActiveIndex];
  return <div className={`tabs tab-container ${className}`} id={activeTab?.language || 'code-tabs'}>
      {}
      <div aria-live="polite" aria-atomic="true" className="sr-only">
        {announcement}
      </div>

      {}
      <ul role="tablist" aria-label={ariaLabel} className="not-prose mb-6 pb-[1px] flex-none min-w-full overflow-auto border-b border-gray-200 gap-x-6 flex dark:border-gray-200/10" data-component-part="tabs-list">
        {processedTabs.map((tab, index) => {
    const isActive = index === safeActiveIndex;
    const isDisabled = tab.disabled;
    return <li key={tab.id} id={tab.id} className="cursor-pointer">
              <button role="tab" aria-selected={isActive} aria-controls={`${tab.id}-panel`} aria-disabled={isDisabled} aria-setsize={processedTabs.length} aria-posinset={index + 1} tabIndex={isActive ? 0 : -1} disabled={isDisabled} onClick={() => handleTabClick(index)} onKeyDown={e => handleKeyDown(e, index)} className={isDisabled ? 'flex text-sm items-center gap-1.5 leading-6 font-semibold whitespace-nowrap pt-3 pb-2.5 -mb-px max-w-max border-b text-gray-400 border-transparent cursor-not-allowed opacity-50' : isActive ? 'flex text-sm items-center gap-1.5 leading-6 font-semibold whitespace-nowrap pt-3 pb-2.5 -mb-px max-w-max border-b text-primary dark:text-primary-light border-current' : 'flex text-sm items-center gap-1.5 leading-6 font-semibold whitespace-nowrap pt-3 pb-2.5 -mb-px max-w-max border-b text-gray-900 border-transparent hover:border-gray-300 dark:text-gray-200 dark:hover:border-gray-700'} data-component-part="tab-button" data-active={isActive}>
                {tab.title}
              </button>
            </li>;
  })}
      </ul>

      {}
      <div role="tabpanel" id={`${activeTab?.id}-panel`} aria-labelledby={activeTab?.id} aria-label={`${activeTab?.title} content, tab panel ${safeActiveIndex + 1} of ${processedTabs.length}`} tabIndex={0} className="prose dark:prose-dark overflow-x-auto" data-component-part="tab-content">
        {activeTab?.content}
      </div>
    </div>;
};

## Update Policy

Deploy or update your authorization policy in Oso Cloud.

<CodeTabs>
  <CodeTab title="Node.js" language={Languages.JAVASCRIPT}>
    ```javascript theme={null}
    // Update policy with Polar code
    await oso.policy("actor User {}");

    // Example with a complete policy
    const policyCode = `
      actor User {}
      resource Repository {
        permissions = ["read", "write"];
        roles = ["owner", "maintainer"];
      }
      has_role(user: User, "owner", repo: Repository) if
        user.id = repo.owner_id;
    `;
    await oso.policy(policyCode);
    ```

    **Signature:** `oso.policy(policy)`
  </CodeTab>

  <CodeTab language={Languages.PYTHON}>
    ```python theme={null}
    # Update policy with Polar code
    oso.policy("actor User {}")

    # Example with a complete policy
    policy_code = """
    actor User {}
    resource Repository {
        permissions = ["read", "write"];
        roles = ["owner", "maintainer"];
    }
    has_role(user: User, "owner", repo: Repository) if
        user.id = repo.owner_id;
    """
    oso.policy(policy_code)
    ```

    **Signature:** `oso.policy(policy)`
  </CodeTab>

  <CodeTab language={Languages.GO}>
    ```go theme={null}
    // Update policy with Polar code
    err := osoClient.Policy("actor User {}")
    if err != nil {
        log.Fatal(err)
    }

    // Example with a complete policy
    policyCode := `
    actor User {}
    resource Repository {
        permissions = ["read", "write"];
        roles = ["owner", "maintainer"];
    }
    has_role(user: User, "owner", repo: Repository) if
        user.id = repo.owner_id;
    `
    err = osoClient.Policy(policyCode)
    ```

    **Signature:** `osoClient.Policy(policy)`
  </CodeTab>

  <CodeTab language={Languages.JAVA}>
    ```java theme={null}
    // Update policy with Polar code
    oso.policy("actor User {}");

    // Example with a complete policy
    String policyCode = """
        actor User {}
        resource Repository {
            permissions = ["read", "write"];
            roles = ["owner", "maintainer"];
        }
        has_role(user: User, "owner", repo: Repository) if
            user.id = repo.owner_id;
        """;
    oso.policy(policyCode);
    ```

    **Signature:** `oso.policy(policy)`
  </CodeTab>

  <CodeTab language={Languages.RUBY}>
    ```ruby theme={null}
    # Update policy with Polar code
    oso.policy("actor User {}")

    # Example with a complete policy
    policy_code = <<~POLAR
      actor User {}
      resource Repository {
        permissions = ["read", "write"];
        roles = ["owner", "maintainer"];
      }
      has_role(user: User, "owner", repo: Repository) if
        user.id = repo.owner_id;
    POLAR
    oso.policy(policy_code)
    ```

    **Signature:** `oso.policy(policy)`
  </CodeTab>

  <CodeTab language={Languages.DOTNET}>
    ```csharp theme={null}
    // Update policy with Polar code
    await oso.Policy("actor User {}");

    // Example with a complete policy
    var policyCode = @"
        actor User {}
        resource Repository {
            permissions = [""read"", ""write""];
            roles = [""owner"", ""maintainer""];
        }
        has_role(user: User, ""owner"", repo: Repository) if
            user.id = repo.owner_id;
    ";
    await oso.Policy(policyCode);
    ```

    **Signature:** `oso.Policy(policy)`
  </CodeTab>

  <CodeTab title="CLI" language={Languages.BASH}>
    ```bash theme={null}
    # Update policy from file
    oso-cloud policy main.polar

    # Update with multiple files
    oso-cloud policy main.polar secondary.polar

    # Force update (skip confirmation)
    oso-cloud policy main.polar --force

    # Preview changes without applying
    oso-cloud policy main.polar --preview
    ```

    **Signature:** `oso-cloud policy <policy-file> <policy-file2> ...`

    ### Test Policy

    ```bash theme={null}
    # Test policy files
    oso-cloud test main.polar

    # Test multiple files
    oso-cloud test main.polar secondary.polar
    ```

    **Signature:** `oso-cloud test <policy-file> <policy-file2> ...`
  </CodeTab>
</CodeTabs>

## Get Policy Metadata

Retrieve metadata about your deployed policy, including available resources, permissions, and roles.

<CodeTabs>
  <CodeTab title="Node.js" language={Languages.JAVASCRIPT}>
    ```javascript theme={null}
    // Get policy metadata
    const metadata = await oso.getPolicyMetadata();

    // Access resource information
    console.log(metadata.resources.keys());        // List all resources
    console.log(metadata.resources.get("Repository")); // Get specific resource metadata
    ```

    **Signature:** `oso.getPolicyMetadata()`
  </CodeTab>

  <CodeTab language={Languages.PYTHON}>
    ```python theme={null}
    # Get policy metadata
    metadata = oso.get_policy_metadata()

    # Access resource information
    print(metadata.resources.keys())               # List all resources
    print(metadata.resources["Repository"])        # Get specific resource metadata
    ```

    **Signature:** `oso.get_policy_metadata()`
  </CodeTab>

  <CodeTab language={Languages.GO}>
    ```go theme={null}
    // Get policy metadata
    metadata, err := osoClient.GetPolicyMetadata()
    if err != nil {
        log.Fatal(err)
    }

    // Access resource information
    for resourceName := range metadata.Resources {
        fmt.Printf("Resource: %s\n", resourceName)
    }
    ```

    **Signature:** `osoClient.GetPolicyMetadata()`
  </CodeTab>

  <CodeTab language={Languages.JAVA}>
    ```java theme={null}
    // Get policy metadata
    PolicyMetadata metadata = oso.getPolicyMetadata();

    // Access resource information
    System.out.println(metadata.getResources().keySet());  // List all resources
    System.out.println(metadata.getResources().get("Repository")); // Get specific resource
    ```

    **Signature:** `oso.getPolicyMetadata()`
  </CodeTab>

  <CodeTab language={Languages.RUBY}>
    ```ruby theme={null}
    # Get policy metadata
    metadata = oso.get_policy_metadata

    # Access resource information
    puts metadata.resources.keys                   # List all resources
    puts metadata.resources["Repository"]          # Get specific resource metadata
    ```

    **Signature:** `oso.get_policy_metadata`
  </CodeTab>

  <CodeTab language={Languages.DOTNET}>
    ```csharp theme={null}
    // Get policy metadata
    var metadata = await oso.GetPolicyMetadata();

    // Access resource information
    Console.WriteLine(string.Join(", ", metadata.Resources.Keys)); // List all resources
    Console.WriteLine(metadata.Resources["Repository"]);           // Get specific resource
    ```

    **Signature:** `oso.GetPolicyMetadata()`
  </CodeTab>
</CodeTabs>
