config

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package config ports src/sec_af/config.py: the depth profiles, the budget thresholds, the runtime AuditConfig the orchestrator phases consume, and the retry and model settings the AI gates apply (AIIntegrationConfig).

Nothing here reads the environment. The original read its AI settings from a chain of variables when the node booted; inside codeaf the provider half of that is gone and the rest are plain values with the node's defaults.

Index

Constants

View Source
const (
	DefaultAIMaxRetries            = 3
	DefaultAIInitialBackoffSeconds = 2.0
	DefaultAIMaxBackoffSeconds     = 8.0
)

The retry defaults the node read from SEC_AF_AI_MAX_RETRIES, SEC_AF_AI_INITIAL_BACKOFF_SECONDS and SEC_AF_AI_MAX_BACKOFF_SECONDS when those variables were unset. They are constants now because nothing in codeaf sets them from the environment.

Variables

This section is empty.

Functions

This section is empty.

Types

type AIIntegrationConfig

type AIIntegrationConfig struct {
	// AIModel is the model the AI gate names on its `.ai()` calls. Empty means
	// "name none", leaving the choice to the App's AI implementation, which is
	// what every agent outside the gate already does.
	AIModel string `json:"ai_model"`
	// MaxRetries is a count of RETRIES after the first attempt, so 0 means one
	// attempt and a negative value means none (see gates.runWithRetry).
	MaxRetries int `json:"max_retries"`
	// InitialBackoffSeconds and MaxBackoffSeconds bound the exponential delay
	// between attempts: min(initial * 2**attempt, max).
	InitialBackoffSeconds float64 `json:"initial_backoff_seconds"`
	MaxBackoffSeconds     float64 `json:"max_backoff_seconds"`
}

AIIntegrationConfig is what remains of the original AIIntegrationConfig once the provider machinery is gone: the retry schedule the gates apply around a model call, and the model the AI gate asks for.

The sec-af node built this from a dozen environment variables that chose an external coding-agent CLI, its binary, its model and the credentials it was handed. Inside codeaf none of that exists — the App behind the audit runs codeaf's own agent loop and model API, which already know their model, their key and their turn budget — so the provider, harness model, turn count, binary paths and provider environment were deleted rather than carried as settings nothing reads. What is left is plain configuration the codeaf side may set; DefaultAIConfig gives the values the node defaulted to.

func DefaultAIConfig

func DefaultAIConfig() AIIntegrationConfig

DefaultAIConfig returns the configuration a gate built without one uses: the node's retry schedule, and no model of its own.

type AuditConfig

type AuditConfig struct {
	RepoPath             string       `json:"repo_path"`
	Depth                DepthProfile `json:"depth"`
	SeverityThreshold    string       `json:"severity_threshold"`
	ScanTypes            []string     `json:"scan_types"`
	OutputFormats        []string     `json:"output_formats"`
	ComplianceFrameworks []string     `json:"compliance_frameworks"`
	IncludePaths         []string     `json:"include_paths"`
	ExcludePaths         []string     `json:"exclude_paths"`
	Budget               BudgetConfig `json:"budget"`
}

AuditConfig ports config.py AuditConfig — the runtime config the orchestrator phases consume (DESIGN.md §3 and §9).

IncludePaths is `list[str] | None` in Python and a nil-able slice here: nil means "no include filter" and is distinct from an empty list.

func DefaultAuditConfig

func DefaultAuditConfig() AuditConfig

DefaultAuditConfig builds the pydantic field defaults. repo_path is `Field(...)` (required) in Python and has no default; callers supply it.

Fresh slices are returned per call, mirroring `default_factory` — a shared package-level slice would let one audit's mutation leak into the next.

func (AuditConfig) FromInput

func (AuditConfig) FromInput(in any, repoPath string) (AuditConfig, error)

FromInput ports AuditConfig.from_input (config.py:53, DESIGN.md §8.2):

@classmethod
def from_input(cls, audit_input: AuditInput, repo_path: str) -> "AuditConfig":
    depth = DepthProfile(audit_input.depth)
    return cls(
        repo_path=repo_path,
        depth=depth,
        severity_threshold=audit_input.severity_threshold,
        scan_types=audit_input.scan_types,
        output_formats=audit_input.output_formats,
        compliance_frameworks=audit_input.compliance_frameworks,
        include_paths=audit_input.include_paths,
        exclude_paths=audit_input.exclude_paths,
        budget=BudgetConfig(
            max_cost_usd=audit_input.max_cost_usd,
            max_provers=audit_input.max_provers,
            max_duration_seconds=audit_input.max_duration_seconds,
        ),
    )

Two parity points that are easy to get wrong:

  • `DepthProfile(audit_input.depth)` is the STRICT enum constructor, not _normalize_depth. An unknown depth raises ValueError and the audit fails; it does NOT silently become "standard". FromInput returns an error with Python's ValueError text.
  • the BudgetConfig is constructed with ONLY the three caps, so the percentages and concurrency limits keep their own defaults.

The Python model also carried a `provider` field defaulting to the name of the external CLI the node drove. Nothing read it, and inside codeaf there is no such CLI, so the field was dropped.

