Chapter 23Lesson 01~135 minutes

Web API, Webhooks, Automation, Provisioning, and Policy as Code: Core Concepts and Mental Model

Turn SonarQube automation into an auditable control plane by separating API identity, documented endpoint/version, request state, asynchronous analysis state, webhook events, and policy ownership.

Web APIWebhooksAutomationPolicy as codeGovernance

Learning objectives

  • Separate automation identity, authentication, endpoint/version, HTTP request/response, persisted policy state, asynchronous analysis state, and webhook delivery state.
  • Explain why Web API V2 is a gradual endpoint-by-endpoint migration rather than a global URL prefix change.
  • Use bearer-authenticated User tokens for Web API automation and preserve token-expiration metadata without exposing the token.
  • Recognize pagination, error bodies, idempotency, reconciliation, task IDs, and audit evidence as first-class automation concerns.
  • Explain what a SonarQube webhook proves, what it does not prove, and why HMAC validation belongs at the receiver trust boundary.
  • Keep scanner/report upload, ceTaskId, Compute Engine completion, analysis result, gate state, webhook state, and downstream automation outcome independent.

1. The practical problem: automation can make a wrong action repeatable

Chapter 22 secured the network and identity boundaries around SonarQube. Chapter 23 moves one layer higher: using documented APIs and webhooks to manage projects and policy repeatedly. The danger is that a manual mistake usually affects one operation, while an automation mistake can affect every project every time it runs.

A safe SonarQube automation is therefore not “a curl command that returned 200.” It is a control that can prove who acted, which documented endpoint/version was used, what state existed before the request, what mutation was intended, what response occurred, and what independent state proves the requested outcome.

automation identity → bearer token → documented API endpoint → read current state → planned mutation → HTTP result → verify persisted state → audit record

2. Two automation paths: command path and event path

Automation and event causality
flowchart TD
  A[Automation identity] -->|Bearer token| B[Documented Web API]
  B --> C[Read / mutate project policy]
  C --> D[Persisted SonarQube state]
  E[Scanner report] --> F[Compute Engine]
  F --> G[Analysis / gate result]
  G --> H[SonarQube webhook]
  H -->|HMAC-signed POST| I[Local / CI receiver]
  I --> J[Validated event record]

The Web API path is request/response automation initiated by a client. The webhook path is asynchronous event delivery initiated by SonarQube. They meet around project and analysis state, but they have different identities, failure modes, and trust controls.

3. State map to define before automation

Identity state

User that owns the token, global/project permissions, token type, expiration, revocation status, and the secret store that supplies it.

API state

Endpoint path, API generation, HTTP method, content type, request parameters/body, pagination model, documented status/error schema, and deprecation state.

Mutation state

Project key, current existence/visibility, gate/profile/settings/webhooks, expected owner, and whether the operation is create-only or reconciled.

Analysis state

Revision, scanner parameters, report upload, ceTaskId, Compute Engine result, analysis ID, Quality Gate status, and resulting project measures/issues.

Webhook state

Webhook key/name, URL, secret presence, latest delivery status, task ID in payload, HMAC header, receiver decision, and replay/deduplication record.

4. Web API V1 and V2: migrate endpoint by endpoint

Current Community Build documentation says Web API V2 will gradually replace the existing Web API as individual endpoints are deprecated and replaced. That means there is no safe rule such as “prepend /api/v2 to every old path.” Some capabilities already expose V2 resources—for example certain user-management and DevOps-platform translation APIs—while long-standing local project creation still documents POST /api/projects/create.

Unsafe assumption Safer automation rule
“V2 exists, so all V1 endpoints are obsolete.” Read the documentation shipped with the exact target instance and migrate only when the documented replacement exists.
“A V2 path uses the same parameters/statuses as V1.” Treat each endpoint contract as independent; update request/response adapters and tests.
“Undocumented browser endpoints are fine because the UI uses them.” Use documented public Web APIs only; internal endpoints can change without compatibility guarantees.
“One client library can hard-code endpoints forever.” Centralize endpoint definitions/version assumptions and fail closed when an endpoint contract is unknown.

5. Bearer authentication: a User token acts with its owner’s permissions

For Web API calls, current Community Build guidance recommends a User token in the Authorization: Bearer ... header. A user token can perform any API action its owner is authorized to perform. This makes the token useful for automation—and dangerous if the owner is a global administrator.

# Token value comes from a secret store or local prompt, never source control.
export SONAR_HOST_URL="http://localhost:9000"
read -rsp "Automation user token: " SONAR_API_TOKEN; echo
export SONAR_API_TOKEN

curl --fail-with-body -sS \
  -D evidence/headers.txt \
  -H "Authorization: Bearer $SONAR_API_TOKEN" \
  "$SONAR_HOST_URL/api/server/version" \
  -o evidence/server-version.txt

Authenticated Web API responses normally include SonarQube-Authentication-Token-Expiration. A few documented endpoints, including authentication validation and server-version/project-badge endpoints, are exceptions; capture expiration from a normal authenticated endpoint that supports it. Never log the Authorization header itself.

6. HTTP method, content type, and error body are part of the contract

Current documentation recommends form data for traditional POST Web API requests and notes application/x-www-form-urlencoded as the usual default unless the endpoint documents another content type. Place mutation parameters in the request body rather than URLs when possible so intermediaries and access logs do not unnecessarily capture sensitive values.

