access-engine/internal/adapters/topaz/policy_bundle.go
tegwick f758381cea
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 6s
Build and Publish Container Image / build-and-push (push) Successful in 1m23s
FLEX-WP-0036: Go module is github.com/netkingdom/access-engine; T02 consumer inventory
- module path renamed (no external importers); golangci local-prefixes
- ACCESS_ENGINE_RUN_TOPAZ_INTEGRATION replaces FLEX_AUTH_RUN_TOPAZ_INTEGRATION
- README title and identity paragraph reflect the landed renames
- docs/runtime-rename-inventory.md: per-consumer references by kind and order
- chart name, image package and /opt paths deliberately left for T05

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 735967@bnt-lap001
Assistant-Session: 5971967f-77f8-4ced-9e02-c6ef67040ffc
2026-10-10 15:29:00 +02:00

80 lines
2.4 KiB
Go

package topaz
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/netkingdom/access-engine/internal/policy"
)
// PolicyBundleFromPackage extracts the Rego module from a flex-auth
// Rego-in-Markdown package without translation.
func PolicyBundleFromPackage(pkg *policy.Package) PolicyBundle {
root := strings.ReplaceAll(pkg.Metadata.Package, ".", "/")
modulePath := filepath.ToSlash(filepath.Join("policy", root+".rego"))
return PolicyBundle{
ID: pkg.Metadata.ID,
Version: pkg.Metadata.Version,
Package: pkg.Metadata.Package,
Revision: pkg.Metadata.Version,
Roots: []string{root},
Modules: []PolicyModule{
{Path: modulePath, Source: pkg.RegoModule},
},
}
}
// FileBundleSink writes a Topaz-readable local OPA bundle directory.
type FileBundleSink struct {
Root string
}
// PutPolicyBundle writes .manifest and module files under Root.
func (s FileBundleSink) PutPolicyBundle(_ context.Context, bundle PolicyBundle) error {
if s.Root == "" {
return fmt.Errorf("bundle root is required")
}
if len(bundle.Modules) == 0 {
return fmt.Errorf("policy bundle %q contains no modules", bundle.ID)
}
if err := os.MkdirAll(s.Root, 0o755); err != nil {
return fmt.Errorf("create policy bundle root: %w", err)
}
manifest := struct {
Revision string `json:"revision,omitempty"`
Roots []string `json:"roots"`
}{
Revision: bundle.Revision,
Roots: append([]string(nil), bundle.Roots...),
}
manifestData, err := json.Marshal(manifest)
if err != nil {
return fmt.Errorf("marshal policy bundle manifest: %w", err)
}
manifestData = append(manifestData, '\n')
if err := os.WriteFile(filepath.Join(s.Root, ".manifest"), manifestData, 0o644); err != nil {
return fmt.Errorf("write policy bundle manifest: %w", err)
}
for _, module := range bundle.Modules {
if module.Path == "" {
return fmt.Errorf("policy bundle %q contains module with empty path", bundle.ID)
}
path := filepath.Clean(filepath.Join(s.Root, module.Path))
if !strings.HasPrefix(path, filepath.Clean(s.Root)+string(os.PathSeparator)) {
return fmt.Errorf("policy module path escapes bundle root: %s", module.Path)
}
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return fmt.Errorf("create policy module directory: %w", err)
}
if err := os.WriteFile(path, []byte(module.Source), 0o644); err != nil {
return fmt.Errorf("write policy module %q: %w", module.Path, err)
}
}
return nil
}