Documentation
¶
Index ¶
- func FixFilePermissions(result *FilePermissionResult, policy *FilePermissionPolicy, dryRun bool) error
- func FormatPolicyViolations(result *PolicyEnforcementResult) string
- func GetPolicyEnforcementSummary(securityCfg *SecurityConfig) string
- func IsReservedTargetName(name string) bool
- func LoadEnvFile(path string) (int, error)
- func LoadEnvFileIfExists(logFunc func(string, ...any)) error
- func LoadEnvFileIfExistsSilent() error
- func LoadPrivateKey(path string) (ed25519.PrivateKey, error)
- func LoadPublicKey(keyID string) (ed25519.PublicKey, error)
- func LoadSignatureFromFile(filePath string) ([]byte, error)
- func ResolveAutoUpdateOnChange(cliFlag *bool, template *Template, cfg *DuckConf) bool
- func ResolveLogLevel(cliLogLevel string, cfg *DuckConf) string
- func ResolveTrackCommitHash(cliFlag *bool, template *Template, cfg *DuckConf) bool
- func SaveKeyPair(keyPair *SignatureKeyPair, outputDir string) error
- func SaveSignatureToFile(signature []byte, filePath string) error
- func SignConfig(configData []byte, privateKey ed25519.PrivateKey) ([]byte, error)
- func ValidateRepoAccess(repoURL string, securityCfg *SecurityConfig) error
- func ValidateStrictPolicyMode(securityCfg *SecurityConfig) error
- func ValidateTarget(t Target, name string) error
- func VerifySignature(configData, signature []byte, publicKey ed25519.PublicKey) error
- type ArgList
- type Delims
- type DigitalSignature
- type DuckConf
- type FilePermissionPolicy
- type FilePermissionResult
- type ParentDirectoryResult
- type PolicyEnforcement
- type PolicyEnforcementResult
- type PolicyViolation
- type Remote
- type ResolvedTemplate
- type SecurityConfig
- func BuildSecurityConfig(cliAllowed []string, cliDenied []string, cliStrict bool) *SecurityConfig
- func BuildSecurityConfigWithFiles(cliAllowed []string, cliDenied []string, cliStrict bool) (*SecurityConfig, error)
- func BuildSecurityConfigWithPrecedence(cliAllowed []string, cliDenied []string, cliStrict bool) (*SecurityConfig, error)
- func LoadSecurityConfigFromEnv() *SecurityConfig
- func LoadSecurityConfigFromFile(path string) (*SecurityConfig, error)
- func MergeSecurityConfigs(configs ...*SecurityConfig) *SecurityConfig
- type SecurityConfigFile
- type SecurityConfigPrecedenceInfo
- type SecurityFileType
- type SecurityMetadata
- type Settings
- type SignatureKeyPair
- type Target
- type Template
- type VarKind
- type VarValue
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FixFilePermissions ¶ added in v0.16.0
func FixFilePermissions(result *FilePermissionResult, policy *FilePermissionPolicy, dryRun bool) error
FixFilePermissions attempts to fix file permission issues
func FormatPolicyViolations ¶ added in v0.16.0
func FormatPolicyViolations(result *PolicyEnforcementResult) string
FormatPolicyViolations formats policy violations for user display
func GetPolicyEnforcementSummary ¶ added in v0.16.0
func GetPolicyEnforcementSummary(securityCfg *SecurityConfig) string
GetPolicyEnforcementSummary provides a summary of active policy enforcement
func IsReservedTargetName ¶ added in v0.21.0
IsReservedTargetName checks if a target name conflicts with subcommand names This is used for warnings and conflict detection, but doesn't prevent target creation
func LoadEnvFile ¶ added in v0.11.0
LoadEnvFile loads environment variables from a .env file into the OS environment. It follows these rules: - Supports KEY=VALUE format - Skips empty lines and comments (lines starting with #) - Removes surrounding quotes (both single and double) - Existing environment variables take precedence (are not overwritten) - Returns the number of variables loaded and any error
func LoadEnvFileIfExists ¶ added in v0.11.0
LoadEnvFileIfExists attempts to find and load a .env file and logs the result. This is the main entry point for automatic .env loading. It returns an error only if a .env file is found but cannot be loaded. Not finding a .env file is not considered an error. The logFunc parameter allows callers to provide their own logging function. If logFunc is nil, no logging is performed.
func LoadEnvFileIfExistsSilent ¶ added in v0.11.0
func LoadEnvFileIfExistsSilent() error
LoadEnvFileIfExistsSilent loads .env file without any logging output. This is useful for early loading before logging is configured.
func LoadPrivateKey ¶ added in v0.16.0
func LoadPrivateKey(path string) (ed25519.PrivateKey, error)
LoadPrivateKey loads a private key from a file
func LoadPublicKey ¶ added in v0.16.0
LoadPublicKey loads a public key by key ID using the key discovery mechanism
func LoadSignatureFromFile ¶ added in v0.16.0
LoadSignatureFromFile loads a signature from a file
func ResolveAutoUpdateOnChange ¶ added in v0.7.0
ResolveAutoUpdateOnChange determines the effective auto-update setting from CLI flag, environment, and config Precedence: CLI flag > Environment variable > Template config > Global settings > Default (false)
func ResolveLogLevel ¶ added in v0.6.0
ResolveLogLevel determines the effective log level from CLI flag, environment, and config Precedence: CLI flag > Environment variable > Config file > Default ("info") Returns the log level string, caller should parse it using run.ParseLogLevel
func ResolveTrackCommitHash ¶ added in v0.7.0
ResolveTrackCommitHash determines the effective track commit hash setting from CLI flag, environment, and config Precedence: CLI flag > Environment variable > Template config > Global settings > Default (false)
func SaveKeyPair ¶ added in v0.16.0
func SaveKeyPair(keyPair *SignatureKeyPair, outputDir string) error
SaveKeyPair saves a key pair to the specified directory
func SaveSignatureToFile ¶ added in v0.16.0
SaveSignatureToFile saves a signature to a file
func SignConfig ¶ added in v0.16.0
func SignConfig(configData []byte, privateKey ed25519.PrivateKey) ([]byte, error)
SignConfig signs the provided configuration data using Ed25519
func ValidateRepoAccess ¶ added in v0.5.0
func ValidateRepoAccess(repoURL string, securityCfg *SecurityConfig) error
ValidateRepoAccess validates that a repository URL is allowed by the security policy. Returns an error if the repository host is denied or not in the allow list.
func ValidateStrictPolicyMode ¶ added in v0.16.0
func ValidateStrictPolicyMode(securityCfg *SecurityConfig) error
ValidateStrictPolicyMode checks if security configuration is required and present
func ValidateTarget ¶ added in v0.1.0
ValidateTarget exposes target validation rules for external callers.
Types ¶
type ArgList ¶ added in v0.1.0
type ArgList []string
ArgList accepts either a single string or a list of strings in YAML. Examples:
args: "--silent" => ["--silent"] args: ["-v", "--color"] => ["-v","--color"]
type DigitalSignature ¶ added in v0.16.0
type DigitalSignature struct {
Algorithm string `yaml:"algorithm"` // "ed25519"
KeyID string `yaml:"keyId"` // Key identifier for lookup
Signature string `yaml:"signature"` // base64-encoded signature
}
DigitalSignature holds signature verification information
type DuckConf ¶
type DuckConf struct {
Version int `yaml:"version"`
// Default is the key of the target (in Targets) executed when the user omits a target.
Default string `yaml:"default"`
Remotes map[string]Remote `yaml:"remotes,omitempty"`
Targets map[string]Target `yaml:"targets"`
Settings *Settings `yaml:"settings,omitempty"`
}
type FilePermissionPolicy ¶ added in v0.16.0
type FilePermissionPolicy struct {
EnforceOwnership bool `yaml:"enforceOwnership"` // Require proper ownership (root for system files)
EnforceReadOnly bool `yaml:"enforceReadOnly"` // Require read-only permissions
AllowGroupWrite bool `yaml:"allowGroupWrite"` // Allow group write permissions
RequireSecureDirectories bool `yaml:"requireSecureDirectories"` // Parent dirs must be secure
}
FilePermissionPolicy defines file permission validation rules
type FilePermissionResult ¶ added in v0.16.0
type FilePermissionResult struct {
Path string
Type SecurityFileType
Valid bool
Issues []string
Owner string
Group string
Permissions os.FileMode
ParentDirSecure bool
ParentDirIssues []string
}
FilePermissionResult holds the result of file permission validation
func ValidateFilePermissions ¶ added in v0.16.0
func ValidateFilePermissions(configFile *SecurityConfigFile, policy *FilePermissionPolicy) (*FilePermissionResult, error)
ValidateFilePermissions validates security configuration file permissions according to policy
func ValidateSecurityConfigPermissions ¶ added in v0.16.0
func ValidateSecurityConfigPermissions(configs []*SecurityConfigFile, policy *FilePermissionPolicy) ([]*FilePermissionResult, error)
ValidateSecurityConfigPermissions validates all discovered security config files
type ParentDirectoryResult ¶ added in v0.16.0
ParentDirectoryResult holds validation results for parent directories
type PolicyEnforcement ¶ added in v0.16.0
type PolicyEnforcement struct {
ForceChecksumValidation bool `yaml:"forceChecksumValidation"` // Fail if template has no checksum
ForceCommitTracking bool `yaml:"forceCommitTracking"` // Fail if trackCommitHash=false
DisableAutoUpdate bool `yaml:"disableAutoUpdate"` // Override autoUpdateOnChange settings
StrictPolicyMode bool `yaml:"strictPolicyMode"` // Require security config to exist
EnforceFilePermissions bool `yaml:"enforceFilePermissions"` // Validate file permissions according to policy
}
PolicyEnforcement defines security policy enforcement rules
type PolicyEnforcementResult ¶ added in v0.16.0
type PolicyEnforcementResult struct {
Allowed bool
Violations []PolicyViolation
Warnings []PolicyViolation
}
PolicyEnforcementResult contains the results of policy enforcement checks
func EnforceSecurityPolicies ¶ added in v0.16.0
func EnforceSecurityPolicies(targetName string, target *Target, securityCfg *SecurityConfig) *PolicyEnforcementResult
EnforceSecurityPolicies validates a target against security policies Returns a result indicating if the target is allowed and any violations found
func NewPolicyEnforcementResult ¶ added in v0.16.0
func NewPolicyEnforcementResult() *PolicyEnforcementResult
NewPolicyEnforcementResult creates a new result with allowed=true by default
func (*PolicyEnforcementResult) AddViolation ¶ added in v0.16.0
func (r *PolicyEnforcementResult) AddViolation(violationType, message, targetName, suggestion string)
AddViolation adds a policy violation and sets Allowed=false
func (*PolicyEnforcementResult) AddWarning ¶ added in v0.16.0
func (r *PolicyEnforcementResult) AddWarning(violationType, message, targetName, suggestion string)
AddWarning adds a policy warning (doesn't affect Allowed status)
type PolicyViolation ¶ added in v0.16.0
type PolicyViolation struct {
Type string // "checksum", "commit_tracking", "auto_update", "template_validation"
Severity string // "error", "warning", "info"
Message string
TargetName string
Suggestion string // How to fix the violation
}
PolicyViolation represents a security policy violation
type Remote ¶ added in v0.22.0
type Remote struct {
Repo string `yaml:"repo"`
Ref string `yaml:"ref,omitempty"`
Submodules bool `yaml:"submodules,omitempty"`
TrackCommitHash bool `yaml:"trackCommitHash,omitempty"`
AutoUpdateOnChange bool `yaml:"autoUpdateOnChange,omitempty"`
}
Remote defines a shared remote repository configuration that can be referenced by multiple templates
type ResolvedTemplate ¶ added in v0.22.0
type ResolvedTemplate struct {
Repo string
Ref string
Path string
Submodules bool
TrackCommitHash bool
AutoUpdateOnChange bool
Checksum string
Delims *Delims
AllowMissing bool
}
ResolvedTemplate contains the fully resolved template configuration, combining remote settings with template-specific settings
func ResolveTemplateConfig ¶ added in v0.22.0
func ResolveTemplateConfig(template Template, remotes map[string]Remote, settings *Settings) (ResolvedTemplate, error)
ResolveTemplateConfig resolves a template configuration by merging remote settings with template-specific settings and global settings fallback
type SecurityConfig ¶ added in v0.5.0
type SecurityConfig struct {
// Existing host restriction fields
AllowedHosts []string `yaml:"allowedHosts,omitempty"`
DeniedHosts []string `yaml:"deniedHosts,omitempty"`
StrictMode bool `yaml:"strictMode,omitempty"` // Fail if no restrictions are configured
Source string `yaml:"source,omitempty"` // "signed", "env", "cli", "unsigned", "none" for audit trail
// NEW: Digital signature fields
Signature *DigitalSignature `yaml:"signature,omitempty"`
// NEW: Policy enforcement
Enforcement *PolicyEnforcement `yaml:"enforcement,omitempty"`
// NEW: File permission validation
FilePermissions *FilePermissionPolicy `yaml:"filePermissions,omitempty"`
// NEW: Metadata for audit trails
Metadata *SecurityMetadata `yaml:"metadata,omitempty"`
// NEW: Source tracking for precedence
SourceFile string `yaml:"sourceFile,omitempty"` // Path to config file if loaded from file
IsSigned bool `yaml:"isSigned,omitempty"` // Whether this config was verified with a valid signature
Version int `yaml:"version,omitempty"` // Configuration version
}
SecurityConfig holds comprehensive security configuration loaded from environment variables, CLI flags, or configuration files to prevent supply-chain attacks. BuildSecurityConfigWithPrecedence builds a security configuration using enhanced precedence system. Precedence order (highest to lowest): 1. 🔒 Signed Security Config Files (tamper-proof, highest) 2. ⚡ CLI flags (high precedence when no signed config) 3. 🌍 Environment variables (system-level control) 4. 📄 Unsigned Security Config Files (lower to prevent bypass) 5. 🔓 No restrictions (backward compatibility)rity settings are kept separate from duck.yaml to prevent attackers from modifying both targets and security policies in the same commit.
func BuildSecurityConfig ¶ added in v0.5.0
func BuildSecurityConfig(cliAllowed []string, cliDenied []string, cliStrict bool) *SecurityConfig
BuildSecurityConfig creates a security configuration with CLI flag precedence. CLI flags override environment variables. Only creates a CLI config when meaningful values are provided (non-empty slices or strict mode enabled).
func BuildSecurityConfigWithFiles ¶ added in v0.16.0
func BuildSecurityConfigWithFiles(cliAllowed []string, cliDenied []string, cliStrict bool) (*SecurityConfig, error)
BuildSecurityConfigWithFiles implements the original precedence system for backward compatibility Precedence order (highest to lowest): 1. Signed Security Config Files (tamper-proof, highest) 2. CLI flags (high precedence when no signed config) 3. Environment variables (system-level control) 4. Unsigned Security Config Files (lower to prevent bypass) 5. No restrictions (backward compatibility)
func BuildSecurityConfigWithPrecedence ¶ added in v0.16.0
func BuildSecurityConfigWithPrecedence(cliAllowed []string, cliDenied []string, cliStrict bool) (*SecurityConfig, error)
BuildSecurityConfigWithPrecedence implements the enhanced precedence system Precedence order (highest to lowest): 1. 🔒 Signed Security Config Files (tamper-proof, highest) 2. ⚡ CLI flags (high precedence when no signed config) 3. 🌍 Environment variables (system-level control) 4. 📄 Unsigned Security Config Files (lower to prevent bypass) 5. 🔓 No restrictions (backward compatibility)
func LoadSecurityConfigFromEnv ¶ added in v0.5.0
func LoadSecurityConfigFromEnv() *SecurityConfig
Environment variables used:
- DUCK_ALLOWED_HOSTS: comma-separated list of allowed hostnames
- DUCK_DENIED_HOSTS: comma-separated list of denied hostnames
- DUCK_STRICT_MODE: "true" to fail if no restrictions are configured
func LoadSecurityConfigFromFile ¶ added in v0.16.0
func LoadSecurityConfigFromFile(path string) (*SecurityConfig, error)
func MergeSecurityConfigs ¶ added in v0.16.0
func MergeSecurityConfigs(configs ...*SecurityConfig) *SecurityConfig
type SecurityConfigFile ¶ added in v0.16.0
type SecurityConfigFile struct {
Path string
Type SecurityFileType
Exists bool
Readable bool
HasSigFile bool // Whether a corresponding .sig file exists
}
SecurityConfigFile represents a discovered security configuration file
func DiscoverSecurityConfigs ¶ added in v0.16.0
func DiscoverSecurityConfigs() ([]*SecurityConfigFile, error)
DiscoverSecurityConfigs discovers security configuration files in the standard hierarchy. Returns files in precedence order (highest to lowest): 1. System-wide: /etc/duckfile/security.{yaml,yml} 2. User-specific: ~/.duckfile/security.{yaml,yml}, ~/.config/duckfile/security.{yaml,yml} 3. Project-specific: ./.duckfile/security.yaml
func DiscoverSecurityConfigsInDir ¶ added in v0.16.0
func DiscoverSecurityConfigsInDir(baseDir string) ([]*SecurityConfigFile, error)
DiscoverSecurityConfigsInDir discovers security configuration files relative to a specific directory. This is primarily for testing purposes.
type SecurityConfigPrecedenceInfo ¶ added in v0.16.0
type SecurityConfigPrecedenceInfo struct {
Sources map[string]*SecurityConfig
EffectiveConfig *SecurityConfig
EffectiveSource string
} // LoadSecurityConfigFromEnv loads security configuration from environment variables.
SecurityConfigPrecedenceInfo provides detailed information about configuration precedence
func GetSecurityConfigPrecedenceInfo ¶ added in v0.16.0
func GetSecurityConfigPrecedenceInfo(cliAllowed []string, cliDenied []string, cliStrict bool) (*SecurityConfigPrecedenceInfo, error)
GetSecurityConfigPrecedenceInfo retrieves security configuration precedence information combining CLI arguments, environment variables, and file-based configurations
type SecurityFileType ¶ added in v0.16.0
type SecurityFileType int
SecurityFileType indicates the type and precedence of a security config file
const ( SecurityFileTypeSystem SecurityFileType = iota // /etc/duckfile/security.yaml SecurityFileTypeUser // ~/.duckfile/security.yaml, ~/.config/duckfile/security.yaml SecurityFileTypeProject // ./.duckfile/security.yaml )
func DetermineSecurityFileType ¶ added in v0.16.0
func DetermineSecurityFileType(filePath string) SecurityFileType
DetermineSecurityFileType determines the security file type based on path
type SecurityMetadata ¶ added in v0.16.0
type SecurityMetadata struct {
CreatedBy string `yaml:"createdBy"`
CreatedAt time.Time `yaml:"createdAt"`
Purpose string `yaml:"purpose"`
Version int `yaml:"version,omitempty"`
}
SecurityMetadata holds audit trail information
type Settings ¶ added in v0.6.0
type Settings struct {
CacheDir string `yaml:"cacheDir,omitempty"`
LogLevel string `yaml:"logLevel,omitempty"`
Locked bool `yaml:"locked,omitempty"`
TrackCommitHash bool `yaml:"trackCommitHash,omitempty"`
AutoUpdateOnChange bool `yaml:"autoUpdateOnChange,omitempty"`
}
Settings represents the global configuration options
func (*Settings) GetAutoUpdateOnChange ¶ added in v0.7.0
GetAutoUpdateOnChange returns whether auto-update on commit hash change is enabled globally
func (*Settings) GetCacheDir ¶ added in v0.6.0
GetCacheDir returns the configured cache dir or default ".duck/objects"
func (*Settings) GetLogLevel ¶ added in v0.6.0
GetLogLevel returns the configured log level or default "info"
func (*Settings) GetTrackCommitHash ¶ added in v0.7.0
GetTrackCommitHash returns whether commit hash tracking is enabled globally
type SignatureKeyPair ¶ added in v0.16.0
type SignatureKeyPair struct {
PublicKey ed25519.PublicKey
PrivateKey ed25519.PrivateKey
KeyID string
}
SignatureKeyPair represents an Ed25519 key pair
func GenerateKeyPair ¶ added in v0.16.0
func GenerateKeyPair() (*SignatureKeyPair, error)
GenerateKeyPair generates a new Ed25519 key pair for signing security configurations
type Target ¶
type Target struct {
// Description is an optional human readable explanation printed by `duck list`.
Description string `yaml:"description,omitempty"`
Binary string `yaml:"binary,omitempty"`
FileFlag string `yaml:"fileFlag,omitempty"`
Template Template `yaml:"template"`
Variables map[string]VarValue `yaml:"variables,omitempty"`
RenderedPath string `yaml:"renderedPath,omitempty"`
CopyRendered bool `yaml:"copyRendered,omitempty"` // If true, copy instead of symlink. RenderedPath required.
Args ArgList `yaml:"args,omitempty"`
}
func ApplyPolicyOverrides ¶ added in v0.16.0
func ApplyPolicyOverrides(target *Target, securityCfg *SecurityConfig) *Target
ApplyPolicyOverrides modifies target configuration based on security policies This function applies mandatory overrides that cannot be bypassed
type Template ¶
type Template struct {
// Remote reference (new approach)
Remote string `yaml:"remote,omitempty"`
// Inline configuration (existing approach - mutually exclusive with Remote)
Repo string `yaml:"repo,omitempty"`
Ref string `yaml:"ref,omitempty"`
Path string `yaml:"path"`
Checksum string `yaml:"checksum,omitempty"`
// Optional delimiter override to avoid conflicts with downstream tools (e.g., Taskfile).
Delims *Delims `yaml:"delims,omitempty"`
// If true, missing keys render as empty strings (zero values). Default: strict error.
AllowMissing bool `yaml:"allowMissing,omitempty"`
// If true, enables commit hash storage and validation. Default: false.
TrackCommitHash bool `yaml:"trackCommitHash,omitempty"`
// If true, auto-update if commit hash changes; otherwise warn and stop. Default: false.
AutoUpdateOnChange bool `yaml:"autoUpdateOnChange,omitempty"`
// If true, fetch submodules with --recurse-submodules. Default: false.
Submodules bool `yaml:"submodules,omitempty"`
}
type VarValue ¶
type VarValue struct {
Kind VarKind
Arg string // tag argument (env name, command, or file path)
Value any // for literal
}
VarValue supports tagged scalars like !env, !cmd, !file as well as plain scalars. It implements yaml.Unmarshaler to capture custom tags.
func (VarValue) MarshalYAML ¶ added in v0.1.0
MarshalYAML enables preserving custom tags when writing config files.