DEV-000061 checkpoint interaction chat foundation
CI / test (push) Failing after 10s
CI / test (pull_request) Failing after 11s

This commit is contained in:
m
2026-08-17 14:10:04 +03:00
parent e4b6121dc0
commit 41154be211
26 changed files with 1376 additions and 8 deletions
+65
View File
@@ -0,0 +1,65 @@
package secrets
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
secretcontracts "git.cin.su/m/Assistant/contracts/secrets"
)
var (
ErrEmptyCredentialRef = errors.New("empty credential ref")
ErrPathOutsideRoot = errors.New("secret path outside protected root")
ErrEmptySecret = errors.New("empty secret")
)
// FileResolver resolves CredentialRef metadata against a protected local file
// backend. It is a bootstrap mechanism, not canonical configuration storage.
type FileResolver struct {
root string
}
func NewFileResolver(root string) (*FileResolver, error) {
root = strings.TrimSpace(root)
if root == "" {
return nil, fmt.Errorf("secret backend root: %w", ErrPathOutsideRoot)
}
cleanRoot, err := filepath.Abs(filepath.Clean(root))
if err != nil {
return nil, fmt.Errorf("secret backend root: %w", err)
}
return &FileResolver{root: cleanRoot}, nil
}
func (r *FileResolver) ResolveFile(ref secretcontracts.SecretFileRef) (string, error) {
if strings.TrimSpace(string(ref.CredentialRef)) == "" {
return "", ErrEmptyCredentialRef
}
cleanPath, err := filepath.Abs(filepath.Clean(strings.TrimSpace(ref.Path)))
if err != nil {
return "", err
}
if !insideRoot(r.root, cleanPath) {
return "", ErrPathOutsideRoot
}
content, err := os.ReadFile(cleanPath)
if err != nil {
return "", err
}
secret := strings.TrimSpace(string(content))
if secret == "" {
return "", ErrEmptySecret
}
return secret, nil
}
func insideRoot(root, path string) bool {
rel, err := filepath.Rel(root, path)
if err != nil {
return false
}
return rel == "." || (!strings.HasPrefix(rel, "..") && !filepath.IsAbs(rel))
}
+78
View File
@@ -0,0 +1,78 @@
package secrets
import (
"errors"
"os"
"path/filepath"
"testing"
secretcontracts "git.cin.su/m/Assistant/contracts/secrets"
)
func TestFileResolverResolvesSecretInsideRoot(t *testing.T) {
root := t.TempDir()
path := filepath.Join(root, "interaction_db_password")
if err := os.WriteFile(path, []byte("strong-secret\n"), 0o600); err != nil {
t.Fatal(err)
}
resolver, err := NewFileResolver(root)
if err != nil {
t.Fatal(err)
}
got, err := resolver.ResolveFile(secretcontracts.SecretFileRef{
CredentialRef: "credential://domovoy/interaction/db-password/v1",
Purpose: secretcontracts.SecretPurposeDatabasePassword,
Consumer: secretcontracts.RuntimeConsumerCore,
Path: path,
})
if err != nil {
t.Fatal(err)
}
if got != "strong-secret" {
t.Fatalf("unexpected secret value")
}
}
func TestFileResolverRejectsPathOutsideRoot(t *testing.T) {
root := t.TempDir()
outside := filepath.Join(t.TempDir(), "secret")
if err := os.WriteFile(outside, []byte("secret"), 0o600); err != nil {
t.Fatal(err)
}
resolver, err := NewFileResolver(root)
if err != nil {
t.Fatal(err)
}
_, err = resolver.ResolveFile(secretcontracts.SecretFileRef{
CredentialRef: "credential://domovoy/interaction/db-password/v1",
Purpose: secretcontracts.SecretPurposeDatabasePassword,
Consumer: secretcontracts.RuntimeConsumerCore,
Path: outside,
})
if !errors.Is(err, ErrPathOutsideRoot) {
t.Fatalf("expected ErrPathOutsideRoot, got %v", err)
}
}
func TestFileResolverRejectsEmptyCredentialRef(t *testing.T) {
root := t.TempDir()
path := filepath.Join(root, "secret")
if err := os.WriteFile(path, []byte("secret"), 0o600); err != nil {
t.Fatal(err)
}
resolver, err := NewFileResolver(root)
if err != nil {
t.Fatal(err)
}
_, err = resolver.ResolveFile(secretcontracts.SecretFileRef{
Purpose: secretcontracts.SecretPurposeDatabasePassword,
Consumer: secretcontracts.RuntimeConsumerCore,
Path: path,
})
if !errors.Is(err, ErrEmptyCredentialRef) {
t.Fatalf("expected ErrEmptyCredentialRef, got %v", err)
}
}