fix(ci): add workflow lint harness
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
name: CI Workflow Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- ".gitea/workflows/ci.yml"
|
||||||
|
- "tools/validate_gitea_ci_workflow_lint_v1.py"
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- ".gitea/workflows/ci.yml"
|
||||||
|
- "tools/validate_gitea_ci_workflow_lint_v1.py"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate-ci-workflow-lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Python Environment
|
||||||
|
run: |
|
||||||
|
/usr/bin/python3 --version
|
||||||
|
/usr/bin/python3 -m pip --version
|
||||||
|
/usr/bin/python3 -m pip install --disable-pip-version-check --quiet pyyaml
|
||||||
|
|
||||||
|
- name: Lint CI Workflow Contract
|
||||||
|
run: python3 tools/validate_gitea_ci_workflow_lint_v1.py --workflow .gitea/workflows/ci.yml
|
||||||
@@ -83,12 +83,14 @@
|
|||||||
- `tools/validate_platform_transition_wbs_v1.py`: `.gs → Python` and `xlsx → sqlite` WBS validator.
|
- `tools/validate_platform_transition_wbs_v1.py`: `.gs → Python` and `xlsx → sqlite` WBS validator.
|
||||||
- `tools/validate_qualitative_sell_strategy_pipeline_v1.py`: qualitative sell validator.
|
- `tools/validate_qualitative_sell_strategy_pipeline_v1.py`: qualitative sell validator.
|
||||||
- `tools/validate_gitea_secrets_contract_v1.py`: Gitea secrets validator.
|
- `tools/validate_gitea_secrets_contract_v1.py`: Gitea secrets validator.
|
||||||
|
- `tools/validate_gitea_ci_workflow_lint_v1.py`: CI workflow lint validator for recurring service-binding mistakes.
|
||||||
- `tools/validate_snapshot_admin_web_v1.py`: snapshot admin smoke validator.
|
- `tools/validate_snapshot_admin_web_v1.py`: snapshot admin smoke validator.
|
||||||
- `tests/parity/test_price_qty_parity_v1.py`: price/qty parity.
|
- `tests/parity/test_price_qty_parity_v1.py`: price/qty parity.
|
||||||
- `tests/parity/test_score_parity_v1.py`: timing score parity.
|
- `tests/parity/test_score_parity_v1.py`: timing score parity.
|
||||||
- `tests/parity/test_routing_gate_parity_v1.py`: routing gate parity.
|
- `tests/parity/test_routing_gate_parity_v1.py`: routing gate parity.
|
||||||
- `.gitea/workflows/qualitative_sell_strategy.yml`: qualitative sell strategy workflow.
|
- `.gitea/workflows/qualitative_sell_strategy.yml`: qualitative sell strategy workflow.
|
||||||
- `.gitea/workflows/snapshot_admin.yml`: snapshot admin workflow and scheduled validation.
|
- `.gitea/workflows/snapshot_admin.yml`: snapshot admin workflow and scheduled validation.
|
||||||
|
- `.gitea/workflows/ci_lint.yml`: CI workflow lint gate for `.gitea/workflows/ci.yml`.
|
||||||
- `docs/CLOUD_SERVER_SETUP.md`: 클라우드 서버(hz-prod-01, 178.104.200.7) 설정 하네스 가이드. 시놀로지 → 클라우드 마이그레이션 매핑 포함.
|
- `docs/CLOUD_SERVER_SETUP.md`: 클라우드 서버(hz-prod-01, 178.104.200.7) 설정 하네스 가이드. 시놀로지 → 클라우드 마이그레이션 매핑 포함.
|
||||||
- `docs/GITEA_SECRETS_SETUP.md`: Gitea secrets setup and verification guide.
|
- `docs/GITEA_SECRETS_SETUP.md`: Gitea secrets setup and verification guide.
|
||||||
- `docs/GATHERTRADINGDATA_XLSX_OPERATING_RUNBOOK.md`: `GatherTradingData.xlsx` 보조 자산 런북.
|
- `docs/GATHERTRADINGDATA_XLSX_OPERATING_RUNBOOK.md`: `GatherTradingData.xlsx` 보조 자산 런북.
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
DEFAULT_WORKFLOW = ROOT / ".gitea" / "workflows" / "ci.yml"
|
||||||
|
|
||||||
|
|
||||||
|
def _load_yaml(path: Path) -> dict:
|
||||||
|
return yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
ap = argparse.ArgumentParser(description="Lint the QuantEngine CI workflow for recurring service-binding mistakes.")
|
||||||
|
ap.add_argument("--workflow", default=str(DEFAULT_WORKFLOW))
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
workflow_path = Path(args.workflow)
|
||||||
|
if not workflow_path.is_absolute():
|
||||||
|
workflow_path = (ROOT / workflow_path).resolve()
|
||||||
|
data = _load_yaml(workflow_path)
|
||||||
|
|
||||||
|
errors: list[str] = []
|
||||||
|
evidence: dict[str, object] = {
|
||||||
|
"workflow": str(workflow_path.relative_to(ROOT)),
|
||||||
|
"jobs": sorted((data.get("jobs") or {}).keys()),
|
||||||
|
}
|
||||||
|
|
||||||
|
jobs = data.get("jobs") or {}
|
||||||
|
core = jobs.get("validate-core") or {}
|
||||||
|
services = core.get("services") or {}
|
||||||
|
postgres = services.get("postgres") or {}
|
||||||
|
|
||||||
|
ports = postgres.get("ports") or []
|
||||||
|
if any(str(port).strip() == "5432:5432" for port in ports):
|
||||||
|
errors.append("validate-core.services.postgres.ports contains fixed host mapping 5432:5432")
|
||||||
|
|
||||||
|
if "PGHOST: postgres" not in workflow_path.read_text(encoding="utf-8"):
|
||||||
|
errors.append("workflow does not pin PGHOST=postgres for CI database steps")
|
||||||
|
|
||||||
|
if "QE_WBS_PG_DSN=host=postgres" not in workflow_path.read_text(encoding="utf-8"):
|
||||||
|
errors.append("workflow does not publish QE_WBS_PG_DSN with service hostname")
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"formula_id": "GITEA_CI_WORKFLOW_LINT_V1",
|
||||||
|
"gate": "PASS" if not errors else "FAIL",
|
||||||
|
"errors": errors,
|
||||||
|
"evidence": evidence,
|
||||||
|
}
|
||||||
|
out = ROOT / "Temp" / "gitea_ci_workflow_lint_v1.json"
|
||||||
|
out.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||||
|
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||||
|
return 0 if not errors else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user