diff --git a/auth/session_store.go b/auth/session_store.go index 12811bb..bf90996 100644 --- a/auth/session_store.go +++ b/auth/session_store.go @@ -1,14 +1,15 @@ package auth import ( - "errors" "maps" "sync" "time" + + coreerr "forge.lthn.ai/core/go-log" ) // ErrSessionNotFound is returned when a session token is not found. -var ErrSessionNotFound = errors.New("auth: session not found") +var ErrSessionNotFound = coreerr.E("auth", "session not found", nil) // SessionStore abstracts session persistence. type SessionStore interface { diff --git a/cmd/crypt/cmd_encrypt.go b/cmd/crypt/cmd_encrypt.go index 95e1dbc..6f3693e 100644 --- a/cmd/crypt/cmd_encrypt.go +++ b/cmd/crypt/cmd_encrypt.go @@ -2,11 +2,11 @@ package crypt import ( "fmt" - "os" "strings" "forge.lthn.ai/core/cli/pkg/cli" "forge.lthn.ai/core/go-crypt/crypt" + coreio "forge.lthn.ai/core/go-io" ) // Encrypt command flags @@ -53,10 +53,11 @@ func runEncrypt(path string) error { return cli.Err("passphrase cannot be empty") } - data, err := os.ReadFile(path) + raw, err := coreio.Local.Read(path) if err != nil { return cli.Wrap(err, "failed to read file") } + data := []byte(raw) var encrypted []byte if encryptAES { @@ -69,7 +70,7 @@ func runEncrypt(path string) error { } outPath := path + ".enc" - if err := os.WriteFile(outPath, encrypted, 0o600); err != nil { + if err := coreio.Local.Write(outPath, string(encrypted)); err != nil { return cli.Wrap(err, "failed to write encrypted file") } @@ -86,10 +87,11 @@ func runDecrypt(path string) error { return cli.Err("passphrase cannot be empty") } - data, err := os.ReadFile(path) + raw, err := coreio.Local.Read(path) if err != nil { return cli.Wrap(err, "failed to read file") } + data := []byte(raw) var decrypted []byte if encryptAES { @@ -106,7 +108,7 @@ func runDecrypt(path string) error { outPath = path + ".dec" } - if err := os.WriteFile(outPath, decrypted, 0o600); err != nil { + if err := coreio.Local.Write(outPath, string(decrypted)); err != nil { return cli.Wrap(err, "failed to write decrypted file") } diff --git a/cmd/testcmd/cmd_runner.go b/cmd/testcmd/cmd_runner.go index 3365491..8224f60 100644 --- a/cmd/testcmd/cmd_runner.go +++ b/cmd/testcmd/cmd_runner.go @@ -2,7 +2,6 @@ package testcmd import ( "bufio" - "errors" "fmt" "io" "os" @@ -11,12 +10,13 @@ import ( "strings" "forge.lthn.ai/core/go-i18n" + coreerr "forge.lthn.ai/core/go-log" ) func runTest(verbose, coverage, short bool, pkg, run string, race, jsonOutput bool) error { // Detect if we're in a Go project if _, err := os.Stat("go.mod"); os.IsNotExist(err) { - return errors.New(i18n.T("cmd.test.error.no_go_mod")) + return coreerr.E("cmd.test", i18n.T("cmd.test.error.no_go_mod"), nil) } // Build command arguments @@ -94,7 +94,7 @@ func runTest(verbose, coverage, short bool, pkg, run string, race, jsonOutput bo // JSON output for CI/agents printJSONResults(results, exitCode) if exitCode != 0 { - return errors.New(i18n.T("i18n.fail.run", "tests")) + return coreerr.E("cmd.test", i18n.T("i18n.fail.run", "tests"), nil) } return nil } @@ -110,7 +110,7 @@ func runTest(verbose, coverage, short bool, pkg, run string, race, jsonOutput bo if exitCode != 0 { fmt.Printf("\n%s %s\n", testFailStyle.Render(i18n.T("cli.fail")), i18n.T("cmd.test.tests_failed")) - return errors.New(i18n.T("i18n.fail.run", "tests")) + return coreerr.E("cmd.test", i18n.T("i18n.fail.run", "tests"), nil) } fmt.Printf("\n%s %s\n", testPassStyle.Render(i18n.T("cli.pass")), i18n.T("common.result.all_passed")) diff --git a/trust/approval.go b/trust/approval.go index a6aafca..8e9a5d1 100644 --- a/trust/approval.go +++ b/trust/approval.go @@ -1,11 +1,12 @@ package trust import ( - "errors" "fmt" "iter" "sync" "time" + + coreerr "forge.lthn.ai/core/go-log" ) // ApprovalStatus represents the state of an approval request. @@ -74,10 +75,10 @@ func NewApprovalQueue() *ApprovalQueue { // Returns an error if the agent name or capability is empty. func (q *ApprovalQueue) Submit(agent string, cap Capability, repo string) (string, error) { if agent == "" { - return "", errors.New("trust.ApprovalQueue.Submit: agent name is required") + return "", coreerr.E("trust.ApprovalQueue.Submit", "agent name is required", nil) } if cap == "" { - return "", errors.New("trust.ApprovalQueue.Submit: capability is required") + return "", coreerr.E("trust.ApprovalQueue.Submit", "capability is required", nil) } q.mu.Lock() @@ -106,10 +107,10 @@ func (q *ApprovalQueue) Approve(id string, reviewedBy string, reason string) err req, ok := q.requests[id] if !ok { - return fmt.Errorf("trust.ApprovalQueue.Approve: request %q not found", id) + return coreerr.E("trust.ApprovalQueue.Approve", fmt.Sprintf("request %q not found", id), nil) } if req.Status != ApprovalPending { - return fmt.Errorf("trust.ApprovalQueue.Approve: request %q is already %s", id, req.Status) + return coreerr.E("trust.ApprovalQueue.Approve", fmt.Sprintf("request %q is already %s", id, req.Status), nil) } req.Status = ApprovalApproved @@ -127,10 +128,10 @@ func (q *ApprovalQueue) Deny(id string, reviewedBy string, reason string) error req, ok := q.requests[id] if !ok { - return fmt.Errorf("trust.ApprovalQueue.Deny: request %q not found", id) + return coreerr.E("trust.ApprovalQueue.Deny", fmt.Sprintf("request %q not found", id), nil) } if req.Status != ApprovalPending { - return fmt.Errorf("trust.ApprovalQueue.Deny: request %q is already %s", id, req.Status) + return coreerr.E("trust.ApprovalQueue.Deny", fmt.Sprintf("request %q is already %s", id, req.Status), nil) } req.Status = ApprovalDenied diff --git a/trust/audit.go b/trust/audit.go index 5b371f4..25ae84a 100644 --- a/trust/audit.go +++ b/trust/audit.go @@ -2,11 +2,12 @@ package trust import ( "encoding/json" - "fmt" "io" "iter" "sync" "time" + + coreerr "forge.lthn.ai/core/go-log" ) // AuditEntry records a single policy evaluation for compliance. @@ -44,7 +45,7 @@ func (d *Decision) UnmarshalJSON(data []byte) error { case "needs_approval": *d = NeedsApproval default: - return fmt.Errorf("trust: unknown decision %q", s) + return coreerr.E("trust.Decision.UnmarshalJSON", "unknown decision: "+s, nil) } return nil } @@ -83,11 +84,11 @@ func (l *AuditLog) Record(result EvalResult, repo string) error { if l.writer != nil { data, err := json.Marshal(entry) if err != nil { - return fmt.Errorf("trust.AuditLog.Record: marshal failed: %w", err) + return coreerr.E("trust.AuditLog.Record", "marshal failed", err) } data = append(data, '\n') if _, err := l.writer.Write(data); err != nil { - return fmt.Errorf("trust.AuditLog.Record: write failed: %w", err) + return coreerr.E("trust.AuditLog.Record", "write failed", err) } } diff --git a/trust/config.go b/trust/config.go index 5b9ad33..fd198dd 100644 --- a/trust/config.go +++ b/trust/config.go @@ -5,6 +5,8 @@ import ( "fmt" "io" "os" + + coreerr "forge.lthn.ai/core/go-log" ) // PolicyConfig is the JSON-serialisable representation of a trust policy. @@ -24,7 +26,7 @@ type PoliciesConfig struct { func LoadPoliciesFromFile(path string) ([]Policy, error) { f, err := os.Open(path) if err != nil { - return nil, fmt.Errorf("trust.LoadPoliciesFromFile: %w", err) + return nil, coreerr.E("trust.LoadPoliciesFromFile", "failed to open file", err) } defer f.Close() return LoadPolicies(f) @@ -36,7 +38,7 @@ func LoadPolicies(r io.Reader) ([]Policy, error) { dec := json.NewDecoder(r) dec.DisallowUnknownFields() if err := dec.Decode(&cfg); err != nil { - return nil, fmt.Errorf("trust.LoadPolicies: %w", err) + return nil, coreerr.E("trust.LoadPolicies", "failed to decode JSON", err) } return convertPolicies(cfg) } @@ -48,7 +50,7 @@ func convertPolicies(cfg PoliciesConfig) ([]Policy, error) { for i, pc := range cfg.Policies { tier := Tier(pc.Tier) if !tier.Valid() { - return nil, fmt.Errorf("trust.LoadPolicies: invalid tier %d at index %d", pc.Tier, i) + return nil, coreerr.E("trust.LoadPolicies", fmt.Sprintf("invalid tier %d at index %d", pc.Tier, i), nil) } p := Policy{ @@ -72,7 +74,7 @@ func (pe *PolicyEngine) ApplyPolicies(r io.Reader) error { } for _, p := range policies { if err := pe.SetPolicy(p); err != nil { - return fmt.Errorf("trust.ApplyPolicies: %w", err) + return coreerr.E("trust.ApplyPolicies", "failed to set policy", err) } } return nil @@ -82,7 +84,7 @@ func (pe *PolicyEngine) ApplyPolicies(r io.Reader) error { func (pe *PolicyEngine) ApplyPoliciesFromFile(path string) error { f, err := os.Open(path) if err != nil { - return fmt.Errorf("trust.ApplyPoliciesFromFile: %w", err) + return coreerr.E("trust.ApplyPoliciesFromFile", "failed to open file", err) } defer f.Close() return pe.ApplyPolicies(f) @@ -107,7 +109,7 @@ func (pe *PolicyEngine) ExportPolicies(w io.Writer) error { enc := json.NewEncoder(w) enc.SetIndent("", " ") if err := enc.Encode(cfg); err != nil { - return fmt.Errorf("trust.ExportPolicies: %w", err) + return coreerr.E("trust.ExportPolicies", "failed to encode JSON", err) } return nil } diff --git a/trust/policy.go b/trust/policy.go index 0b1f1b8..368a1c1 100644 --- a/trust/policy.go +++ b/trust/policy.go @@ -4,6 +4,8 @@ import ( "fmt" "slices" "strings" + + coreerr "forge.lthn.ai/core/go-log" ) // Policy defines the access rules for a given trust tier. @@ -146,7 +148,7 @@ func (pe *PolicyEngine) Evaluate(agentName string, cap Capability, repo string) // SetPolicy replaces the policy for a given tier. func (pe *PolicyEngine) SetPolicy(p Policy) error { if !p.Tier.Valid() { - return fmt.Errorf("trust.SetPolicy: invalid tier %d", p.Tier) + return coreerr.E("trust.SetPolicy", fmt.Sprintf("invalid tier %d", p.Tier), nil) } pe.policies[p.Tier] = &p return nil