Applying API Governance as Code for a Decentralized API World
Draft!!
Note: This article extends the existing draft
2020-10-26-apicgov4-as-code.mdwith new v12 capabilities and patterns.
In my earlier article on Governance as Code for a Decentralized API World, I described how to treat API governance rules like code — committing them to a repository, running them as part of the build pipeline, and treating the linting results as a first-class build artifact. That approach was valid in 2020, and it’s still valid — but API Connect v12 has significantly strengthened the governance story, and it’s worth revisiting the topic with the new capabilities.
This article picks up where that earlier article left off, covering what’s new in v12 for governance, how to use the new governance rule set APIs, and how to integrate governance into CI/CD pipelines for a truly decentralized API programme.
Table of Contents
- What Has Changed in v12?
- v12 Governance Architecture
- Governance Rule Sets in v12
- CI/CD Integration: The Full Pipeline
- Decentralized Governance Patterns
- Handling Governance Violations
- Ownership, Certification, and Standards in v12
What Has Changed in v12?
The key new capabilities in v12 for governance are:
- Scheduled Governance Scans — You can now attach recurring schedules to governance rule sets, so compliance is continuously monitored, not just checked at deploy time.
- Governance REST API — Full CRUD operations on governance rule sets via the REST API, enabling programmatic governance management.
- Governance History — Every scan writes a result record to governance history, giving you an audit trail of compliance over time.
- CLI Improvements — The
apic governanceCLI commands are more complete and support scriptable workflows. - Webhook Notifications — Governance scan failures can trigger webhooks, enabling integration with alerting systems (Slack, PagerDuty, etc.).
v12 Governance Architecture
In v12, governance in API Connect operates across three layers:
Layer 1: Governance Rule Sets
A rule set is a collection of governance rules that check API definitions for compliance. Rules are written in JSON Schema and/or XPath for XML, and are executed against API definitions during scans.
Layer 2: The Governance Scan
A scan runs a rule set against a scope (org, catalog, space, or specific APIs). Scans can be run on-demand or on a schedule.
Layer 3: Governance Results
Results are the output of a scan — a list of rule violations, each with the rule name, severity, the affected API, and a description.
Governance Rule Sets in v12
Creating a Governance Rule Set via CLI
# Create a new governance rule set
apic governance-rulesets:create \
--server ${MANAGEMENT_SERVER} \
--org ${PROVIDER_ORG} \
--catalog ${CATALOG} \
--name "payments-api-rules" \
--description "Governance rules for payment APIs" \
--scope catalog \
--output - \
--format json
Adding Rules to a Rule Set
Rules are defined in a rules file. Here’s an example rule that requires all payment APIs to have a x-ibm-paymenteering extension:
{
"rules": [
{
"id": "payment-001",
"name": "Payment API must have owner",
"description": "Every payment API must define an owner in x-governance",
"severity": "error",
"appliesTo": [
{
"field": "paths",
"match": "^/payments.*"
}
],
"condition": {
"type": "property_exists",
"schema": {
"$.x-governance.owner": {}
}
},
"message": "This API handles payments and must have an x-governance.owner defined."
},
{
"id": "payment-002",
"name": "Payment API must use OAuth 2.0",
"description": "Payment APIs must use OAuth 2.0 for authentication",
"severity": "error",
"appliesTo": [
{
"field": "paths",
"match": "^/payments.*"
}
],
"condition": {
"type": "equals",
"schema": {
"$.components.securitySchemes.OAuth20.type": "oauth2"
}
},
"message": "Payment APIs must use OAuth 2.0 security."
}
]
}
Publishing the Rule Set
apic governance-rulesets:update \
--server ${MANAGEMENT_SERVER} \
--org ${PROVIDER_ORG} \
--catalog ${CATALOG} \
--ruleset ${RULESET_ID} \
--rules-file ./governance-rules/payment-rules.json
CI/CD Integration: The Full Pipeline
Here’s a complete CI/CD pipeline for API governance. This assumes you’re using a standard CI system (Jenkins, GitHub Actions, GitLab CI, etc.) and that your API definitions are stored in a Git repository.
GitHub Actions Example
# .github/workflows/api-governance.yml
name: API Governance
on:
pull_request:
paths:
- 'apis/**'
- 'products/**'
push:
branches: [main]
paths:
- 'apis/**'
- 'products/**'
schedule:
# Run governance scan nightly
- cron: '0 2 * * *'
jobs:
governance-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up APIC CLI
run: |
curl -sL https://ibm.com/install-apic-cli | bash
echo "$HOME/.apic/cli" >> $GITHUB_PATH
- name: Authenticate to API Connect
run: |
apic login --server $ \
--username $ \
--password $
- name: Run Governance Scan
id: scan
run: |
RESULT=0
for ruleset in $(apic governance-rulesets:list \
--server $ \
--org $ \
--catalog $ \
--fields id \
--format json | jq -r '.[].id'); do
echo "Scanning with ruleset: $ruleset"
apic governance-rulesets:run \
--server $ \
--org $ \
--catalog $ \
--ruleset $ruleset \
--output ./governance-results/$ruleset.json \
--format json || RESULT=1
done
exit $RESULT
- name: Upload governance results
uses: actions/upload-artifact@v3
if: always()
with:
name: governance-results
path: governance-results/
- name: Post results to Slack on failure
if: failure() && github.event_name != 'schedule'
uses: slackapi/slack-github-action@v1
with:
channel-id: 'api-governance'
payload: |
{
"text": " Governance scan failed for $:$",
"blocks": [{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Governance Violations Detected*\nRepository: $\nBranch: $\n<$/$/actions/runs/$|View Results>"
}
}]
}
env:
SLACK_BOT_TOKEN: $
- name: Fail the build on governance violations
if: failure() && github.event_name == 'pull_request'
run: |
echo "Governance violations found. Please fix them before merging."
exit 1
Processing Governance Results
#!/usr/bin/env bash
# process-governance-results.sh
# Summarise governance violations from scan results
RESULTS_DIR="./governance-results"
for result_file in $RESULTS_DIR/*.json; do
echo "=== $(basename $result_file) ==="
jq -r '
.violations[] |
"[\(.severity)] \(.rule_id): \(.message) (API: \(.api_name))"
' "$result_file" 2>/dev/null || echo "No violations or invalid format"
echo ""
done
Decentralized Governance Patterns
In a truly decentralized API programme, different teams own different APIs, and governance needs to respect team boundaries while maintaining overall programme standards. Here are patterns for achieving this:
Pattern 1: Space-Scoped Governance
Use API Connect Spaces to isolate team boundaries, and attach team-specific governance rule sets to each space:
# Create a team-specific space with its own ruleset
apic spaces:create \
--server ${MANAGEMENT_SERVER} \
--org ${PROVIDER_ORG} \
--catalog ${CATALOG} \
--name "payments-team" \
--description "Payments team API space"
# Associate governance ruleset with this space
apic governance-rulesets:schedules:create \
--server ${MANAGEMENT_SERVER} \
--org ${PROVIDER_ORG} \
--catalog ${CATALOG} \
--ruleset payments-ruleset-id \
--scope space:payments-team \
--cron "0 3 * * *"
Pattern 2: Central Standards + Team Exceptions
Have a central governance rule set that all APIs must pass, plus team-specific rule sets for team-specific requirements:
# Central ruleset — required for all APIs
apic governance-rulesets:run \
--server ${MANAGEMENT_SERVER} \
--org ${PROVIDER_ORG} \
--catalog ${CATALOG} \
--ruleset central-standards-v3
# Team-specific — only scans APIs owned by that team
apic governance-rulesets:run \
--server ${MANAGEMENT_SERVER} \
--org ${PROVIDER_ORG} \
--catalog ${CATALOG} \
--ruleset payments-team-rules \
--filter "x-governance.owner=payments-team"
Pattern 3: Exemption Workflow
For governance rules that genuinely don’t apply to a specific API, allow exemptions with documented justification:
# Mark a specific API as exempt from a specific rule
apic governance-rulesets:exemptions:create \
--server ${MANAGEMENT_SERVER} \
--org ${PROVIDER_ORG} \
--catalog ${CATALOG} \
--ruleset ${RULESET_ID} \
--api ${API_ID} \
--rule payment-001 \
--justification "This is a test API with no real payment data, approved by Jane on 2026-07-01"
Exemptions expire after 90 days by default and must be renewed.
Handling Governance Violations
When a governance scan finds violations, you have several options:
Option 1: Fail the Pipeline (Strict)
Fail the CI pipeline on any error severity violation. This prevents violations from reaching production:
# Fail if any error-level violations
ERROR_COUNT=$(jq '[.violations[] | select(.severity=="error")] | length' $RESULTS_FILE)
if [ "$ERROR_COUNT" -gt 0 ]; then
echo "ERROR: $ERROR_COUNT governance violations found — blocking deployment"
exit 1
fi
Option 2: Warn but Allow (Advisory)
Log violations but don’t fail the build. Useful for new rule sets that teams are still adapting to:
# Log warnings but don't fail
WARNING_COUNT=$(jq '[.violations[] | select(.severity=="warning")] | length' $RESULTS_FILE)
if [ "$WARNING_COUNT" -gt 0 ]; then
echo "WARNING: $WARNING_COUNT advisory governance violations — review but not blocking"
fi
Option 3: Human Approval Gate
For critical rule sets (e.g., security compliance), require a human to review and approve violations before proceeding:
# In GitHub Actions — require manual approval for security violations
- name: Block on security violations
if: steps.scan.outputs.security-violations > 0
run: |
echo "Security governance violations found — requires human approval"
# The GitHub Actions environment will pause and require approval
# before continuing
environment:
name: governance-approval
Ownership, Certification, and Standards in v12
These three pillars from my earlier article remain the foundation of API governance, and v12 provides better tooling for each:
Ownership
In v12, ownership is expressed in the OpenAPI definition’s x-governance extension (or equivalent):
x-governance:
ownership:
dev: payments-team
test: payments-qa
production: payments-platform-ops
state: production
owner: payments-team@example.com
The ownership.owner field provides the single source of truth for who owns an API at any point in its lifecycle.
Certification
In v12, certification is tracked via the governance history. Each scan run records whether the API passed or failed, giving you a certification timeline:
# Get certification history for an API
apic governance:history \
--server ${MANAGEMENT_SERVER} \
--org ${PROVIDER_ORG} \
--api ${API_ID} \
--format json | jq '.[] | {date: .timestamp, passed: .passed, ruleset: .ruleset}'
Standards
Standards are enforced by governance rule sets. The key standards to enforce are:
- Naming conventions — consistent API and operation naming
- Security standards — required authentication, no hardcoded credentials
- Documentation standards — all operations must have descriptions
- Schema standards — consistent response structure, error formats
Summary
Governance as code in API Connect v12 is more powerful and more practical than ever. The combination of governance rule sets, scheduled scans, REST API management, and CI/CD integration means you can implement a governance programme that scales with your API portfolio — without governance becoming a bottleneck.
The key principles remain the same as in 2020:
- Commit your governance rules to version control
- Run them automatically in your CI pipeline
- Give each team clear ownership of their APIs
- Use a certification model that rewards compliant APIs
With v12’s new tooling, there’s no excuse for governance that only runs when someone remembers to run it.
Screenshots to Capture
-
[Placeholder: /images/governance-rule-set-creation-ui.png] What to capture: The UI for creating a governance rule set in the API Manager, showing the rule set name, scope selection, and initial rule configuration. Where: API Manager → Governance → Rule Sets → Add
-
[Placeholder: /images/governance-scan-results-violations.png] What to capture: Governance scan results showing violation details — rule name, severity, affected API, and the specific violation description. Where: API Manager → Governance → Run scan → Results view
-
[Placeholder: /images/space-scoped-governance-config.png] What to capture: A space-scoped governance configuration showing how a ruleset is associated with a specific team space rather than the catalog or org level. Where: API Manager → Manage → Catalog → Spaces → Select space → Governance tab
-
[Placeholder: /images/governance-exemption-workflow-ui.png] What to capture: The exemption workflow UI showing an active exemption on a rule with justification, expiry date, and the approved-by information. Where: API Manager → Governance → Exemptions → [Active exemption]
-
[Placeholder: /images/ci-governance-slack-notification.png] What to capture: A Slack notification showing a governance violation alert posted by the CI/CD pipeline, with the repository, branch, and link to view results. Where: Slack channel configured for governance alerts (representative output from the GitHub Actions workflow)
Questions about governance as code? Have you implemented governance in your API programme? Find me on Twitter @cminion.
