Option C Linter#

Version: 0.3.0

A strict, deterministic static analysis tool enforcing the Option C coding standard across Python projects. The linter is part of a broader development ecosystem and is designed to be reusable across all current and future projects.


Purpose#

The Option C Linter validates and enforces:

  1. Mandatory 4‑line header block

  2. Module docstring structure

  3. Diagnostics profile block

  4. _dbg usage in non‑trivial modules

  5. func = "..." pattern in functions that call _dbg()

  6. No hardcoded secrets (§6b Secret Hygiene — AST‑based detection)

  7. Syntax warnings (invalid escape sequences)

  8. Type hint coverage

  9. Presence of regression tests

  10. Project‑level documentation requirements

  11. Directory exclusion rules

  12. Colorized terminal summary and log output

It can also automatically fix header blocks using --fix-headers.


Mandatory Header Block#

Every Python file in an Option C project must begin with:

#!/usr/bin/env python3

-- coding: utf-8 --#

<project_name>/<relative/path/to/file.py>#

Followed by exactly one blank line and then the module docstring.

The linter validates and enforces:

  • Correctness

  • Ordering

  • Uniqueness

  • No leading whitespace

  • No comments before shebang

  • Exactly one blank line after the header block


func = "..." Pattern Check#

Every non-trivial function (in files longer than 20 lines) that calls _dbg() must define func = "function_name" as a local variable before the first _dbg() call:

def my_function(data):
    func = "my_function"
    _dbg("L3", "Processing data", domain="DOMAIN", func=func)

The linter scans each function body using an indent-based parser. For each function containing a _dbg() call, it verifies that func = "..." (or func = '...') was assigned first. Violations are reported per function name.

Functions that contain no _dbg() calls are not flagged.


no_hardcoded_secrets Check (§6b Secret Hygiene)#

Hardcoded secrets in source files are a blocking lint violation at compact and strict profiles. The check uses AST inspection to detect three patterns:

Pattern A — Direct assignment:

# VIOLATION
password = "hunter2"
API_KEY = "sk-abc123"
password: str = "hunter2"  # annotated assignment

# SAFE (not flagged)
password = os.getenv("PASSWORD")
API_KEY = os.environ["API_KEY"]
password = get_password()

Pattern B — Dict literal with secret-like key:

# VIOLATION
config = {"password": "secret", "api_key": "sk-123"}

# SAFE (not flagged)
config = {"password": os.getenv("DB_PASS")}
config = {"max_retries": "3"}

Pattern C — Function default argument:

# VIOLATION
def connect(password="default"):
    ...

# SAFE (not flagged)
def connect(host="localhost"):
    ...

Secret-like names include: password, passwd, pwd, secret, secret_key, private_key, api_key, apikey, api_secret, token, auth_token, access_token, refresh_token, connection_string, conn_str, dsn, database_url, db_url, aws_secret, aws_key, aws_access, credentials, client_secret.

The correct pattern is to load secrets from environment variables at runtime:

import os
API_KEY = os.environ["API_KEY"]
DATABASE_URL = os.getenv("DATABASE_URL")

Waivers are supported via the inline waiver mechanism:

password = "test"  # OCT-LINT: disable=no_hardcoded_secrets reason="Test fixture"

Usage#

From any Option C project root:

oct lint

To automatically fix header blocks:

oct lint --fix-headers

A log file is written to the project’s logs/ directory.


Test Suite#

The linter includes a full test suite located in tests_linter/.

Test Types#

  • Header validation tests

  • Header fixing tests

  • no_hardcoded_secrets tests (21 tests covering all patterns, safe patterns, edge cases)

  • Integration tests

  • Regression tests

  • Fixtures (intentionally malformed files)

Run tests with:

pytest tests_linter


Continuous Integration#

A GitHub Actions workflow is included in:

.github/workflows/linter-tests.yml

It runs the full test suite on every push or pull request.


Project Philosophy#

The linter is itself an Option C project:

  • Fully documented

  • Fully tested

  • Fully deterministic

  • Fully compliant with the Option C standard

It is designed to evolve alongside the ecosystem and remain reusable across all future projects.


License#

Internal development tool — license as appropriate for your ecosystem.