Developer CI/CD guide¶
This page explains how to add or change CI/CD safely in dpone. It belongs in Developer docs because workflow changes are implementation changes: they affect release safety, contributor UX, security posture, and public artifacts.
Principles¶
- Keep the default PR gate deterministic and credential-free.
- Keep vendor credentials in manual or scheduled gates only.
- Use least-privilege workflow permissions.
- Prefer explicit artifacts over hidden logs.
- Make every new workflow reproducible locally or document why it cannot be.
- Update user docs and runbooks in the same PR as workflow changes.
- Keep
masteras the default branch in workflow triggers and docs.
When to add a new workflow¶
Add a workflow only when one of these is true:
| Case | Prefer |
|---|---|
| Fast deterministic quality check | Extend .github/workflows/ci.yml. |
| Documentation build/deploy behavior | Extend .github/workflows/pages.yml. |
| Public package publishing | Extend .github/workflows/release.yml. |
| Long-running source/sink or connector certification | Manual/scheduled workflow. |
| Vendor credentials required | Manual/scheduled workflow with explicit secrets and docs. |
| Security/supply-chain posture | Dedicated security workflow with least-privilege permissions. |
Do not add a new always-on PR workflow for slow, flaky, vendor-dependent, or credential-dependent tests.
New workflow checklist¶
Before opening a PR:
- Choose the trigger:
push,pull_request,workflow_dispatch,schedule, or tag. - Choose minimum permissions. Start with
contents: read. - Decide whether the workflow must run on
master, PRs, tags, schedule, or manual dispatch. - Add local reproduction commands to Workflow reference.
- Add failure recovery to Failure runbooks.
- Add artifact names and retention expectations.
- Add or update tests that protect the docs/workflow contract.
- Confirm no job writes secrets to logs or artifacts.
Changing the default CI gate¶
Default CI changes affect all contributors. Keep them boring and reproducible.
Required local gate:
uv sync --all-extras
uv run ruff check .
uv run ruff format --check .
uv run mypy --config-file mypy.ini
uv run pytest -m "not integration_live" --cov=src/dpone --cov-report=xml
uv build
Rules:
- Do not require Docker for the default quality matrix unless the job is isolated like
postgres-xmin. - Do not require cloud/vendor credentials.
- Keep optional integration markers opt-in.
- If coverage minimum changes, document the rationale in the PR.
Adding a manual integration gate¶
Use this pattern for broad matrix, stress, benchmark, or connector certification workflows:
on:
workflow_dispatch:
inputs:
run_mode:
type: choice
options: [mock_contract, mock_local, vendor_live]
permissions:
contents: read
Design requirements:
- All input names must be documented.
- Every run writes artifacts even on failure with
if: always(). mock_contractandmock_localmust not require external vendor credentials.vendor_livemust clearly list required secrets.- Use focused filters such as
DPONE_MATRIX_CASE_IDfor debugging.
Adding secrets¶
Before adding a secret:
- Ask whether Trusted Publishing, OIDC, or local mock mode can avoid the secret.
- Scope the secret to the smallest provider/project/package possible.
- Use it only in the workflow/job that needs it.
- Redact diagnostics and artifacts.
- Add rotation instructions to the relevant runbook.
Never add secrets to ordinary PR CI from forks.
Adding artifacts¶
Artifacts should answer: what ran, with what inputs, what passed/failed, and what evidence exists.
Recommended artifact content:
- command and workflow inputs;
- source/sink/strategy coverage;
- row counts and checksums for data movement tests;
- warnings and skipped cases with reason;
- environment summary without secrets;
- JUnit XML when pytest is involved.
Recommended paths:
test_artifacts/integration_matrix/
test_artifacts/connectors/
test_artifacts/benchmarks/
test_artifacts/route_certification/
test_artifacts/route_certification_release/
test_artifacts/route_release_finalize/
test_artifacts/route_readiness/
test_artifacts/route_execution/
test_artifacts/route_rc_execution/
test_artifacts/route_state/
test_artifacts/cdc_apply/
test_artifacts/cdc_handoff/
test_artifacts/cdc_schema/
test_artifacts/cdc_schema_apply/
test_artifacts/cdc_promotion/
test_artifacts/cdc_runtime/
test_artifacts/cdc_poison_quarantine/
test_artifacts/cdc_compare_repair/
test_artifacts/certification/suite/
test_artifacts/observability/
test_artifacts/supply-chain/
Adding certification suite automation¶
Use Certification suite automation when a workflow needs to combine matrix correctness, benchmark regression, lineage, dbt lineage, and evidence checksums.
Recommended flow:
uv run dpone ops certification-run \
--artifact-dir test_artifacts/certification/current
uv run dpone ops benchmark-baseline \
--output-dir test_artifacts/benchmarks/current \
--metrics-json "$METRICS_JSON" \
--baseline-json "$BASELINE_JSON"
uv run dpone ops certification-suite \
--output-dir test_artifacts/certification/suite \
--suite-id "$GITHUB_RUN_ID" \
--certification-report test_artifacts/certification/current/certification_report.json \
--benchmark-baseline test_artifacts/benchmarks/current/benchmark_baseline.json \
--require-benchmark \
--format json
Rules:
- Keep this workflow manual or scheduled unless it is credential-free and fast.
- Upload
test_artifacts/certification/suite/withif: always(). - For critical source -> sink routes, generate route evidence first and then run
uv run dpone ops route-certification-pack; uploadtest_artifacts/route_certification/and any embeddedtest_artifacts/route_readiness/outputs withif: always(). - For new or changed source -> sink onboarding UX, run
uv run dpone ops connection-doctor,uv run dpone ops source-discover,uv run dpone ops route-bootstrap, anduv run dpone ops route-doctoragainst credential-free schema fixtures. Uploadtest_artifacts/onboarding/withif: always()and treatroute_doctor.jsonas the pre-readiness user-facing go/no-go artifact; see Route bootstrap and doctor. - For route acceptance changes, run
uv run dpone ops route-conformance runfor each changedsource -> sink -> strategypair and thenuv run dpone ops route-conformance release-gateover the produced artifacts. Uploadtest_artifacts/route_conformance/withif: always(). Ordinary OSS CI can use deterministic credential-free synthetic datasets; Docker-live/vendor-live jobs should attach live evidence separately. See Route Conformance Lab. - For protected Docker-live route acceptance, run
DPONE_VENDOR_LIVE=1 DPONE_LIVE_ROUTE_CONFORMANCE=1 uv run dpone ops route-conformance live-runwith--adapter vendor_liveor--adapter dockeragainst disposable Postgres, MSSQL, and ClickHouse services. The built-in protected bindings coverpostgres -> mssqlandmssql -> clickhouseforincremental_merge. Uploadroute_conformance_live.json,live_source_snapshot.json,live_sink_snapshot.json, and the embeddedroute_conformance.jsonwithif: always(). Keep the default adapterin_memoryfor ordinary OSS CI and register real Postgres, MSSQL, or ClickHouse adapters only in opt-in jobs. - For route release candidates, run
uv run dpone ops route-rc-executewithout--executefirst and uploadroute_rc_execution.json. Add--executeonly behind an explicit manual workflow input and after Docker or vendor-live services are ready. - When retry/resume, state commit, fencing, repair, resync, or route execution
ordering changes, run
uv run dpone ops route-execution-ledgerfor the affected route and uploadtest_artifacts/route_execution/withif: always(). The required route readiness evidence isroute_execution_ledger. Use--store-backend sqlite --store-uri test_artifacts/route_execution/shared/route_execution_ledger.sqlite3when a workflow has more than one local runner or needs atomic compare-and-swap lease fencing evidence; see Route execution ledger. - When source state, offset, xmin, LSN, cursor, or checkpoint promotion changes,
run
uv run dpone ops route-state-promoteafter route execution ledger evidence and uploadtest_artifacts/route_state/withif: always(). The required route readiness evidence isstate_promotion. Use--state-backend sqlite --state-uri test_artifacts/route_state/shared/route_state_store.sqlite3when a workflow has more than one local runner or needs atomic compare-and-swap state evidence; see Route state promotion. - For route release candidates, run
uv run dpone ops route-release-gateafterroute_readiness.json,route_certification_pack.json,route_execution_ledger.json,state_promotion.json, and any route-specific benchmark/schema/CDC evidence exist. Uploadtest_artifacts/route_release/withif: always()and treatroute_release_gate.jsonas the final route-scoped go/no-go artifact; see Route release gate. - For Docker-live or vendor-live route release candidates, run
uv run dpone ops route-live-certificationafter the upstream live checks have produced route evidence. Uploadtest_artifacts/route_live/withif: always()and pass the live bundle toroute-release-gate:
--artifact route_live_evidence_bundle=<route_live_certification.json> \
--require route_live_evidence_bundle
See
Route live certification.
- For route releases, run uv run dpone ops route-certify after refresh
execution, snapshot capture, exact verification, readiness, checklist, and
evidence-chain artifacts exist. Use --profile oss_ci in ordinary CI and
--profile vendor_live only in opt-in Docker-live/vendor-live jobs that also
attach route_live_evidence_bundle. Upload test_artifacts/route_certify/
with if: always() and treat route_certification_bundle.json as the final
route promotion artifact; see Route certify.
- For release candidates that claim first-class route certification, run
uv run dpone ops route-certify-release after every required route has a
route_certification_bundle.json. Upload
test_artifacts/route_certification_release/ with if: always() and treat
route_certification_release.json as the release-level go/no-go artifact;
see Route certify release.
- For final route-certified release review, run
uv run dpone ops route-release-finalize after route bundles are in a stable
bundle root. Upload test_artifacts/route_release_finalize/ with
if: always() and treat route_release_finalizer.json plus
route_certification_history_index.json as the final route release evidence;
see Route release finalize.
- For route release candidates that need the full train in one receipt, run
uv run dpone ops route-rc-orchestrator. Upload
test_artifacts/route_rc/ with if: always() and treat
route_rc_orchestration.json plus the nested release_evidence_pack.json as
the review bundle; see
Route release candidate orchestrator.
- For release candidates that merge a stacked train, export every PR with
gh pr view --json number,title,baseRefName,headRefName,state,mergeStateStatus,isDraft,url,statusCheckRollup,
run uv run dpone ops release-rc-collect, and then run the generated
uv run dpone ops release-rc-finalize command after route, docs, package,
and release evidence exists. Upload test_artifacts/release_rc_collect/ and
test_artifacts/release_rc_finalizer/ with if: always() and block tags
unless release_rc_finalizer.json is rc_ready; see
Release RC collector and
Release RC finalizer.
- For CDC promotion routes, generate or export a credential-free fixture, run
uv run dpone ops cdc-apply-certification, then run or review the embedded
uv run dpone ops cdc-handoff report; upload test_artifacts/cdc_apply/
with if: always().
- When CDC evidence is produced by another specialized job, generate snapshot
boundary, CDC window, retention, apply correctness, delete semantics, typed
hash, and schema drift artifacts first, then run uv run dpone ops cdc-handoff; upload
test_artifacts/cdc_handoff/ with if: always().
- When CDC telemetry or SLO behavior changes, run
uv run dpone ops cdc-observability-evidence with the handoff JSON, apply
certification JSON, metrics JSON, and optional SLO profile; upload
test_artifacts/cdc_observability/ with if: always().
- When CDC recovery behavior changes, run
uv run dpone ops cdc-recovery-evidence with handoff, apply,
observability, scenario, and optional policy JSON; upload
test_artifacts/cdc_recovery/ with if: always().
- When CDC schema evolution or target DDL governance changes, run
uv run dpone ops cdc-schema-evolution-evidence with handoff, apply,
observability, recovery, schema-change, and optional policy JSON; upload
test_artifacts/cdc_schema/ with if: always().
- When CDC target DDL apply or typed serving refresh behavior changes, run
uv run dpone ops cdc-schema-apply --mode dry_run and, for approved local
Docker routes, uv run dpone ops cdc-schema-apply --mode apply; upload
test_artifacts/cdc_schema_apply/ with if: always(); see
CDC schema apply. The opt-in live check must verify
additive column DDL, backfill SQL, cdc_schema_apply_result.json, and
typed_refresh/cdc_typed_materialization.json when --typed-refresh is set.
- When a CDC stream is ready for release or environment promotion, run
uv run dpone ops cdc-promotion-gate with apply, handoff, observability,
recovery, and schema evolution JSON; upload test_artifacts/cdc_promotion/
with if: always(). The gate records production_ready and
promote_offsets; it does not promote offsets itself.
- When runtime CDC apply behavior changes, run
uv run dpone ops cdc-runtime-run with a bounded events JSON and local
checkpoint JSON; upload test_artifacts/cdc_runtime/ with if: always().
This verifies that offsets commit only after durable sink apply.
- When CDC poison classification, quarantine, or replay behavior changes, run
uv run dpone ops cdc-runtime-run --poison-mode quarantine_and_continue,
uv run dpone ops cdc-quarantine-inspect, and
uv run dpone ops cdc-replay-execute; upload
test_artifacts/cdc_poison_quarantine/ with if: always(). See
CDC poison quarantine and replay. The check must
prove cdc_poison_quarantine.json, cdc_quarantine_inspection.json,
cdc_replay_execution.json, duplicate_events_skipped, and no offset
mutation during replay.
- When CDC compare, repair planning, or repair execution changes, run
uv run dpone ops cdc-compare-repair and, for approved bounded plans,
uv run dpone ops cdc-repair-execute; upload
test_artifacts/cdc_compare_repair/ with if: always(). See
CDC compare and repair. The check must prove
cdc_compare_repair.json, cdc_repair_plan.json,
cdc_repair_execution.json, source-to-ClickHouse CDC log current-state
comparison, and no offset mutation during repair.
- When CDC retention gap auto-resync changes, run
uv run dpone ops cdc-retention-check, uv run dpone ops cdc-resync-plan,
and, for approved bounded plans, uv run dpone ops cdc-resync-execute;
upload test_artifacts/cdc_retention_resync/ with if: always(). See
CDC retention gap auto-resync. The check must
prove cdc_retention_check.json, cdc_resync_plan.json,
cdc_resync_actions.json, cdc_resync_execution.json, Docker-live
mssql -> clickhouse probe coverage when credentials are available, and no
offset mutation during resync.
- When live CDC runtime adapters change, run the local smoke above and an
opt-in vendor-live uv run dpone ops cdc-runtime-run --mode live check for
mssql -> clickhouse; see CDC live runtime adapters.
The live check must verify SQL Server read, ClickHouse apply, and no offset
commit on non-durable sink receipts.
- When ClickHouse CDC serving materialization changes, run
uv run dpone ops cdc-materialize-clickhouse against a fixture or opt-in
Docker route and upload test_artifacts/cdc_materialization/ with
if: always(); see ClickHouse CDC materialization.
The check must verify active-row and tombstone delete modes.
- When ClickHouse CDC typed serving materialization changes, run
uv run dpone ops cdc-materialize-clickhouse-typed against a fixture or
opt-in Docker route and upload test_artifacts/cdc_typed_materialization/
with if: always(); see
ClickHouse CDC typed materialization.
The check must verify declared column types, active-row mode, tombstone mode,
--fail-on-parse-errors, --schema-drift-mode strict, and
cdc_typed_parse_quarantine.json for malformed payloads.
- Upload test_artifacts/observability/ with if: always() when a workflow exports runtime metrics.
- Add required secrets only to vendor-live jobs.
- Update Developer certification suite when adding evidence types.
Adding observability artifacts¶
Use Runtime observability when a workflow needs Prometheus/OpenTelemetry evidence for a run.
Recommended flow:
uv run dpone run "$MANIFEST" --format json > test_artifacts/runs/run_report.json
uv run dpone observability metrics-export \
--run-report test_artifacts/runs/run_report.json \
--output-dir test_artifacts/observability/current \
--label ci_run_id="$GITHUB_RUN_ID" \
--label branch="$GITHUB_REF_NAME" \
--format json
Rules:
- Keep labels secret-free and low-cardinality.
- Keep collector upload optional; artifact generation must work locally.
- Link any new failure mode to Failure runbooks.
- Update Developer observability guide when adding renderers or metric sources.
Adding supply-chain evidence¶
Use Supply-chain evidence when a release workflow needs SBOM, provenance, signature envelope, and checksum evidence.
Recommended flow:
uv build
uv run twine check dist/*
subjects=()
for artifact in dist/*.whl dist/*.tar.gz; do
subjects+=(--subject "$artifact")
done
uv run dpone supply-chain attest \
--release "$GITHUB_REF_NAME" \
"${subjects[@]}" \
--repository "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" \
--commit-sha "$GITHUB_SHA" \
--builder-id "github-actions:$GITHUB_RUN_ID" \
--signing-key "$DPONE_LOCAL_ATTESTATION_KEY" \
--signing-key-id github-actions \
--output-dir test_artifacts/supply-chain/current \
--format json
mkdir -p test_artifacts/supply-chain/github-attestations
for artifact in dist/*.whl dist/*.tar.gz; do
gh attestation verify "$artifact" \
--repo "$GITHUB_REPOSITORY" \
--source-ref "$GITHUB_REF" \
--source-digest "$GITHUB_SHA" \
--format json \
> "test_artifacts/supply-chain/github-attestations/$(basename "$artifact").github-attestation.json"
done
Rules:
- Upload
test_artifacts/supply-chain/withif: always(). - Keep
DPONE_LOCAL_ATTESTATION_KEYin the release environment secrets and fail the release when it is missing. - Do not store local HMAC signing keys in artifacts or logs.
- Use and verify GitHub Artifact Attestations or Sigstore/cosign for public identity-backed trust before PyPI publication.
- Run
uv run python tools/agent_policy/governance_gate.py --base-ref origin/master --output test_artifacts/agent-policy/agent_governance_gate.jsonwhen CI/CD, agent policy, release evidence, or supply-chain controls change. - Update Developer supply-chain guide when adding formats or signers.
Docs contract tests¶
When CI/CD documentation changes, add or update docs contract tests. A good test verifies:
- public workflow files are named in docs;
- default branch remains
master; - runbooks mention every required workflow;
- developer docs link to CI/CD implementation guidance.
PR description template for CI/CD changes¶
## CI/CD change
- Workflow(s):
- Trigger(s):
- Permissions:
- Secrets required:
- Artifacts produced:
- Local reproduction:
- Failure runbook updated:
- Docs updated: