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:
Mandatory 4‑line header block
Module docstring structure
Diagnostics profile block
_dbgusage in non‑trivial modulesfunc = "..."pattern in functions that call_dbg()No hardcoded secrets (§6b Secret Hygiene — AST‑based detection)
Syntax warnings (invalid escape sequences)
Type hint coverage
Presence of regression tests
Project‑level documentation requirements
Directory exclusion rules
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_secretstests (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.