curl --fail-with-body -sS -X POST \
  -H "Authorization: Bearer $SONAR_API_TOKEN" \
  --data-urlencode "project=sq-ch23-policy-lab" \
  --data-urlencode "name=SQ Chapter 23 Policy Lab" \
  --data-urlencode "visibility=private" \
  "$SONAR_HOST_URL/api/projects/create"

--fail-with-body is useful because it preserves SonarQube’s response body when an HTTP error occurs. An automation that throws away the error body and retries cannot distinguish duplicate-key validation, permission denial, malformed parameters, rate/load conditions, or server failure.

7. Pagination is a correctness property, not a performance detail

Many search APIs are paginated. A policy client that inspects only page one can conclude that a rule, project, user, or issue is absent when it merely lives on a later page. Traditional endpoints commonly accept page/page-size parameters such as p and ps and return paging metadata; V2 resources can use different representations, so read each endpoint schema.

def iter_v1_pages(get_page):
    page = 1
    while True:
        payload = get_page(page)
        yield payload
        meta = payload.get("paging", {})
        index = int(meta.get("pageIndex", page))
        size = int(meta.get("pageSize", 0))
        total = int(meta.get("total", 0))
        if size == 0 or index * size >= total:
            break
        page += 1

8. Idempotence and reconciliation: read → compare → mutate → verify

Idempotent automation can be run repeatedly and converge on the same intended state without creating duplicates or amplifying side effects. The safest pattern is a reconciliation loop:

  1. Read current state with a documented read endpoint.
  2. Normalize only the fields your automation owns.
  3. Compare desired state with current state.
  4. Skip when they match.
  5. Apply the smallest mutation when they differ.
  6. Read again and verify the result.
  7. Record what changed and what was already compliant.

Do not convert every API operation into a retry loop. A create call, delete call, comment creation, or other non-idempotent mutation may need a preflight read, an idempotency key in your own control plane, or explicit reconciliation logic before retry.

9. Webhooks are signed event notifications—not authenticated commands

SonarQube webhooks notify external services when analysis-related events occur. The payload includes project information, analysis time, task status/ID, Quality Gate information, and optional sonar.analysis.* properties. Project and global webhooks are additive.

Configure a webhook secret and validate X-Sonar-Webhook-HMAC-SHA256 at the receiver. SonarQube computes a lower-case HMAC-SHA256 digest of the raw request body. If the signature does not match, ignore the payload.

Do not treat a webhook body as a trusted command. Even a valid SonarQube webhook should be interpreted as event evidence. The receiver must validate HMAC, project/task identity, expected URL/secret ownership, and its own authorization rules before triggering downstream actions.

10. Asynchronous state still matters after you automate it

scanner exit → report upload → report-task.txt / ceTaskId → Compute Engine terminal state → analysis persisted → gate result → webhook delivery → downstream receiver state

A successful API mutation or webhook delivery does not collapse those states into one. The webhook payload itself includes a task ID/status so receivers can correlate the event to server-side processing rather than guessing from CI job state.

11. Read-only inspection before mutation

mkdir -p evidence
curl -fsS "$SONAR_HOST_URL/api/server/version" | tee evidence/version.txt

curl --fail-with-body -sS \
  -H "Authorization: Bearer $SONAR_API_TOKEN" \
  "$SONAR_HOST_URL/api/components/search?qualifiers=TRK&p=1&ps=100" \
  | tee evidence/projects-page-1.json

# Inspect the exact Web API documentation shipped with the instance:
#   $SONAR_HOST_URL/web_api
# Record endpoint path, method, permissions, parameters, and changelog before coding a mutation.

Knowledge check

Does Web API V2 mean every old endpoint has a mechanical /api/v2 replacement?

Why should an API client preserve HTTP error bodies?

What does SonarQube-Authentication-Token-Expiration help an automation do?

Why must webhook HMAC be calculated over the raw request body?

A valid webhook reports gate ERROR. Should the receiver assume the scanner failed?

Next lesson

Build the idempotent local API and webhook workflow

Lesson 2 turns the API/webhook mental model into a disposable Community Build reconciliation workflow.

Official references and version notes

Version and compatibility note

Rechecked 2026-09-08. Mandatory examples target Community Build 26.9.0.129388 and SonarScanner CLI 8.1.0.6389. Current Community Build documentation states that Web API V2 is gradually replacing the existing Web API endpoint by endpoint; do not infer a mechanical /api/v2 rewrite. Bearer authentication with a User token is recommended for Web API calls, and authenticated responses normally expose SonarQube-Authentication-Token-Expiration for rotation planning. Unless an endpoint documents otherwise, traditional POST Web API calls should use form data / application/x-www-form-urlencoded. Project creation remains documented at POST /api/projects/create, while some newer capabilities already use V2 resources. SonarQube webhooks can be configured at project/global scope and can be protected with HMAC-SHA256 in X-Sonar-Webhook-HMAC-SHA256; validate the raw body before trusting a payload. Webhook payloads include background task and Quality Gate evidence, but delivery success is not equivalent to Compute Engine success or gate pass. Always recheck the exact target instance’s /web_api documentation, endpoint changelog, permission requirement, pagination/error schema, and V2 replacement status before production automation.

Automation evidence rule. Preserve endpoint generation/path/method, sanitized request intent, HTTP status/body, pagination completion, token owner/type/expiration (never the value), before/after policy state, revision, ceTaskId, Compute Engine result, webhook HMAC outcome, task/gate state, controller version, ownership record, and cleanup/revocation evidence separately.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.