Skip to content

Repository files navigation

Swift-OPA-SDK

Swift 6.1+

Swift-OPA-SDK is a Swift package that extends Swift OPA with a higher-level interface and extended features.

Adding Swift-OPA-SDK as a Dependency

Package.swift

let package = Package(
    // required minimum versions for using swift-opa-sdk
    platforms: [
        .macOS(.v15),
        .iOS(.v18),
    ],
    // name, platforms, products, etc.
    dependencies: [
        .package(url: "https://github.com/open-policy-agent/swift-opa-sdk", branch: "main"),
        // other dependencies
    ],
    targets: [
        // or libraryTarget
        .executableTarget(name: "<target-name>", dependencies: [
            .product(name:"SwiftOPASDK", package: "swift-opa-sdk"),
            // other dependencies
        ]),
        // other targets
    ]
)

Usage

The core of the Swift OPA SDK is the OPA.Runtime type. It represents an instance of a Rego policy engine, and can be started with several options that control configuration, logging, and lifecycle.

The Runtime is intended to provide a "policy decision point (PDP) in a box", and is meant to be embedded into larger Swift applications. Once configured, the Runtime will automatically handle applying updates to the underlying policy and data stores as needed.

Here's a basic usage example (assumes you already have a valid OPA config and policy bundles available):

import Yams // https://github.com/jpsim/Yams
import Foundation
import SwiftOPASDK

// Fetch config from YAML file on-disk.
let configURL = URL(fileURLWithPath: "config.yaml", relativeTo: URL(fileURLWithPath: FileManager.default.currentDirectoryPath))
let config = try YAMLDecoder().decode(OPA.Config.self, from: Data(contentsOf: configURL)

// Start the runtime, and launch its background worker tasks.
let runtime = await OPA.Runtime(config: config)
let runtimeTask = Task { try await runtime.run() }

// Make policy decisions at any time while run() is active.
let result = try await runtime.decision("authz/allow", input: myInput)

// Shut down when done.
runtimeTask.cancel()

Its APIs are inspired by OPA's sdk.OPA type in the Go sdk library.

RegoExtensions

The RegoExtensions target provides built-in Rego functions not included in swift-opa itself. When using OPA.Runtime from the SwiftOPASDK product, these are registered automatically. If you use OPA.Engine directly, you can register them explicitly via the customBuiltins parameter.

Currently provided builtins:

Rego name Description
yaml.is_valid Returns true if the input string is valid YAML
yaml.marshal Serializes a Rego value to a YAML string
yaml.unmarshal Deserializes a YAML string to a Rego value

Adding RegoExtensions as a dependency

Package.swift

let package = Package(
    platforms: [
        .macOS(.v15),
        .iOS(.v18),
    ],
    dependencies: [
        .package(url: "https://github.com/open-policy-agent/swift-opa", branch: "main"),
        .package(url: "https://github.com/open-policy-agent/swift-opa-sdk", branch: "main"),
    ],
    targets: [
        .executableTarget(name: "<target-name>", dependencies: [
            .product(name: "SwiftOPA", package: "swift-opa"),
            .product(name: "RegoExtensions", package: "swift-opa-sdk"),
        ]),
    ]
)

Example: customizing an Engine with YAML builtins

import Rego
import RegoExtensions

let engine = OPA.Engine(
    bundlePaths: [.init(path: "./bundles/authz.tar.gz", isDir: false)],
    customBuiltins: SDKBuiltinFuncs.sdkDefaultBuiltins
)

let prepared = try await engine.prepareForEval(query: "data.authz.allow")
let result = try await prepared.eval(input: .object(["user": .string("alice")]))

You can also merge the YAML builtins with your own custom builtins:

import Rego
import RegoExtensions

let myBuiltins: [String: AsyncBuiltin] = [
    "custom.greet": { _, args in
        guard case .string(let name) = args.first else {
            throw BuiltinError.argumentTypeMismatch(arg: "name", got: args.first?.typeName ?? "none", want: "string")
        }
        return .string("Hello, \(name)!")
    }
]

let engine = OPA.Engine(
    bundlePaths: [.init(path: "./bundles/authz.tar.gz", isDir: false)],
    customBuiltins: SDKBuiltinFuncs.sdkDefaultBuiltins.merging(myBuiltins, uniquingKeysWith: { _, new in new })
)

Bundle Service Support

Currently, the OPA.Runtime only implements loading bundles from a subset of the control plane service credential types that OPA supports.

Type Config Prefix Supported?
No Auth (default) -
Bearer Token services[_].credentials.bearer
Client TLS Certificate services[_].credentials.client_tls
OAuth2 Client Credentials services[_].credentials.oauth2
OAuth2 Client Credentials JWT authentication services[_].credentials.oauth2
OAuth2 JWT Bearer Grant Type services[_].credentials.oauth2
AWS Signature services[_].credentials.s3_signing
GCP Metadata Token services[_].credentials.gcp_metadata
Azure Managed Identities Token services[_].credentials.azure_managed_identity
OCI Repositories -
Custom Plugin services[_].credentials.plugin

Note: Custom Plugin support is available by providing a custom BundleLoader type at OPA.Runtime init.

Version Support

We aim to support "latest Swift major version - 2" releases back. As an example, for Swift 6.4, that implies supporting Swift 6.3, and 6.2 as well.

For .macOS and .iOS platform versions, we aim to support the platform versions associated with the current and previous major macOS releases. For example, if the current macOS release is macOS 26 "Tahoe", then the previous major release was macOS 15 "Sequoia", and we would support the .macOS(.v15) target, as well as the iOS version that released at the same time, .iOS(.v18).

Community Support

Feel free to open an issue if you encounter any problems using swift-opa-sdk, or have ideas on how to make it even better. We are also happy to answer more general questions in the #swift-opa channel of the OPA Slack.

About

Swift package providing a high-level interface and extended features for swift-opa.

Resources

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages