Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions config/repo_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,21 +364,27 @@ def validate_checks(checks: list[Any]) -> list[dict[str, str]]:
"""Validate and normalize a list of check command entries.

Filters out malformed entries and coerces values to strings.
Mirrors ``egg_config.validators.validate_checks``, including
the optional ``fix`` auto-remediation command (#3409).

Args:
checks: Raw list of check entries (e.g. from YAML or JSON).

Returns:
List of {"name": "...", "command": "..."} dicts with only
valid entries retained.
List of {"name": "...", "command": "..."} dicts (plus
"fix" when configured) with only valid entries retained.
"""
if not isinstance(checks, list):
return []
return [
{"name": str(c["name"]), "command": str(c["command"])}
for c in checks
if isinstance(c, dict) and "name" in c and "command" in c
]
result = []
for c in checks:
if not (isinstance(c, dict) and "name" in c and "command" in c):
continue
entry = {"name": str(c["name"]), "command": str(c["command"])}
if c.get("fix"):
entry["fix"] = str(c["fix"])
result.append(entry)
return result


def reload_config() -> None:
Expand Down Expand Up @@ -572,14 +578,16 @@ def get_repo_checks(repo: str) -> list[dict[str, str]]:

These are the commands to run during the SDLC pipeline implement phase
checker step. Each check has a "name" (display label) and "command"
(shell command to execute). They run sequentially.
(shell command to execute). They run sequentially. A check may also
carry an optional "fix" command — an auto-remediation the per-slice
green gate runs when the check is red at the slice tip (#3409).

Args:
repo: Repository in "owner/repo" format

Returns:
List of {"name": "...", "command": "..."} dicts,
or empty list if no checks configured.
List of {"name": "...", "command": "..."} dicts (plus "fix"
when configured), or empty list if no checks configured.
"""
checks = get_repo_setting(repo, "checks", [])
result: list[dict[str, str]] = validate_checks(checks)
Expand Down
8 changes: 8 additions & 0 deletions config/repositories.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ readable_repos:
# - checks: List of check commands for the SDLC pipeline implement phase
# Each entry has "name" (display label) and "command" (shell command)
# These run sequentially during the checker step
# An entry may also set "fix" (shell command): when the per-slice green
# gate finds that check red at the slice tip, it runs the fix command,
# re-runs the check, and — if the fix turned it green — commits and
# pushes the result to the slice integration branch as the orchestrator
# (#3409). Only configure deterministic auto-remediations here, e.g.
# "make lint-fix" for a format/lint check. Checks without "fix" route
# red verdicts back to the slice team unchanged.
# - build_commands: Commands to run during Docker image build to install
# project-specific dependencies. Results are baked into the image so
# containers start with dependencies pre-installed (critical for private
Expand Down Expand Up @@ -138,6 +145,7 @@ repo_settings:
# checks:
# - name: lint
# command: make lint
# fix: make lint-fix # optional green-gate auto-remediation (#3409)
# - name: test
# command: make test
# some-org/external-repo:
Expand Down
15 changes: 14 additions & 1 deletion docs/architecture/slice-dag.md
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,20 @@ shape:
rollout via `EGG_SLICE_GREEN_GATE` — default `on` (a red verdict
withholds the slice PR), `log` runs the checks and logs the
verdict without blocking; fail-open on infra errors, including
infra-signature-tagged reds inside check execution, #3417) — calls
infra-signature-tagged reds inside check execution, #3417.
**The gate can also write to the integration branch**: when every
genuine red carries an optional `fix:` command in
`repositories.yaml` (e.g. `lint: {fix: make lint-fix}`), the
runner applies the fixes in its worktree and the orchestrator
commits them as `egg-green-gate` and pushes to the integration
branch via the launcher-authed gateway push route, #3409. This is
the one place the orchestrator authors commits on a slice branch;
it fires only in `on` mode, and only when the runner proves the
exact tree `git add -u` will stage is green — one full re-run of
*every* configured check against the all-fixes-applied tree
(`final_verification.all_ok`) plus a no-new-untracked-files
check. Any failure to commit or push blocks the slice exactly
like an unfixed red) — calls
`GatewayClient.create_slice_pr` with `base` resolved from the
slice's DAG parent (root → latest completed chain tip, else the
pipeline branch (#3541); child → parent's
Expand Down
14 changes: 9 additions & 5 deletions orchestrator/routes/pipelines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,11 +467,15 @@ def get_repo_checks(repo: str) -> list[dict[str, str]]: # type: ignore[misc]
def validate_checks(checks: list) -> list[dict[str, str]]: # type: ignore[misc]
if not isinstance(checks, list):
return []
return [
{"name": str(c["name"]), "command": str(c["command"])}
for c in checks
if isinstance(c, dict) and "name" in c and "command" in c
]
result = []
for c in checks:
if not (isinstance(c, dict) and "name" in c and "command" in c):
continue
entry = {"name": str(c["name"]), "command": str(c["command"])}
if c.get("fix"):
entry["fix"] = str(c["fix"])
result.append(entry)
return result


pipelines_bp = Blueprint("pipelines", __name__, url_prefix="/api/v1/pipelines")
Expand Down
Loading
Loading