Skip to content

Authoring Custom Packs

Create custom standards packs for organization-specific rules.

Pack structure

Each pack is a Python package inside src/guard/packs/:

src/guard/packs/
  my_custom_pack/
    __init__.py       # Module docstring (1 line)
    pack.yaml         # Pack metadata + rules

__init__.py

"""My Custom Pack — description of what this pack covers."""

pack.yaml

name: "My Custom Pack"
description: "One-sentence description of the pack's purpose"

rules:
  - id: MYPACK-001
    name: rule-name
    type: regex
    pattern: "..."
    severity: high
    file_glob: "**/*.py"

Rule format

Required fields

Field Type Description
id string Unique ID (prefix with pack abbreviation)
name string Kebab-case name
type string regex, required_pattern, file_policy, ast, or documentation_obligation
severity string critical, high, medium, low, or info

Optional fields

Field Type Description
description string What the rule detects
file_glob string Glob pattern for files to check
pattern string Regex pattern (for regex/required_pattern)
all_patterns list All patterns must match (composite regex)
check string Check function name (for file_policy)
ast_check string AST check function (for ast)
params dict Configurable thresholds
autofix string remove_line, comment_out, or replace
replacement string Replacement text (with autofix: replace)
standard string Regulatory standard name
clause string Standard clause reference
remediation_guidance string Fix instructions shown in reports
tags list Categorization tags

Rule type examples

Regex

- id: MYPACK-001
  name: no-hardcoded-passwords
  type: regex
  pattern: "(?i)password\\s*=\\s*[\"'][^\"']{4,}"
  severity: critical
  file_glob: "**/*.py"
  remediation_guidance: "Use environment variables or a secrets manager"

Composite regex

- id: MYPACK-002
  name: sql-injection-risk
  type: regex
  severity: critical
  file_glob: "**/*.py"
  all_patterns:
    - "execute\\("
    - "request\\.(GET|POST|form)"

Required pattern

- id: MYPACK-003
  name: require-license-header
  type: required_pattern
  pattern: "Licensed under"
  severity: low
  file_glob: "src/**/*.py"

File policy

- id: MYPACK-004
  name: max-file-length
  type: file_policy
  check: max_lines
  severity: medium
  file_glob: "**/*.py"
  params:
    max_lines: 400

Available checks: starts_with_docstring, max_lines, must_contain_pattern, must_not_import, max_function_count.

AST

- id: MYPACK-005
  name: strict-complexity
  type: ast
  ast_check: high_complexity
  severity: high
  file_glob: "src/**/*.py"
  params:
    max_complexity: 7

Available checks: no_mutable_defaults, no_star_imports, high_complexity, no_nested_functions, no_global_variables, max_function_length.

Documentation obligation

- id: MYPACK-DOC-001
  name: incident-response-plan
  type: documentation_obligation
  severity: info
  standard: "Internal Policy"
  clause: "IRP-01"
  remediation_guidance: "Create and maintain an incident response plan"

Registering a pack

Add an entry to _BUILTIN_PACKS in src/guard/packs/registry.py:

_BUILTIN_PACKS: dict[str, str] = {
    "fda-iec-62304": "guard.packs.fda_iec_62304",
    "owasp-top-10": "guard.packs.owasp_top_10",
    "soc2": "guard.packs.soc2",
    "my-custom-pack": "guard.packs.my_custom_pack",
}

Enabling

sentra add-pack my-custom-pack

Or in .guard.yaml:

standards_packs:
  - my-custom-pack

Testing

sentra list-packs           # Verify pack loads
sentra list-rules           # Verify rules appear
sentra scan                 # Check findings

ID naming conventions

Pack Format Example
FDA IEC 62304 IEC62304-{category}-{num} IEC62304-CODE-001
OWASP Top 10 OWASP-{category}-{num} OWASP-A01-001
SOC2 SOC2-{category}-{num} SOC2-CC6-001

Use a consistent prefix for your organization.

Severity guidelines

Severity When to use
critical Security vulnerabilities, data exposure
high Bugs likely to cause issues, unsafe patterns
medium Code quality, maintainability risks
low Style issues, minor improvements
info Documentation obligations, informational