Example

CI/CD integrations for the Test Data API

Thin, copyable recipes that let a pipeline request approved test data, wait for it, run its own tests and release it — through the DataNivra CLI or REST API only. They add no logic of their own: the DataNivra control plane decides (AUTO_APPROVED, PENDING_HUMAN_APPROVAL, DENIED) from the second-person-approved profile, and your customer-resident DataNivra agent hydrates and tears down the target. Rows never pass through the CI system; only ids, states and reason codes do.

About this example

Thin, copyable recipes that let a pipeline request approved test data, wait for it, run its own tests and release it — through the DataNivra CLI or REST API only. They add no logic of their own: the DataNivra control plane decides (AUTO_APPROVED, PENDING_HUMAN_APPROVAL, DENIED) from the second-person-approved profile, and your customer-resident DataNivra agent hydrates and tears down the target. Rows never pass through the CI system; only ids, states and reason codes do.

These are examples of compatibility through standard APIs, not official vendor integrations or partnerships. Every value in them is a synthetic placeholder (acme/claims-service, datanivra:acme, <WORKLOAD_IDENTITY_ID>).

Before you start (one-time, by your DataNivra administrators)

  1. A DataNivra agent in your network and a certified dataset; an approved test-data profile (here claims-pr-regression v1) whose target pool your runners can reach.
  2. For GitHub Actions and GitLab CI: a workload identity trust for the repository and audience (datanivra workload-identities create ...), named in the profile's automation envelope. Workload identity and automatic approval are off by default and enabled by the DataNivra operator only after owner approval. Without automatic approval, requests wait for a human (datanivra test-data approve); the recipes then end with exit code 25 when they time out.
  3. The CLI (datanivra-cli) and SDK wheels from your DataNivra release assets — the packages are not published to PyPI or npm.

The repeatable part (every run) is what the recipes show. The shared manifest is request.yaml (JSON twin: request.json); validate it with datanivra test-data validate request.yaml.

Matrix

IntegrationFileAuthCleanupValidated howStatus
GitHub Actionsgithub-actions/pr-test-data.ymljob OIDC token → workload session (id-token: write)if: always() release + PR-closed jobYAML, pinned SHAs, CLI argv parsed by the real CLI parser, actionlintstatic-validated
GitLab CIgitlab-ci/.gitlab-ci.ymlid_tokens → workload sessionafter_script releaseYAML, CLI argv parsedstatic-validated
Jenkinsjenkins/Jenkinsfileshort-lived session token (credential binding)post { always }CLI argv parsedillustrative, not run
Azure DevOpsazure-devops/azure-pipelines.ymlshort-lived session token (secret variable)condition: always()YAML, CLI argv parsedillustrative, not run
CircleCIcircleci/config.ymlshort-lived session token (context)when: alwaysYAML, CLI argv parsedillustrative, not run
Generic shell (curl + jq)generic-shell/datanivra-test-data.shsession token or workload exchangetrap ... EXITshellcheckstatic-validated
Generic Python (stdlib)generic-shell/datanivra_test_data.pysession token or workload exchangefinallyrun against the in-process control plane and a fake agentsynthetic E2E in repo
Blacksmith-style runnerblacksmith/pr-test-data.ymlGitHub OIDC (as GitHub Actions)if: always()YAML, actionlintillustrative, not run — GitHub Actions-compatible runner example, unverified, no Blacksmith dependency
Self-hosted runnerself-hosted-runner/README.mdany of the above——guidance
Ephemeral Kuberneteskubernetes/README.mdany of the abovelease TTL + namespace teardown—guidance

"static-validated" means the files are parsed and checked by DataNivra's own contract tests; it does not mean the pipeline ran on that CI service. The control-plane behaviour the recipes rely on (decisions, isolated pool targets, release, TTL expiry, 30 concurrent pull requests) is covered by DataNivra's control-plane test suite.

Behaviour every recipe keeps

  • Request → wait → test → release, with release on success, failure and cancellation. A runner killed before releasing is covered by the lease TTL (ttl_seconds): the request ends and the agent tears the copy down. Releasing never revokes the shared certified version.
  • Idempotent re-runs: --ci-from-env (GitHub/GitLab) attaches a re-run of the same pull request to its live request; elsewhere a deterministic --idempotency-key does the same.
  • Never logged: tokens (CI OIDC tokens, sessions), connection strings, row values. Output is ids, states, decision and reason codes.
  • Exit codes (CLI): 24 denied by the profile, 25 still waiting for a human approval, 26 ended without READY, 27 timed out, 28 invalid manifest.
  • examples/ci/ — the earlier run/lease recipes using datanivra_ci.py (dataset id + target reference given by the pipeline). The recipes here use approved profiles instead, so the pipeline never chooses sources or targets.
  • Test Data API documentation — administrator setup, workload identity, automatic approval and troubleshooting.

Files

Exactly as they are in the examples repository. Every value is a synthetic placeholder; nothing here is a credential.

request.json

{
  "apiVersion": "datanivra.io/v1alpha1",
  "kind": "TestDataRequest",
  "metadata": {
    "name": "claims-pr-tests",
    "description": "Isolated certified claims data for one pull-request test run"
  },
  "spec": {
    "profile": { "name": "claims-pr-regression", "version": 1 },
    "ttl_seconds": 3600,
    "purpose_ref": "QA-1234"
  }
}

examples/integrations/request.json

request.yaml

# yaml-language-server: $schema=../../packages/contracts/schemas/v1/manifests/test-data-request.schema.json
# TestDataRequest manifest (ADR-0018). It pins an APPROVED profile version and chooses nothing
# else: sources, targets, masking/certification policies and the approval envelope all live in
# the second-person-approved profile `claims-pr-regression` version 1. Synthetic placeholders.
# Copy to `.datanivra/request.yaml` in your repository; validate with
#   datanivra test-data validate .datanivra/request.yaml
apiVersion: datanivra.io/v1alpha1
kind: TestDataRequest
metadata:
  name: claims-pr-tests
  description: Isolated certified claims data for one pull-request test run
spec:
  profile:
    name: claims-pr-regression
    version: 1
  ttl_seconds: 3600
  purpose_ref: QA-1234

examples/integrations/request.yaml

SYNTHETIC_MANIFEST.json

{
  "synthetic": true,
  "generator": "hand-written CI/CD recipes for the Test Data API (ADR-0018)",
  "seed": 0,
  "description": "CI pipeline definitions and TestDataRequest manifests. Placeholder repository (acme/claims-service), audience (datanivra:acme), profile name, ticket key (QA-1234), example URLs (api.example.test) and secret/variable NAMES only. No rows, people, customers, tokens or credentials.",
  "expected_detector_hits": ["CREDENTIAL_ASSIGNMENT"],
  "expected_detector_hits_reason": "Reviewed: the hits are pipeline syntax, not values - GitHub's required `id-token: write` permission and `DATANIVRA_TOKEN: $(DATANIVRA_TOKEN)`-style mappings of a CI secret variable NAME into a step's environment."
}

examples/integrations/SYNTHETIC_MANIFEST.json