Skip to content

feat(iaci): {profile} placeholder in secrets_inventory paths (#65)#66

Merged
Zorlin merged 1 commit into
mainfrom
feat/env-secrets-profile-template
Jun 30, 2026
Merged

feat(iaci): {profile} placeholder in secrets_inventory paths (#65)#66
Zorlin merged 1 commit into
mainfrom
feat/env-secrets-profile-template

Conversation

@Zorlin

@Zorlin Zorlin commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Implements #65.

What

secrets_inventory paths may contain {profile}, substituted with the active profile name at contract-resolution — so one test environment layers <site>-test per selected profile (london/nyc/seattle) instead of needing a per-site env.

profiles:
  london: { inventory: [labs/london], secrets_inventory: [../infra-secrets/london] }
environments:
  test:
    secrets_inventory:
      - ../infra-secrets/{profile}-test   # --profile london → ../infra-secrets/london-test

Applies to environments.<n>.secrets_inventory (core) and profiles.<n>.secrets_inventory (self-name, symmetry/DRY). defaults.secrets_inventory is intentionally not supported (ambiguous which profile).

Decisions

  • Syntax {profile} (issue's primary lean) — a contract-time meta-token, deliberately not {{var}} Templar syntax, so only {profile} is special and contract paths can't be accidentally templated.
  • No profile + {profile} → clear error (not silent empty substitution).
  • YAML quoting: {/} are flow indicators, so quote in flow style (["../sec/{profile}-test"]) or use block style — same rule as {{var}} everywhere else.

Tests (3 new, all green; 431 total pass, 0 fail, no new warnings)

  • environment_secrets_profile_placeholder_resolves_to_active_profile — resolves and lands in the real load list.
  • environment_secrets_profile_placeholder_without_profile_errors — clear error naming the placeholder + cause.
  • profile_secrets_profile_placeholder_self_substitutes — a profile's own {profile} → its name.

The downstream load → later-wins → template chain is already covered by the #60 env-axis composition tests + loading.rs regressions, so no redundant full-load e2e.

🤖 Generated with Claude Code

A `secrets_inventory` path may now contain `{profile}`, substituted with
the active profile name at the contract-resolution step — so ONE
environment can layer `<site>-test` per selected profile:

  profiles:
    london: { inventory: [labs/london], secrets_inventory: [../infra-secrets/london] }
  environments:
    test:
      secrets_inventory:
        - ../infra-secrets/{profile}-test      # → ../infra-secrets/london-test

Applies to both `environments.<n>.secrets_inventory` (the core ask) and
`profiles.<n>.secrets_inventory` (self-name substitution, for symmetry/DRY).
`defaults.secrets_inventory` is intentionally NOT supported — "the profile"
is ambiguous there.

Design decisions:
- Syntax `{profile}` (per the issue's primary suggestion), a contract-time
  meta-token. Deliberately NOT `{{var}}` Templar syntax — only `{profile}`
  is special, so contract paths can't be accidentally templated.
- `{profile}` with no profile selected is a clear error (the operator asked
  for a per-profile overlay but named no profile), not a silent empty subst.
- Because `{`/`}` are YAML flow indicators, a `{profile}` path needs quoting
  in flow style (`["../sec/{profile}-test"]`) or block style
  (`  - ../sec/{profile}-test`) — same rule as `{{var}}` everywhere else.

Tests: placeholder resolves to the active profile (and lands in the real
load list); placeholder-without-profile errors clearly; a profile's own
`{profile}` self-substitutes. The downstream load→later-wins→template
chain is already covered by the env-axis composition tests (#60) and
loading.rs regressions, so no redundant full-load e2e.

Co-Authored-By: Claude <noreply@anthropic.com>
@Zorlin Zorlin merged commit d8e2901 into main Jun 30, 2026
8 of 9 checks passed
@Zorlin Zorlin deleted the feat/env-secrets-profile-template branch June 30, 2026 16: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