oct.git.quality_gate module#
Purpose#
Orchestrate the Phase 4B unified quality gate: lint + format dry-run +
secrets detection on a scoped set of files. Returns a structured
QualityGateResult that downstream consumers (oct git check,
oct git commit, hooks, MCP) can inspect and render.
Responsibilities#
Resolve file scope (staged / changed / all) via
oct.core.git.Run the linter on Python files via
oct.linter.oct_lint._lint_single_file().Run the formatter in dry-run mode via
oct.formatter.oct_format.format_file().Run secrets detection (content + filename pattern) via
oct.linter.oct_lint.check_no_hardcoded_secrets()andoct.core.exclusions.NEVER_EXPORT_FILE_PATTERNS.Optionally run pytest via subprocess (
--include-tests).Support
--fixtwo-pass mode: detect → fix → re-verify.
Diagnostics#
Domain: GIT Levels:
L2 — lifecycle: gate start/end, scope resolution L3 — details: per-pass summary counts L4 — deep trace: per-file check outcomes
Contracts#
This module does not import
click. It is a pure orchestrator.It calls existing library functions (linter, formatter, exclusions) directly; it never shells out to
oct lintoroct format.The only subprocess call is for pytest (
--include-tests), which is a distinct tool boundary.run_quality_gate()never raises on check failures; it returns aQualityGateResultwith the findings. Only infrastructure errors (missing git repo, broken imports) may propagate.
- class oct.git.quality_gate.PreCommitResult(ok: bool, exit_code: int, errors: list, branch: str, effective_profile: str, staged_files: list, pb_advisory: str = '')[source]#
Bases:
objectOI-527: structured outcome of the three pre-gate checks that run before
oct git commitexecutes the quality gate.When
okis True the caller proceeds to the quality gate usingstaged_files; the other fields carry context the command needs regardless (branch, effective_profile). Whenokis False the caller emitserrorson stderr (or as JSON) and exits withexit_code.pb_advisoryis a protected-branch advisory string that must be echoed whether or not the check blocked the commit; callers treat it as a side-channel warning.- branch: str#
- effective_profile: str#
- errors: list#
- exit_code: int#
- ok: bool#
- pb_advisory: str = ''#
- staged_files: list#
- class oct.git.quality_gate.QualityGateResult(files_checked: int = 0, lint_violations: int = 0, format_violations: int = 0, secrets_findings: list = <factory>, test_failures: int = 0, duration_ms: int = 0, exit_code: int = 0, per_file: list = <factory>)[source]#
Bases:
objectStructured output from a quality-gate run.
Every field is JSON-serialisable (primitives, lists of tuples/dicts). Field names must match the attribute access in
oct.git.policy.apply_profile_policy().- duration_ms: int = 0#
- exit_code: int = 0#
- files_checked: int = 0#
- format_violations: int = 0#
- lint_violations: int = 0#
- per_file: list#
Per-file dicts suitable for
--jsonrendering.
- secrets_findings: list#
List of
(path_str, line, reason)tuples.
- test_failures: int = 0#
- oct.git.quality_gate.pre_commit_checks(project_root: Path, branch: str, message: str, force_commit: bool, profile: str, octrc: dict) PreCommitResult[source]#
OI-527: run the three pre-gate checks and collapse their outcomes into a single
PreCommitResult.The helper replaces the four sequential early-return blocks that previously lived in
git_commit_cmd(commit-message validation, staged-files presence, protected-branch guard). Exit codes and side effects match the original CLI behaviour byte-for-byte:exit_code == 3— invalid commit message (skipped whenforce_commitis True).exit_code == 4— no staged files.exit_code == 1— protected-branch block.
- oct.git.quality_gate.run_quality_gate(project_root: Path, scope: Literal['staged', 'changed', 'all'], profile: Literal['proto', 'compact', 'strict'], include_tests: bool = False, fix: bool = False, sandbox: bool = False) QualityGateResult[source]#
Orchestrate lint + format-dry-run + secrets on the scoped files.
When
fix=True, runs in two passes:Detect pass: run the gate with
fix=Falseto record the initial state.Fix pass: run lint and format with
fix_mode=Trueto apply auto-fixes.Re-verify pass: run the gate again with
fix=False. The returned result reflects the post-fix state.
Secrets are never auto-fixed (no safe auto-fix for a hardcoded password). The
--fixflag does not bypass the always-blocking secrets rule.- Parameters:
project_root – Resolved project root containing
.octrc.json,tests/, etc.scope –
"staged"checks only the git index;"changed"checks staged + unstaged + untracked;"all"checks every Python file.profile – Lint profile:
"proto"/"compact"/"strict".include_tests – If True, also run
pytestas a subprocess (exit code 4 on fail).fix – If True, attempt auto-fix of lint/format violations, then re-check.
sandbox – OI-517: when True and
include_testsis True, the pytest subprocess runs under the MCP sandbox environment — sanitised env, no network side-channels via PYTHONPATH, output capped.
- oct.git.quality_gate.run_quality_gate_on_files(project_root: Path, files: list[Path], profile: Literal['proto', 'compact', 'strict'], include_tests: bool = False, fix: bool = False, sandbox: bool = False) QualityGateResult[source]#
Run the quality gate on an explicit file list.
Identical contract to
run_quality_gate()but accepts a pre-resolved list of files instead of computing one from a scope string. This is the entry point used by F1.3 per-subproject fan-out at workspace-level commit, where the workspace-wide staged set is grouped into subproject buckets and each bucket runs under its own profile.- Parameters:
project_root – Resolved project root for octrc / linter-context / secrets config loading. For a per-subproject call, pass the subproject’s path; for a workspace-level call, pass the workspace root.
files – Pre-filtered list of files to lint / format / scan. May include non-Python files (passed through to the secrets scanner; lint/format ignore them via the suffix filter).
profile – Lint profile:
"proto"/"compact"/"strict".include_tests – Same semantics as
run_quality_gate().fix – Same semantics as
run_quality_gate().sandbox – Same semantics as
run_quality_gate().