Option C Tools
Loading...
Searching...
No Matches
oct.git.quality_gate Namespace Reference

Classes

class  QualityGateResult
class  PreCommitResult

Functions

PreCommitResult pre_commit_checks (Path project_root, str branch, str message, bool force_commit, str profile, dict octrc)
list[Path] _resolve_scope (Path project_root, Literal["staged", "changed", "all"] scope)
list[Path] _walk_secret_filenames (Path project_root, *, exclude_dirs, wildcard_exclude_dirs, patterns)
 _build_linter_context (Path project_root)
 _build_formatter_context (Path project_root, *, bool fix_mode=False)
list[tuple[str, int, str]] _run_secrets_pass (list[Path] all_files, Path project_root, *, float code_entropy_threshold=4.5, float docstring_entropy_threshold=5.0, float comment_entropy_threshold=5.0, str secret_match_mode="substring", list[dict]|None entropy_exclusions=None, list[str]|None excluded_field_patterns=None)
tuple[int, list[dict]] _run_lint_pass (list[Path] py_files, Path project_root, str profile, bool fix_mode=False)
int _run_format_pass (list[Path] py_files, Path project_root, bool fix_mode=False)
int _run_test_pass (Path project_root, bool sandbox=False)
QualityGateResult run_quality_gate (Path project_root, Literal["staged", "changed", "all"] scope, Literal["proto", "compact", "strict"] profile, bool include_tests=False, bool fix=False, bool sandbox=False)
QualityGateResult run_quality_gate_on_files (Path project_root, list[Path] files, Literal["proto", "compact", "strict"] profile, bool include_tests=False, bool fix=False, bool sandbox=False)

Detailed Description

Purpose
-------
Orchestrate the Phase 4B unified quality gate: lint + format dry-run +
secrets detection on a scoped set of files. Returns a structured
:class:`QualityGateResult` that downstream consumers (``oct git check``,
``oct git commit``, hooks, MCP) can inspect and render.

Responsibilities
----------------
- Resolve file scope (staged / changed / all) via :mod:`oct.core.git`.
- Run the linter on Python files via :func:`oct.linter.oct_lint._lint_single_file`.
- Run the formatter in dry-run mode via :func:`oct.formatter.oct_format.format_file`.
- Run secrets detection (content + filename pattern) via
  :func:`oct.linter.oct_lint.check_no_hardcoded_secrets` and
  :data:`oct.core.exclusions.NEVER_EXPORT_FILE_PATTERNS`.
- Optionally run pytest via subprocess (``--include-tests``).
- Support ``--fix`` two-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 lint`` or ``oct format``.
- The only subprocess call is for pytest (``--include-tests``), which is
  a distinct tool boundary.
- :func:`run_quality_gate` never raises on check failures; it returns
  a :class:`QualityGateResult` with the findings. Only infrastructure
  errors (missing git repo, broken imports) may propagate.

Function Documentation

◆ _build_formatter_context()

oct.git.quality_gate._build_formatter_context ( Path project_root,
* ,
bool fix_mode = False )
protected
Build a ``FormatterContext`` for dry-run (or fix) mode.

Definition at line 317 of file quality_gate.py.

Here is the caller graph for this function:

◆ _build_linter_context()

oct.git.quality_gate._build_linter_context ( Path project_root)
protected
Build a minimal ``LinterContext`` for the quality gate.

We import lazily to avoid pulling Click and the full linter on
import of this module.

Definition at line 299 of file quality_gate.py.

Here is the caller graph for this function:

◆ _resolve_scope()

list[Path] oct.git.quality_gate._resolve_scope ( Path project_root,
Literal["staged", "changed", "all"] scope )
protected
Return the list of files to check based on *scope*.

For ``"staged"`` and ``"changed"`` we return **all** file types so
that filename-pattern secrets detection can flag non-Python files
like ``.env`` or ``*.pem``. The caller filters to ``.py`` for the
lint and format passes.

For ``"all"`` we use the linter's own ``find_python_files`` for the
Python set, but also walk the tree for non-Python secret-filename
checks.

Definition at line 191 of file quality_gate.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _run_format_pass()

int oct.git.quality_gate._run_format_pass ( list[Path] py_files,
Path project_root,
bool fix_mode = False )
protected
Run the formatter in dry-run (or fix) mode, return violation count.

A "violation" is a file where ``format_file`` reports ``changed=True``
(i.e. the formatter would modify it).

Definition at line 467 of file quality_gate.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _run_lint_pass()

