Files
dingtalk-workspace-cli/pkg/configmeta/registry.go
T
修雨 4a717bd92f feat(audit): implement user operation audit log
- Add internal/audit package: Event struct, FileSink, date rotation, L1 hash chain, HTTP forwarding, 3-tier redaction
- Integrate with runner: emit audit event in executeInvocation defer
- Add dws audit tail/export/verify command group
- Register DWS_AUDIT* env vars in configmeta, enabled by default
2026-07-06 11:55:40 +08:00

158 lines
4.2 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package configmeta provides a central registry of all environment-variable
// based configuration items used by the DWS CLI. Each package registers its
// own items via init(), and the "dws config list" command reads the registry
// to present a unified view to the developer.
package configmeta
import (
"os"
"sort"
"strings"
"sync"
)
// Category groups related configuration items for display purposes.
type Category string
const (
CategoryCore Category = "core"
CategoryAuth Category = "auth"
CategoryNetwork Category = "network"
CategorySecurity Category = "security"
CategoryAudit Category = "audit"
CategoryRuntime Category = "runtime"
CategoryDebug Category = "debug"
CategoryExternal Category = "external"
)
// categoryOrder defines the display order for categories.
var categoryOrder = map[Category]int{
CategoryCore: 0,
CategoryAuth: 1,
CategoryNetwork: 2,
CategorySecurity: 3,
CategoryAudit: 4,
CategoryRuntime: 5,
CategoryDebug: 6,
CategoryExternal: 7,
}
// ConfigItem describes a single environment-variable configuration item.
type ConfigItem struct {
Name string // Environment variable name, e.g. "DWS_CONFIG_DIR"
Category Category // Logical grouping
Description string // Short human-readable description
DefaultValue string // Description of the default value
Example string // Example value for documentation
Sensitive bool // If true, actual value is masked in output
Hidden bool // If true, omitted from default list output
}
var (
mu sync.RWMutex
items []ConfigItem
)
// Register adds a configuration item to the global registry.
// Duplicate names are silently ignored (first registration wins).
func Register(item ConfigItem) {
mu.Lock()
defer mu.Unlock()
for _, existing := range items {
if existing.Name == item.Name {
return
}
}
items = append(items, item)
}
// All returns every registered configuration item sorted by category
// (display order) then by name.
func All() []ConfigItem {
mu.RLock()
defer mu.RUnlock()
out := make([]ConfigItem, len(items))
copy(out, items)
sort.Slice(out, func(i, j int) bool {
ci, cj := categoryOrder[out[i].Category], categoryOrder[out[j].Category]
if ci != cj {
return ci < cj
}
return out[i].Name < out[j].Name
})
return out
}
// ByCategory returns registered items that match the given category.
func ByCategory(cat Category) []ConfigItem {
all := All()
var out []ConfigItem
for _, item := range all {
if item.Category == cat {
out = append(out, item)
}
}
return out
}
// Resolve returns the current value of the named environment variable.
// For sensitive items the value is masked. Returns ("", false) when the
// variable is not set.
func Resolve(name string) (string, bool) {
val, ok := os.LookupEnv(name)
if !ok {
return "", false
}
mu.RLock()
defer mu.RUnlock()
for _, item := range items {
if item.Name == name && item.Sensitive {
return maskValue(val), true
}
}
return val, true
}
// Categories returns all known category values in display order.
func Categories() []Category {
cats := make([]Category, 0, len(categoryOrder))
for c := range categoryOrder {
cats = append(cats, c)
}
sort.Slice(cats, func(i, j int) bool {
return categoryOrder[cats[i]] < categoryOrder[cats[j]]
})
return cats
}
func maskValue(v string) string {
if len(v) == 0 {
return ""
}
if len(v) <= 4 {
return strings.Repeat("*", len(v))
}
return v[:2] + strings.Repeat("*", len(v)-4) + v[len(v)-2:]
}
// Reset clears the registry. Intended for testing only.
func Reset() {
mu.Lock()
defer mu.Unlock()
items = nil
}