ADR 0008: Airflow parse-safe provider¶
Status¶
Accepted.
Amended by ADR 0024. The bounded loader accepts v1 only for
local_preview; strict executableinit_fetchrequiresdpone.airflow-deployment-index.v2.
Context¶
Airflow DAG parsing must be deterministic and fast. It must not parse dpone manifests, call external systems, read secrets, or refresh caches.
Decision¶
The canonical Airflow import is airflow.providers.dpone. The recommended loader is:
from airflow.providers.dpone import load_dpone_dags
load_report = load_dpone_dags(
globals(),
index_path="/opt/airflow/dags/.dpone-cache/current/airflow-index.json",
)
if load_report.fatal:
error_code = (
load_report.errors[0].get("code", "DPONE_AIRFLOW_INDEX_INVALID")
if load_report.errors
else "DPONE_AIRFLOW_INDEX_INVALID"
)
raise RuntimeError(
f"{error_code}: dpone Airflow deployment index could not be loaded"
)
The loader reads one supported airflow-index.json: v1 for non-runnable
local_preview, or v2 for strict executable init_fetch. It resolves only
cache:// artifacts inside the configured cache root, validates sizes and
checksums, and returns LoadReport.
The same bounded resolution surface is available through CacheResolver for
escape-hatch code that needs to resolve logical cached://dags/<dag_id> /
cached://workloads/<workload_id> refs or the strict pinned
cached://deployments/<deployment_id>/dags/<dag_id> /
cached://deployments/<deployment_id>/workloads/<workload_id> refs without
scanning the repository or touching external systems. Query-form
release/deployment pins remain a compatibility path, but public examples use
the deployment-scoped form.
dpone init project --airflow also owns the migration path for generated
dags/dpone.py files. It upgrades only an exact SHA-256 fingerprint from the
allowlist of historical dpone-generated loaders. The replacement uses a
compare-and-swap guard against the fingerprint observed during planning.
Canonical bytes are a no-op on later runs. Unknown bytes, including comments or
whitespace edits to an otherwise generated loader, remain a conflict and are
never overwritten. Fresh scaffolds and successful upgrades both use the same
canonical template.
Consequences¶
- Airflow parse path is bounded.
- A missing, malformed, or contract-invalid deployment index is visible as an Airflow DAG import error instead of a successful parse with zero dpone DAGs.
- Generated-loader migration is deterministic and idempotent; maintainers rerun
dpone init project --airflowinstead of hand-editing the loader. - User-owned loader variants require manual review and remain byte-for-byte unchanged.
- Existing
dpone_airflow_packprovider facade APIs remain as compatibility exports and emit oneDeprecationWarningper process when accessed from the legacy root namespace. - Invalid DAG specs are isolated according to provider policy.