tuple[int, list[dict]] oct.git.quality_gate._run_lint_pass ( list[Path] py_files,
Path project_root,
str profile,
bool fix_mode = False )
protected
Run the linter on *py_files* and return (violation_count, per_file).

Uses ``_lint_single_file`` directly, bypassing the CLI. The profile
selects which rules are active via ``_PROFILES``.

Definition at line 427 of file quality_gate.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _run_secrets_pass()

list[tuple[str, int, str]] oct.git.quality_gate._run_secrets_pass ( list[Path] all_files,
Path project_root,
* ,
float code_entropy_threshold = 4.5,
float docstring_entropy_threshold = 5.0,
float comment_entropy_threshold = 5.0,
str secret_match_mode = "substring",
list[dict] | None entropy_exclusions = None,
list[str] | None excluded_field_patterns = None )
protected
Check files for hardcoded secrets (content) and secret filenames.

Returns a list of ``(relative_path, line, reason)`` tuples.

Definition at line 334 of file quality_gate.py.

Here is the caller graph for this function:

◆ _run_test_pass()

int oct.git.quality_gate._run_test_pass ( Path project_root,
bool sandbox = False )
protected
Run ``python -m pytest tests/`` and return the failure count.

Returns 0 if all tests pass (exit code 0), or 1 if any test fails
(non-zero exit code). This is a subprocess boundary — tests are a
distinct tool and their execution is not inline.

When ``sandbox=True`` (OI-517), the pytest subprocess runs under a
sanitised environment via :class:`oct.mcp.sandbox.SandboxExecutor`:
secret-named env vars are stripped, ``PYTHONPATH`` is dropped, and a
600s wall-clock ceiling is enforced. Output is capped at 1 MiB so a
runaway test cannot flood stderr.

Definition at line 498 of file quality_gate.py.

Here is the caller graph for this function:

◆ _walk_secret_filenames()

list[Path] oct.git.quality_gate._walk_secret_filenames ( Path project_root,
* ,
exclude_dirs,
wildcard_exclude_dirs,
patterns )
protected
Yield non-Python files whose name matches any ``patterns`` glob.

Uses ``os.walk`` with in-place pruning of ``dirnames`` so excluded
trees are never descended into. Mirrors the exclusion semantics of
:func:`oct.linter.oct_lint.find_python_files` — if a directory name
is in ``exclude_dirs`` (exact) or matches one of the wildcard entries
(prefix/suffix/glob), it is pruned from the walk.

Definition at line 253 of file quality_gate.py.

Here is the caller graph for this function:

◆ pre_commit_checks()

PreCommitResult oct.git.quality_gate.pre_commit_checks ( Path project_root,
str branch,
str message,
bool force_commit,
str profile,
dict octrc )
OI-527: run the three pre-gate checks and collapse their outcomes
into a single :class:`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 when
    ``force_commit`` is True).
  * ``exit_code == 4`` — no staged files.
  * ``exit_code == 1`` — protected-branch block.

Definition at line 109 of file quality_gate.py.

◆ run_quality_gate()

QualityGateResult oct.git.quality_gate.run_quality_gate ( Path project_root,
Literal["staged", "changed", "all"] scope,
Literal["proto", "compact", "strict"] profile,
bool include_tests = False,
bool fix = False,
bool sandbox = False )
Orchestrate lint + format-dry-run + secrets on the scoped files.

When ``fix=True``, runs in two passes:

1. **Detect pass:** run the gate with ``fix=False`` to record the
   initial state.
2. **Fix pass:** run lint and format with ``fix_mode=True`` to apply
   auto-fixes.
3. **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 ``--fix`` flag 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 ``pytest`` as 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_tests`` is True, the pytest
    subprocess runs under the MCP sandbox environment — sanitised
    env, no network side-channels via PYTHONPATH, output capped.

Definition at line 545 of file quality_gate.py.

Here is the call graph for this function:

◆ run_quality_gate_on_files()

QualityGateResult oct.git.quality_gate.run_quality_gate_on_files ( Path project_root,
list[Path] files,
Literal["proto", "compact", "strict"] profile,
bool include_tests = False,
bool fix = False,
bool sandbox = False )
Run the quality gate on an explicit file list.

Identical contract to :func:`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, fix, sandbox
    Same semantics as :func:`run_quality_gate`.

Definition at line 604 of file quality_gate.py.

Here is the call graph for this function:
Here is the caller graph for this function: