config

package
v0.23.0 Latest Latest
Warning

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

Go to latest
Published: Sep 29, 2025 License: GPL-2.0 Imports: 17 Imported by: 0

Documentation

Index

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

func IsReservedTargetName(name string) bool

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

func LoadEnvFile(path string) (int, error)

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

func LoadEnvFileIfExists(logFunc func(string, ...any)) error

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

func LoadPublicKey(keyID string) (ed25519.PublicKey, error)

LoadPublicKey loads a public key by key ID using the key discovery mechanism

func LoadSignatureFromFile added in v0.16.0

func LoadSignatureFromFile(filePath string) ([]byte, error)

LoadSignatureFromFile loads a signature from a file

func ResolveAutoUpdateOnChange added in v0.7.0

func ResolveAutoUpdateOnChange(cliFlag *bool, template *Template, cfg *DuckConf) bool

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

func ResolveLogLevel(cliLogLevel string, cfg *DuckConf) string

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

func ResolveTrackCommitHash(cliFlag *bool, template *Template, cfg *DuckConf) bool

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

func SaveSignatureToFile(signature []byte, filePath string) error

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

func ValidateTarget(t Target, name string) error

ValidateTarget exposes target validation rules for external callers.

func VerifySignature added in v0.16.0

func VerifySignature(configData, signature []byte, publicKey ed25519.PublicKey) error

VerifySignature verifies a signature against the provided data and public key

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"]

func (*ArgList) UnmarshalYAML added in v0.1.0

func (a *ArgList) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML enables custom decoding for ArgList.

type Delims

type Delims struct {
	Left  string `yaml:"left"`
	Right string `yaml:"right"`
}

Delims lets a template override the default Go template delimiters.

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"`
}

func Load

func Load(path string) (*DuckConf, error)

Load reads the configuration from disk as YAML.

func (*DuckConf) Save added in v0.1.0

func (c *DuckConf) Save(path string) error

Save writes the configuration to disk as YAML.

func (*DuckConf) Validate added in v0.1.0

func (c *DuckConf) Validate() error

Validate enforces cross-field rules: - binary is optional - fileFlag and args are only allowed when binary is set

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

type ParentDirectoryResult struct {
	Secure bool
	Issues []string
}

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

func (s *Settings) GetAutoUpdateOnChange() bool

GetAutoUpdateOnChange returns whether auto-update on commit hash change is enabled globally

func (*Settings) GetCacheDir added in v0.6.0

func (s *Settings) GetCacheDir() string

GetCacheDir returns the configured cache dir or default ".duck/objects"

func (*Settings) GetLogLevel added in v0.6.0

func (s *Settings) GetLogLevel() string

GetLogLevel returns the configured log level or default "info"

func (*Settings) GetTrackCommitHash added in v0.7.0

func (s *Settings) GetTrackCommitHash() bool

GetTrackCommitHash returns whether commit hash tracking is enabled globally

func (*Settings) IsLocked added in v0.6.0

func (s *Settings) IsLocked() bool

IsLocked returns whether locked mode is enabled

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 VarKind

type VarKind int

VarKind represents the origin/behavior of a variable value.

const (
	VarLiteral VarKind = iota // plain scalar (string/number/bool)
	VarEnv                    // !env NAME
	VarCmd                    // !cmd 'sh expression'
	VarFile                   // !file path
)

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 NewCmdVar added in v0.1.0

func NewCmdVar(cmd string) VarValue

NewCmdVar helper.

func NewEnvVar added in v0.1.0

func NewEnvVar(name string) VarValue

NewEnvVar helper.

func NewFileVar added in v0.1.0

func NewFileVar(path string) VarValue

NewFileVar helper.

func NewLiteralVar added in v0.1.0

func NewLiteralVar(val any) VarValue

NewLiteralVar helper.

func (VarValue) MarshalYAML added in v0.1.0

func (v VarValue) MarshalYAML() (any, error)

MarshalYAML enables preserving custom tags when writing config files.

func (*VarValue) UnmarshalYAML

func (v *VarValue) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML enables custom tag decoding for VarValue.

Jump to

Keyboard shortcuts

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