in may be any value that JSON-marshals to the AuditInput shape — in practice schemas.AuditInput once that package exists, or AuditInputFields directly. Pass the typed struct through FromInputFields when you already have one.

func (AuditConfig) FromInputFields

func (AuditConfig) FromInputFields(in AuditInputFields, repoPath string) (AuditConfig, error)

FromInputFields is FromInput over the already-projected fields.

func (*AuditConfig) UnmarshalJSON

func (c *AuditConfig) UnmarshalJSON(data []byte) error

UnmarshalJSON seeds the pydantic defaults before decoding.

type AuditInputFields

type AuditInputFields struct {
	Depth                string   `json:"depth"`
	SeverityThreshold    string   `json:"severity_threshold"`
	ScanTypes            []string `json:"scan_types"`
	OutputFormats        []string `json:"output_formats"`
	ComplianceFrameworks []string `json:"compliance_frameworks"`
	IncludePaths         []string `json:"include_paths"`
	ExcludePaths         []string `json:"exclude_paths"`
	MaxCostUSD           *float64 `json:"max_cost_usd"`
	MaxProvers           *int     `json:"max_provers"`
	MaxDurationSeconds   *int     `json:"max_duration_seconds"`
}

AuditInputFields is the projection of schemas.AuditInput that AuditConfig.from_input reads. It exists so this package does not have to import internal/schemas (which owns the full AuditInput, including the ~12 fields from_input ignores): the json tags are the pydantic field names, so FromInput can project any AuditInput-shaped value onto it through JSON.

type BudgetConfig

type BudgetConfig struct {
	MaxCostUSD         *float64 `json:"max_cost_usd"`
	MaxProvers         *int     `json:"max_provers"`
	MaxDurationSeconds *int     `json:"max_duration_seconds"`

	ReconBudgetPct float64 `json:"recon_budget_pct"`
	HuntBudgetPct  float64 `json:"hunt_budget_pct"`
	ProveBudgetPct float64 `json:"prove_budget_pct"`

	MaxConcurrentHunters int `json:"max_concurrent_hunters"`
	MaxConcurrentProvers int `json:"max_concurrent_provers"`

	HunterEarlyStopFileThreshold int `json:"hunter_early_stop_file_threshold"`
}

BudgetConfig ports config.py BudgetConfig — the budget-enforcement thresholds from DESIGN.md §9.1.

The three caps are `X | None` in Python and pointers here: nil means "no cap", which is NOT the same as a zero cap. The percentages and concurrency limits have non-zero pydantic defaults, so UnmarshalJSON seeds them (a BudgetConfig can arrive over the wire inside a checkpoint or a phase payload, where a Go zero value would silently mean "no hunters, no budget").

func DefaultBudgetConfig

func DefaultBudgetConfig() BudgetConfig

DefaultBudgetConfig builds the pydantic defaults verbatim:

recon_budget_pct = 0.10, hunt_budget_pct = 0.45, prove_budget_pct = 0.45
max_concurrent_hunters = 4, max_concurrent_provers = 3
hunter_early_stop_file_threshold = 30
max_cost_usd / max_provers / max_duration_seconds = None

func (*BudgetConfig) UnmarshalJSON

func (b *BudgetConfig) UnmarshalJSON(data []byte) error

UnmarshalJSON seeds the pydantic defaults before decoding, so keys absent from the payload keep their Python default rather than the Go zero value.

type DepthProfile

type DepthProfile string

DepthProfile ports config.py DepthProfile — the scan-depth profile (DESIGN.md §9). It is a string type so it marshals to and from the same JSON values as the Python `class DepthProfile(str, Enum)`.

const (
	DepthQuick    DepthProfile = "quick"
	DepthStandard DepthProfile = "standard"
	DepthThorough DepthProfile = "thorough"
)

The three profiles, with the exact Python enum values.

func NormalizeDepth

func NormalizeDepth(depth string) DepthProfile

NormalizeDepth ports the _normalize_depth helper that SEC-AF repeats verbatim in four modules — src/sec_af/reasoners/phases.py:52, agents/recon/__init__.py:62, agents/hunt/__init__.py:73 and agents/prove/__init__.py:47:

def _normalize_depth(depth: str) -> DepthProfile:
    try:
        return DepthProfile(depth.lower())
    except ValueError:
        return DepthProfile.STANDARD

Lower-case first, and ANY unrecognised value silently becomes STANDARD. This is the LENIENT path used everywhere inside the pipeline; it is deliberately NOT what AuditConfig.FromInput does, which uses the strict `DepthProfile(...)` constructor and fails on a bad value.

src/sec_af/agents/hunt/business_logic.py:26 declares a fifth copy that accepts `str | DepthProfile` and short-circuits when it is already a profile. In Go DepthProfile IS a string type, so NormalizeDepth(string(d)) covers both arms with the same result.

func (DepthProfile) IsValid

func (d DepthProfile) IsValid() bool

IsValid reports whether d is one of the three declared profiles — the membership test `DepthProfile(value)` performs in Python.

func (DepthProfile) String

func (d DepthProfile) String() string

String returns the profile's wire value.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL