diff --git a/documentation/docs/getting-started/configuration.mdx b/documentation/docs/getting-started/configuration.mdx index 673cc539..b0540d2e 100644 --- a/documentation/docs/getting-started/configuration.mdx +++ b/documentation/docs/getting-started/configuration.mdx @@ -1144,6 +1144,14 @@ Default: `{}` If inline OPA is enabled, the user can set the [server configuration options](https://docs.opal.ac/getting-started/running-opal/run-opal-client/opa-runner-parameters) that affect how OPA will start when running `opa run --server` inline. Watch escaping quotes. +#### OPAL_OPA_V0_COMPAT + +Default: `True` (for OPAL v0.9.x, will be changed to unconfigured in v0.10.0) + +Set to `true` to enable OPA v0 compatibility mode (`--v0-compatible` flag). +This setting merges with `OPAL_INLINE_OPA_CONFIG.v0_compatible` - if either is enabled, the flag will be added to OPA. +This allows for easier migration from OPA v0 to OPA v1 by enabling the compatibility mode by default until everyone migrates. + #### OPAL_INLINE_OPA_LOG_FORMAT Default: `none` diff --git a/documentation/docs/tutorials/opa-version-migration.mdx b/documentation/docs/tutorials/opa-version-migration.mdx new file mode 100644 index 00000000..6f2f9a60 --- /dev/null +++ b/documentation/docs/tutorials/opa-version-migration.mdx @@ -0,0 +1,188 @@ +# OPA Version Migration Guide + +## Overview + +Starting with OPAL v0.9.x, OPAL now ships with OPA v1 by default and supports both OPA v0 and OPA v1 compatibility modes. +This guide explains how to migrate your Rego policies from OPA v0 to OPA v1 while ensuring a smooth transition. + +## What's Changed in OPA v1 + +OPA v1 introduces several breaking changes that affect how Rego policies are written: + +- **Package declarations**: In OPA v0, you could write `package authz` or just `package authz`. In OPA v1, you must use `package authz.v1` (with a version suffix). +- **Rule declarations**: Rules now require explicit package versioning. +- **Import statements**: Import paths have changed to be more explicit. +- **Built-in functions**: Some built-in functions have been renamed or deprecated. + +For more information, see [OPA v1 Migration Guide](https://www.openpolicyagent.org/docs/v0-upgrade). + +## Migration Strategy + +OPAL provides a gradual migration path: + +1. **Enable v0 compatibility mode** (default in OPAL v0.9.x) +2. **Test your policies** with v0 compatibility enabled +3. **Migrate your policies** to OPA v1 format +4. **Disable v0 compatibility mode** when ready + +## Step 1: Enable v0 Compatibility Mode + +By default, OPAL v0.9.x enables v0 compatibility mode automatically. This means: + +- OPA will accept both v0 and v1 syntax +- You can run your existing policies without immediate changes +- The `--v0-compatible` flag is automatically added to OPA + +### Configuration + +The v0 compatibility mode is controlled by the `OPAL_OPA_V0_COMPAT` setting: + +```bash +# Enable v0 compatibility (default in v0.9.x) +export OPAL_OPA_V0_COMPAT=true + +# Disable v0 compatibility +export OPAL_OPA_V0_COMPAT=false +``` + +This setting merges with the inline OPA configuration: + +```bash +# You can also set it in the inline OPA config +export OPAL_INLINE_OPA_CONFIG='{"v0_compatible": true}' +``` + +**Note**: If either `OPAL_OPA_V0_COMPAT` or `OPAL_INLINE_OPA_CONFIG.v0_compatible` is `true`, the `--v0-compatible` flag will be added to OPA. + +## Step 2: Test Your Current Policies + +With v0 compatibility enabled, verify that your existing policies work correctly: + +1. Start OPAL with your current policies +2. Test authorization queries +3. Check that all expected functionality works + +## Step 3: Migrate Your Policies + +### Basic Package Migration + +**OPA v0 syntax:** +```rego +package authz + +default allow = false + +allow { + input.user == "admin" +} +``` + +**OPA v1 syntax:** +```rego +package authz.v1 + +default allow := false + +allow if { + input.user == "admin" +} +``` + +### Key Changes to Make: + +1. **Add `.v1` suffix** to package declarations +2. **Replace `=` with `:=`** for assignments +3. **Replace `if` statements** with guard syntax +4. **Update import paths** to include version suffixes + +### Example Migration + +Here's a more complex example: + +**Before (OPA v0):** +```rego +package authz + +import data.users + +default allow = false + +allow { + user := data.users[input.user] + user.role == "admin" + input.action == "delete" +} + +has_permission[user] { + user := data.users[input.user] + user.role == "admin" +} +``` + +**After (OPA v1):** +```rego +package authz.v1 + +import data.users + +default allow := false + +allow if { + user := data.users[input.user] + user.role == "admin" + input.action == "delete" +} + +has_permission contains user if { + user := data.users[input.user] + user.role == "admin" +} +``` + +## Step 4: Disable v0 Compatibility Mode + +Once you've migrated all your policies: + +1. **Set `OPAL_OPA_V0_COMPAT=false`** or remove the setting (it defaults to `false` in v0.10.0+) +2. **Remove `v0_compatible: true`** from your `OPAL_INLINE_OPA_CONFIG` +3. **Restart OPAL** to apply the changes + +## Migration Timeline + +- **OPAL v0.9.x**: `OPAL_OPA_V0_COMPAT` defaults to `true` for easier migration +- **OPAL v0.10.0+**: `OPAL_OPA_V0_COMPAT` will be unconfigured (effectively `false`) by default + +## Troubleshooting + +### Common Migration Issues + +1. **Package not found errors**: Make sure to add `.v1` suffix to package declarations +2. **Syntax errors**: Update `=` to `:=` and use guard syntax for `if` statements +3. **Import errors**: Update import paths to include version suffixes + +### Debugging Tips + +1. **Check OPA logs** for detailed error messages +2. **Use OPA's playground** to test individual policies +3. **Enable verbose logging** during migration: + ```bash + export OPAL_INLINE_OPA_LOG_FORMAT=full + ``` + +### Rollback Plan + +If you encounter issues: + +1. Re-enable v0 compatibility mode: + ```bash + export OPAL_OPA_V0_COMPAT=true + ``` +2. Restart OPAL +3. Fix any remaining policy issues +4. Try migration again + +## Resources + +- [OPA v1 Migration Guide](https://www.openpolicyagent.org/docs/v0-upgrade) +- [OPA v1 Playground](https://play.openpolicyagent.org/) +- [Rego Language Reference](https://www.openpolicyagent.org/docs/latest/policy-language/) diff --git a/packages/opal-client/opal_client/config.py b/packages/opal-client/opal_client/config.py index b5d94fb3..3cf7800d 100644 --- a/packages/opal-client/opal_client/config.py +++ b/packages/opal-client/opal_client/config.py @@ -163,6 +163,12 @@ def load_policy_store(): description="CLI options used when running `opa run --server` inline", ) + OPA_V0_COMPAT = confi.bool( + "OPA_V0_COMPAT", + True, # Enabled by default for OPAL v0.9.x, will be changed to unconfigured in v0.10.0 + description="Set to true to enable OPA v0 compatibility mode (--v0-compatible flag). This merges with INLINE_OPA_CONFIG.v0_compatible - if either is enabled, the flag will be added to OPA", + ) + INLINE_OPA_LOG_FORMAT: EngineLogFormat = confi.enum( "INLINE_OPA_LOG_FORMAT", EngineLogFormat, diff --git a/packages/opal-client/opal_client/engine/options.py b/packages/opal-client/opal_client/engine/options.py index 4392d677..cfa1f79f 100644 --- a/packages/opal-client/opal_client/engine/options.py +++ b/packages/opal-client/opal_client/engine/options.py @@ -88,7 +88,9 @@ def alias_generator(cls, string: str) -> str: def get_cli_options_dict(self): """Returns a dict that can be passed to the OPA cli.""" - return self.dict(exclude_none=True, by_alias=True, exclude={"files"}) + return self.dict( + exclude_none=True, by_alias=True, exclude={"files", "v0_compatible"} + ) class CedarServerOptions(BaseModel): diff --git a/packages/opal-client/opal_client/engine/runner.py b/packages/opal-client/opal_client/engine/runner.py index 73ceb7d3..fadf35c9 100644 --- a/packages/opal-client/opal_client/engine/runner.py +++ b/packages/opal-client/opal_client/engine/runner.py @@ -316,6 +316,17 @@ def get_executable_path(self) -> str: def get_arguments(self) -> list[str]: args = ["run", "--server"] opts = self._options.get_cli_options_dict() + + # Check if v0 compatibility mode should be enabled + # Either the top-level OPAL_OPA_V0_COMPAT setting or the inline OPA config v0_compatible setting + v0_compatible_enabled = ( + opal_client_config.OPA_V0_COMPAT or self._options.v0_compatible + ) + + # If v0 compatibility is enabled, add the --v0-compatible flag + if v0_compatible_enabled: + args.append("--v0-compatible") + args.extend(f"{k}={v}" for k, v in opts.items()) if self._options.files: args.extend(self._options.files)