mirror of
https://github.com/lukaszraczylo/harness-sync.git
synced 2026-10-15 01:07:27 +00:00
feat(adapter): define Adapter interface and FileSet
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
// Package secrets provides ${VAR} substitution for canonical configs.
|
||||
package secrets
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Lookup resolves a placeholder name to a value. Returns false if missing.
|
||||
type Lookup func(name string) (string, bool)
|
||||
|
||||
// OSEnv resolves via os.LookupEnv.
|
||||
func OSEnv(name string) (string, bool) {
|
||||
return os.LookupEnv(name)
|
||||
}
|
||||
|
||||
// Substitute replaces ${NAME} placeholders in s using lookup. Escape with $$.
|
||||
// Missing keys produce an error so secrets are never silently empty.
|
||||
func Substitute(s string, lookup Lookup) (string, error) {
|
||||
var b strings.Builder
|
||||
i := 0
|
||||
for i < len(s) {
|
||||
if i+1 < len(s) && s[i] == '$' && s[i+1] == '$' {
|
||||
b.WriteByte('$')
|
||||
i += 2
|
||||
continue
|
||||
}
|
||||
if i+1 < len(s) && s[i] == '$' && s[i+1] == '{' {
|
||||
end := strings.IndexByte(s[i+2:], '}')
|
||||
if end == -1 {
|
||||
return "", fmt.Errorf("unterminated placeholder at offset %d", i)
|
||||
}
|
||||
name := s[i+2 : i+2+end]
|
||||
val, ok := lookup(name)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("missing env var %q", name)
|
||||
}
|
||||
b.WriteString(val)
|
||||
i += 2 + end + 1
|
||||
continue
|
||||
}
|
||||
b.WriteByte(s[i])
|
||||
i++
|
||||
}
|
||||
return b.String(), nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package secrets
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSubstituteSimple(t *testing.T) {
|
||||
lookup := func(k string) (string, bool) {
|
||||
if k == "FOO" {
|
||||
return "bar", true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
out, err := Substitute("hello ${FOO}", lookup)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "hello bar", out)
|
||||
}
|
||||
|
||||
func TestSubstituteMissingStrict(t *testing.T) {
|
||||
lookup := func(k string) (string, bool) { return "", false }
|
||||
_, err := Substitute("${MISSING}", lookup)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestSubstituteEscaped(t *testing.T) {
|
||||
lookup := func(k string) (string, bool) { return "should-not-see", true }
|
||||
out, err := Substitute("$${LITERAL}", lookup)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "${LITERAL}", out)
|
||||
}
|
||||
Reference in New Issue
Block a user