Skip to content

Governance check

What happens

Admins define rulesets, e.g. "OpenAPI best practices" or "OWASP security rules", and group them into policies. Each policy applies to APIs with certain labels, and is checked at certain moments such as "on create" or "on deploy". Whenever a matching API changes, APIM queues a governance request, runs the rulesets against the API and stores the result and any violations. Policies can also block an action when a serious rule fails.

Who: Admin (sets up the rules), then APIM's governance engine (runs the checks automatically) · Tables written: GOV_RULESET*, GOV_POLICY*, GOV_ARTIFACT, GOV_REQUEST, GOV_REQUEST_POLICY, GOV_POLICY_RUN, GOV_RULESET_RUN, GOV_RULE_VIOLATION · Tables read: AM_API, AM_API_LABEL_MAPPING

How the rules are organised

A policy bundles rulesets and says when to check them and what to do about failures.

erDiagram
    GOV_POLICY ||--o{ GOV_POLICY_RULESET : "uses"
    GOV_RULESET ||--o{ GOV_POLICY_RULESET : "used by"
    GOV_RULESET ||--o{ GOV_RULESET_RULE : "contains"
    GOV_POLICY ||--o{ GOV_POLICY_LABEL : "applies to label"
    GOV_POLICY ||--o{ GOV_POLICY_GOVERNABLE_STATE : "checked when"
    GOV_POLICY_GOVERNABLE_STATE ||--o{ GOV_POLICY_ACTION : "then do"
  • Ruleset = the rules themselves, stored as a Spectral-style YAML file.
  • Policy = which rulesets, for which APIs (by label or IS_GLOBAL), at which moments (states), and with which action per severity.

The flow at a glance

This diagram shows a check triggered by an API being updated.

sequenceDiagram
    participant Pub as Publisher
    participant DB as APIM DB
    participant Gov as Governance engine
    Pub->>DB: API created or updated (AM_API)
    Pub->>DB: insert GOV_ARTIFACT (first time) + GOV_REQUEST (PENDING)
    Pub->>DB: insert GOV_REQUEST_POLICY
    Gov->>DB: pick up request, run rulesets
    Gov->>DB: replace GOV_RULESET_RUN + GOV_RULE_VIOLATION rows
    Gov->>DB: upsert GOV_POLICY_RUN, delete GOV_REQUEST
  • Checks run asynchronously in the background. A blocking action (e.g. "block deploy when an ERROR-level rule fails") is instead evaluated synchronously at that moment.

Step by step

  1. Define rulesets (admin).

    • GOV_RULESET holds RULESET_ID, NAME, ARTIFACT_TYPE (e.g. REST API), RULE_CATEGORY, RULE_TYPE (e.g. API definition, documentation) and ORGANIZATION.
    • The uploaded YAML is stored in GOV_RULESET_CONTENT, and each rule parsed from it is stored in GOV_RULESET_RULE (RULE_NAME, SEVERITY, RULE_CONTENT).
  2. Define policies (admin).

    What's seeded out of the box:

    GOV_POLICY_ACTION.STATE SEVERITY TYPE
    API_CREATE ERROR / WARN / INFO NOTIFY
    API_UPDATE ERROR / WARN / INFO NOTIFY

    Changing a row to TYPE = 'BLOCK' (e.g. for API_DEPLOY + ERROR) makes the policy stop the action. That wasn't tested.

  3. Register the API as a governed artifact. GOV_ARTIFACT gets one row per API. Its ARTIFACT_KEY is the governance id, and ARTIFACT_REF_ID is the API UUID. (ARTIFACT_REF_ID, ARTIFACT_TYPE, ORGANIZATION) is unique.

    Logical link (no foreign key)

    GOV_ARTIFACT.ARTIFACT_REF_ID → AM_API.API_UUID is a value match only. Policy labels match API labels (AM_LABEL.NAME) by name, too.

  4. Queue a request. GOV_REQUEST gets a row with ARTIFACT_KEY, STATUS = 'PENDING' and REQ_TIMESTAMP. It's deleted once processed. The unique key (STATUS, ARTIFACT_KEY) stops duplicate pending requests for the same API. The policies to evaluate are listed in GOV_REQUEST_POLICY.

  5. Store the results.

    • GOV_RULESET_RUN keeps one row per (artifact, ruleset). It holds the latest RESULT (1 pass, 0 fail) and RUN_TIMESTAMP. Each new run replaces the row with a new RULESET_RUN_ID.
    • GOV_RULE_VIOLATION gets one row for each failed rule, with RULE_NAME, MESSAGE and VIOLATED_PATH (where in the API definition the problem is). It links back to the run and to the rule.
    • GOV_POLICY_RUN records when each policy last ran for the artifact.

    Real violations recorded for PizzaShackAPI:

    RULE_NAME MESSAGE VIOLATED_PATH
    api-technical-owner-email Technical owner email is missing or empty. [data][businessInformation][technicalOwnerEmail]
    api-business-owner-email Business owner email is missing or empty. [data][businessInformation][businessOwnerEmail]
    api-no-insecure-transports API should not have insecure transports. [data][transport][0]

What gets cleaned up

The GOV_* FKs have no ON DELETE rules, so the database blocks deleting a parent while child rows exist. APIM's code deletes in order: violations → runs → requests → artifact, and for rules: policy links → rules → ruleset. Deleting an API removes its governance data: the GOV_ARTIFACT, GOV_POLICY_RUN, GOV_RULESET_RUN and GOV_RULE_VIOLATION rows.

Try it

This query shows the current compliance problems for each API.

SELECT a.API_NAME, a.API_VERSION, rs.NAME AS RULESET,
       v.RULE_NAME, v.MESSAGE, v.VIOLATED_PATH
FROM GOV_RULE_VIOLATION v
JOIN GOV_RULESET_RUN r ON r.RULESET_RUN_ID = v.RULESET_RUN_ID
JOIN GOV_RULESET rs ON rs.RULESET_ID = r.RULESET_ID
JOIN GOV_ARTIFACT ga ON ga.ARTIFACT_KEY = r.ARTIFACT_KEY
LEFT JOIN AM_API a ON a.API_UUID = ga.ARTIFACT_REF_ID;

Different in 3.x

API governance doesn't exist in 3.x. There are no GOV_* tables. The 3.x flows have no equivalent page.

Related domains: Governance · Lifecycle & labels