Skip to content

feat(config): unify env and forced_env with interpolation support#6

Merged
dedene merged 3 commits intomainfrom
feat/unified-env-interpolation
Feb 19, 2026
Merged

feat(config): unify env and forced_env with interpolation support#6
dedene merged 3 commits intomainfrom
feat/unified-env-interpolation

Conversation

@dedene
Copy link
Owner

@dedene dedene commented Feb 18, 2026

Summary

  • Merge env and forced_env into a single env key with three value types:
    • Exact credential reference: value matches a defined credential name → resolved at runtime
    • Template interpolation: {{ credential-name }} → substituted inline
    • Literal value: no credential refs → used as-is
  • All env entries are now admin-controlled (forced) and cannot be overridden by client requests
  • Deprecate forced_env (still works with warning for backward compatibility)

Example

credentials:
  github-token:
    source: pass:github/token
  db-password:
    source: op://vault/db/password

tools:
  myapp:
    binary: /usr/bin/myapp
    env:
      GH_TOKEN: github-token                                    # exact credential ref
      DATABASE_URL: "postgres://app:{{ db-password }}@db/prod"  # interpolated
      PATH: /usr/bin:/bin                                       # literal

Test plan

  • Unit tests for interpolation module (interpolate_test.go)
  • Updated config validation tests
  • Updated executor env tests (unified env cannot be overridden)
  • Full test suite passes (go test ./...)
  • Manual integration test with running daemon (requires credential setup)

Merge `env` and `forced_env` into a single `env` key with three value types:
- Exact credential reference: value matches a defined credential name
- Template interpolation: `{{ credential-name }}` substituted inline
- Literal value: no credential refs, used as-is

All env entries are now admin-controlled (forced) and cannot be overridden
by client requests.

Changes:
- Add interpolate.go with FindCredentialRefs, Interpolate, ResolveEnvValue
- Update config validation to support unified env with template refs
- Update executor to use ResolveEnvValue for all three value types
- Deprecate forced_env (still works with warning)
- Update README with new env syntax documentation

BREAKING: None - forced_env still works (deprecated)
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR unifies the env and forced_env configuration fields into a single env key that supports three value types: exact credential references, template interpolation with {{ credential-name }} syntax, and literal values. All entries are admin-controlled and cannot be overridden by client requests. The forced_env field is deprecated but remains functional for backward compatibility.

Changes:

  • Introduces a new interpolation module (internal/config/interpolate.go) with functions for parsing and resolving credential references in env values
  • Updates config validation to handle the three env value types (exact credential, interpolated template, or literal)
  • Modifies executor environment building to use the new unified env resolution system
  • Adds comprehensive unit tests for interpolation logic and updates existing tests for the unified behavior

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/config/interpolate.go New module implementing credential reference parsing, classification, and interpolation with {{ name }} syntax
internal/config/interpolate_test.go Comprehensive unit tests for all interpolation functions covering edge cases and error scenarios
internal/config/config.go Updated validation logic to support unified env with three value types and emit deprecation warnings for forced_env
internal/config/config_test.go Updated tests to reflect new behavior where plain values are literals and only {{ refs }} require credentials
internal/daemon/executor.go Modified environment building to resolve env values using the new classification and interpolation system
internal/daemon/executor_env_test.go New tests verifying literal values, override protection, and admin-controlled dangerous variables in unified env
README.md Updated documentation with clear examples of the three env value types and deprecation notice for forced_env

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 147 to 151
// NormalizeCredentialRef trims whitespace from a credential ref.
// "{{ foo }}" → "foo"
func NormalizeCredentialRef(ref string) string {
return strings.TrimSpace(ref)
}
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NormalizeCredentialRef function is defined but never used in the codebase. Consider removing it to reduce dead code, or if it's intended for future use, document its purpose and mark it with a TODO comment.

Copilot uses AI. Check for mistakes.
}
if value == "" {
return nil, fmt.Errorf("empty credential: %s", credName)
return "", fmt.Errorf("empty value")
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message "empty value" doesn't include the credential name, which could make debugging harder. Consider including the credential name in the error: fmt.Errorf("credential %s returned empty value", name). This error will be wrapped with the env var name at line 291, providing full context.

Copilot uses AI. Check for mistakes.
- Remove unused NormalizeCredentialRef function (dead code)
- Improve error message to include credential name for debugging
Dead code - logic already inlined in ClassifyEnvValue.
@dedene dedene merged commit b6f66c8 into main Feb 19, 2026
2 checks passed
@dedene dedene deleted the feat/unified-env-interpolation branch February 19, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments