fix(apply): never substitute env vars - leave ${VAR} for harnesses to resolve

This commit is contained in:
2026-05-23 12:24:26 +01:00
parent d5b0de12cb
commit 0677223ff6
+7 -6
View File
@@ -12,7 +12,6 @@ import (
"github.com/lukaszraczylo/harness-sync/internal/canonical" "github.com/lukaszraczylo/harness-sync/internal/canonical"
"github.com/lukaszraczylo/harness-sync/internal/gitx" "github.com/lukaszraczylo/harness-sync/internal/gitx"
"github.com/lukaszraczylo/harness-sync/internal/merge" "github.com/lukaszraczylo/harness-sync/internal/merge"
"github.com/lukaszraczylo/harness-sync/internal/secrets"
) )
// Options configures a Run call. // Options configures a Run call.
@@ -42,12 +41,14 @@ type Action struct {
// Run renders all adapters and writes their FileSets to disk. // Run renders all adapters and writes their FileSets to disk.
// Conflicts are recorded as <dest>.rej files; processing continues past conflicts. // Conflicts are recorded as <dest>.rej files; processing continues past conflicts.
// Run renders all adapters and writes their FileSets to disk. //
// Conflicts are recorded as <dest>.rej files; processing continues past conflicts. // IMPORTANT: harness-sync intentionally does NOT resolve ${VAR} references in
// canonical configs. Every supported harness performs its own env-var
// expansion at MCP launch / config-load time, so resolving here would only
// bake real secret values into the rendered target files AND the state/
// snapshots tracked by git — which is a security regression. Leave
// placeholders alone; the downstream harness resolves them at use time.
func Run(opt Options) (*Report, error) { func Run(opt Options) (*Report, error) {
if err := canonical.SubstituteSecrets(opt.Bundle, secrets.OSEnv); err != nil {
return nil, fmt.Errorf("env-var substitution: %w", err)
}
rep := &Report{} rep := &Report{}
for _, ad := range opt.Adapters { for _, ad := range opt.Adapters {
files, err := ad.Render(opt.Bundle) files, err := ad.Render(opt.Bundle)