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 ¶
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.