Andrushika commented on code in PR #73378:
URL: https://github.com/apache/airflow/pull/73378#discussion_r4312034257


##########
dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md:
##########
@@ -0,0 +1,769 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ -->
+
+<!-- START doctoc generated TOC please keep comment here to allow auto update 
-->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+
+- [Fork CI for external contributors 
(AIP-120)](#fork-ci-for-external-contributors-aip-120)
+  - [Goals and non-goals](#goals-and-non-goals)
+  - [Overview](#overview)
+  - [Configuration](#configuration)
+  - [Eligibility](#eligibility)
+  - [Project CI gate](#project-ci-gate)
+  - [Fork mode CI](#fork-mode-ci)
+  - [Reconciler](#reconciler)
+  - [Monitor workflow](#monitor-workflow)
+  - [`breeze ci audit`](#breeze-ci-audit)
+  - [Documentation changes](#documentation-changes)
+  - [Rollout and rollback](#rollout-and-rollback)
+  - [Security considerations](#security-considerations)
+  - [Known limitations](#known-limitations)
+  - [Testing](#testing)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
+# Fork CI for external contributors (AIP-120)
+
+This document is the design of the CI changes implementing
+[AIP-120: Run CI for external contributions in contributor 
forks](https://cwiki.apache.org/confluence/spaces/AIRFLOW/pages/451974711/AIP-120+Run+CI+for+external+contributions+in+contributor+forks).
+The policy itself and its rationale live in the AIP and in the dev list 
discussions
+([first](https://lists.apache.org/thread/w74655o8y1jzrzcnygntyyovocf7zmzj),
+[second](https://lists.apache.org/thread/ky392mrrcmj312y1r276r30p584n804c), 
which agreed to
+start with an opt-in pilot).
+This document describes how the policy is mechanised.
+
+## Goals and non-goals
+
+Goals:
+
+- External contributors get CI feedback from a plain `git push` to their fork. 
No pull request
+  against their own fork, no manual workflow dispatch, no sorting through 
workflow files.
+- Project CI (`apache/airflow` runners) does not run for gated pull requests. 
The decision is
+  made by one function with one configuration file.
+- A single scheduled reconciler owns the lifecycle of gated pull requests: 
labelling, drafting,
+  undrafting, the state comment, the nudge after workflows are enabled, 
closing after
+  inactivity, and closing a pull request that tampered with the gate to get 
project CI. It is
+  idempotent, so missed or duplicated scheduled runs are harmless.
+- Maintainers and contributors see the fork CI state where they already look: 
a commit status
+  on the pull request head, red / yellow / green, linking to the run in the 
fork.
+- A contributor can verify their whole setup locally with `breeze ci audit` 
before pushing.
+- Everything ships dormant and is switched on by a one-line configuration 
change.
+- Before it is switched on for everyone, the whole flow can be piloted on real 
traffic by
+  committers on single pull requests and by volunteer external contributors on 
all their new
+  pull requests, without affecting anyone else.
+
+Non-goals:
+
+- The one-time reset of the open pull request backlog (AIP-120 §9.1). The 
design makes it a
+  configuration change, but it is decided separately.
+- Any change to how committer, collaborator or exempted-organisation pull 
requests are tested.
+- Event-driven mutation of pull requests. Nothing in this design uses 
`pull_request_target`.
+  All writes come from the scheduled reconciler.
+
+## Overview
+
+```
+                 contributor fork                          apache/airflow
+   ┌──────────────────────────────────┐      
┌──────────────────────────────────────────┐
+   │ git push feature-branch          │      │ pull_request event              
          │
+   │   └─ ci-amd.yml (push trigger)   │      │   └─ ci-amd.yml                 
          │
+   │        gate job: fork -> run     │      │        gate job: eligibility -> 
skip      │
+   │        build-info: fork mode     │      │        (build-info and 
everything after   │
+   │          changed files from      │      │         are skipped for gated 
PRs)        │
+   │          compare API vs upstream │      │                                 
          │
+   │        public runners only       │      │ fork-ci-monitor.yml (every 15 
minutes)    │
+   └──────────────────────────────────┘      │   └─ breeze ci 
fork-ci-reconcile          │
+                     ▲                        │        discover new gated PRs 
-> label    │
+                     │ GraphQL: checkSuites   │        per labelled PR: fork 
state ->     │
+                     │ REST: workflow state   │          draft/undraft, 
labels, comment,  │
+                     └────────────────────────│          commit status with 
run link,     │
+                                              │          close after 7 days or 
when the   │
+                                              │          PR tampered with the 
gate        │
+                                              │        unknown failures -> 
Slack          │
+                                              
└──────────────────────────────────────────┘
+```
+
+Four pieces, in dependency order:
+
+1. **Eligibility** — `dev/breeze/src/airflow_breeze/utils/fork_ci_gate.py`, 
one pure function
+   and one configuration file. Used by the gate job and by the reconciler.
+2. **Project CI gate** — a `gate` job at the head of `ci-amd.yml`.
+3. **Fork mode CI** — a push trigger plus fork-aware selective checks.
+4. **Reconciler** — `breeze ci fork-ci-reconcile`, run by 
`fork-ci-monitor.yml` on a schedule.
+
+Plus `breeze ci audit` for the contributor's local setup, and documentation.
+
+## Configuration
+
+One file, `.github/fork-ci-gate.toml`, parsed with the standard library 
`tomllib`:
+
+```toml
+# Fork CI gate (AIP-120). See 
dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md
+
+# Master switch. When false the gate job lets every pull request run project 
CI, except
+# pull requests labelled `use fork ci` and pull requests of [pilot] 
participants. Push
+# filtering for apache/airflow branches applies regardless.
+enabled = false
+
+# Pull requests created before this instant are never gated, whatever their 
author.
+# Moving the date back is how the backlog reset (AIP-120 §9.1) would be 
applied.
+enabled_since = 2026-01-01T00:00:00Z
+
+# Days without any fork CI activity after which a gated pull request is closed.
+close_after_days = 7
+
+# Organisations exempted under AIP-120 §2.2. Keys are display names used in 
comments,
+# values are GitHub logins. Changes go through a reviewed pull request.
+[allowlist]
+# "Example Org" = ["login-one", "login-two"]
+
+# Opt-in pilot participants. Keys are GitHub logins, values are the instant 
they joined.
+# Their pull requests created at or after that instant are gated whether or 
not `enabled`
+# is set. Contributors opt in and out with a pull request editing this table.
+[pilot]
+# "login-three" = 2026-10-20T00:00:00Z
+```
+
+The file lives in the repository rather than in an Actions variable because 
ASF projects
+cannot self-serve Actions variables, and because exemption changes should be 
reviewed like
+any other change. The gate job reads it from the pull request's *base* branch, 
never from
+the pull request's own tree, so a pull request cannot change its own 
eligibility.
+
+## Eligibility
+
+`fork_ci_gate.decide(event, config) -> Decision` is a pure function. `event` 
carries the
+fields both callers have: event name, repository, ref, head repository, author 
login,
+author association, pull request creation time and the pull request's current 
labels.
+`Decision` is `run` (a bool) plus a `reason` from a fixed set, used in logs, 
comments and by
+the reconciler.
+
+The rules, first match wins. The push rules are independent of `enabled` 
because the `'**'`
+push trigger exists whether or not the gate is on, and today no CI runs for 
pushes to
+`main` or to ad-hoc branches in `apache/airflow` (post-merge coverage is the 
cron canary).
+The label and pilot rules are also independent of `enabled`; see "Override 
labels" and
+"Contributor pilot" below.
+
+The `fork_schedule` rule exists because enabling `ci-amd.yml` in a fork also 
enables its
+cron trigger, and selective checks force the full matrix for `schedule` 
events. Without it
+every enabled fork would run the full canary matrix twice a day on the 
contributor's
+concurrency cap. A manual `workflow_dispatch` in a fork still runs.
+
+| Rule | Decision | Reason |
+|---|---|---|
+| Event is `schedule` and repository is not `apache/airflow` | skip | 
`fork_schedule` |
+| Event is `schedule` or `workflow_dispatch` | run | `scheduled` |
+| Event is `push` and repository is not `apache/airflow` | run | `fork_push` |
+| Event is `push` to `apache/airflow` and the branch matches the pre-existing 
push patterns (`v*-test`, `providers-*/v*`, `chart/v*x-test`, 
`airflow-ctl/v*-test`) | run | `canonical_branch` |
+| Event is `push` to `apache/airflow`, any other branch | skip | 
`adhoc_branch` |
+| Pull request carries `use project ci` | run | `label_project_ci` |
+| Pull request carries `use fork ci` | skip | `label_fork_ci` |
+| Author login is in `[pilot]` and the pull request was created at or after 
that login's join instant | skip | `pilot` |
+| `enabled` is false | run | `gate_disabled` |

Review Comment:
   We might need to sync this design doc with the copy in the stack. For 
example, there `head_is_upstream` now comes before `use fork ci`, and 
`base_without_gate` and the `needs project ci` label are new. The ADR also 
still says Slack gets two expected outcomes, while `green_unverified` posts too.
   
   ---
   Drafted-by: Claude Code (Opus 5.5); reviewed by @Andrushika before posting



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to