How to Run Integrations Locally¶
TL;DR¶
Test and validate an OAA integration locally before deploying to production.
Understanding the run command¶
Every tutorial and example in this series runs integrations with this pattern:
uv tool run --from oaa-runner oaa app run --config-file=config.yaml
Breaking it down:
uv tool run— runs a command provided by an installed tool, without activating a virtual environment--from oaa-runner— specifies the PyPI package that provides the command (oaa-runneris the package name)oaa— the CLI entry point installed by that package (the command you’re actually running)app run— the subcommand: load and process a Custom App integration
The package is named oaa-runner on PyPI; the CLI it installs is named oaa. The --from flag is what connects them.
!!! note “Preferred Command Alias”
Use oaa app as the primary command. The older oaa custom_app alias is deprecated and will be removed in a future release. Both commands are currently fully equivalent.
Dry runs with --no-push¶
Adding --no-push loads and validates data locally without sending anything to Veza:
uv tool run --from oaa-runner oaa app run --config-file=config.yaml --no-push
Environment variables are not required during a dry run. Any !env config values are evaluated but the actual push step — the one that would fail without valid credentials — is skipped. You can safely run --no-push without setting VEZA_URL, VEZA_API_KEY, or any csv_provider_id env vars.
Prerequisites¶
OAA integration project set up with config.yaml
Python 3.9 or later installed
uvtool installed (see How do I install OAA?)All credentials configured in
.envfile
Steps¶
Step 1: Validate Configuration¶
Before running, validate that your config.yaml is correct:
cd /path/to/your/integration
uv tool run --from oaa-runner oaa app validate --config=config.yaml
This checks:
✅ YAML syntax is valid
✅ All required fields are present
✅ Module imports work
✅ Connections are configured correctly
✅ Sources are defined properly
Step 2: Set Up Environment¶
Ensure your .env file has all required credentials:
# .env file
API_KEY=your_api_key_here
ANOTHER_KEY=value_here
# Never commit .env to git!
echo ".env" >> .gitignore
Step 3: Run Integration Locally¶
Execute the integration with JSON output:
uv tool run --from oaa-runner oaa app run \
--config=config.yaml \
--save-json
This:
✅ Fetches data from sources
✅ Applies transformations
✅ Maps fields to OAA
✅ Generates
output.json✅ Prints results to console
Step 4: Examine Output¶
Check the generated output.json:
# View overall structure
jq '.' output.json | head -50
# Count entities by type
jq '.local_users | length' output.json
jq '.local_roles | length' output.json
jq '.local_groups | length' output.json
# View first user
jq '.local_users[0]' output.json
# View relationships
jq '.relationships | length' output.json
jq '.relationships[] | select(.src_type=="LocalUser")' output.json
Step 5: Enable Debug Logging¶
For more detailed output:
uv tool run --from oaa-runner oaa app run \
--config=config.yaml \
--save-json \
--debug
This shows:
✅ Detailed transformation steps
✅ Field mapping operations
✅ Hook executions
✅ Relationship building
Common Commands¶
Validate Only (Dry Run)¶
Check configuration without fetching data:
uv tool run --from oaa-runner oaa app validate --config=config.yaml
Show Configuration¶
Display the loaded configuration:
uv tool run --from oaa-runner oaa app show_config --config=config.yaml
Run with Priority Push¶
Test with priority_push flag (for Veza conflicts):
uv tool run --from oaa-runner oaa app run \
--config=config.yaml \
--save-json \
--priority-push
Run Specific Source Only¶
Test individual source (if supported):
uv tool run --from oaa-runner oaa app run \
--config=config.yaml \
--save-json \
--source=users # Only fetch 'users' source
Troubleshooting¶
Error: Config file not found¶
# Make sure you're in the right directory
cd /path/to/integration
# And config.yaml exists
ls config.yaml
Error: Module import failed¶
# Check modules are in logic_modules list
cat config.yaml | grep logic_modules
# Verify files exist
ls modules/
Error: Connection failed¶
# Verify credentials in .env
cat .env
# Test connection manually
python3 -c "import os; print(os.getenv('API_KEY'))"
Error: YAML syntax error¶
Validate YAML syntax:
# Using Python
python3 -m yaml config.yaml
# Or using online validator
# Copy config.yaml to https://www.yamllint.com/
No data in output.json¶
Check logs for:
# Look for ERROR or WARNING in output
uv tool run --from oaa-runner oaa app run \
--config=config.yaml \
--save-json 2>&1 | grep -i error
Common causes:
API credentials invalid
Source endpoint incorrect
No data in source system
Field mapping errors
Inspecting Output¶
Count All Entities¶
jq '
{
users: (.local_users | length),
roles: (.local_roles | length),
groups: (.local_groups | length),
resources: (.resources | length),
relationships: (.relationships | length)
}
' output.json
Find Missing Email Addresses¶
jq '.local_users[] | select(.email == null or .email == "")' output.json
List All Custom Properties¶
jq '.local_users[0].custom_properties' output.json
View Relationship Graph¶
jq '.relationships[]' output.json | jq -s 'group_by(.src_type)'
Find Relationships for Specific User¶
jq '.relationships[] | select(.src_id=="user123")' output.json
Performance Monitoring¶
Track Integration Time¶
time uv tool run --from oaa-runner oaa app run \
--config=config.yaml \
--save-json
Monitor Memory Usage¶
# On macOS
/usr/bin/time -v uv tool run --from oaa-runner oaa app run \
--config=config.yaml \
--save-json
# On Linux
command time -v uv tool run --from oaa-runner oaa app run \
--config=config.yaml \
--save-json
Local Development Workflow¶
Initial Setup
cd /path/to/integration cp sample.env .env # Edit .env with your credentials
Validate Configuration
uv tool run --from oaa-runner oaa app validate --config=config.yaml
Run with Debug Output
uv tool run --from oaa-runner oaa app run \ --config=config.yaml \ --save-json \ --debug
Inspect Results
jq '.' output.json | less
Fix Issues
Edit config.yaml or modules/hooks.py
Re-run from step 2
Commit When Ready
git add config.yaml modules/ git commit -m "Add integration for XYZ"
Examples¶
Test ThousandEyes Integration¶
cd /path/to/netapp/thousandeyes
# Validate
uv tool run --from oaa-runner oaa app validate --config=config.yaml
# Run with debug
uv tool run --from oaa-runner oaa app run \
--config=config.yaml \
--save-json \
--debug
# Check output
jq '.local_users | length' output.json
jq '.local_roles | length' output.json
jq '.relationships[] | select(.src_type=="LocalUser")' output.json
Test Abnormal Integration¶
cd /path/to/gxo/abnormal
uv tool run --from oaa-runner oaa app run \
--config=config.yaml \
--save-json
# View first user with custom properties
jq '.local_users[0] | {name, email, custom_properties}' output.json
Next Steps¶
How to Configure Field Mappings - Review field mappings
How to Use PRE_TRANSFORM Hooks - Debug data transformations
How to Use RECORD_TRANSFORM Hooks - Debug per-record logic