fix: inject channel env vars into K8s manifests (closes #50)#54
Open
initializ-mk wants to merge 1 commit into
Open
fix: inject channel env vars into K8s manifests (closes #50)#54initializ-mk wants to merge 1 commit into
initializ-mk wants to merge 1 commit into
Conversation
The K8s manifests generated by `forge build` / `forge package` included only skill-aggregated env vars. Channel env vars (e.g. SLACK_BOT_TOKEN, TELEGRAM_BOT_TOKEN) were silently dropped, even though docker-compose got them via a hardcoded switch in package.go. Unify both paths on a single canonical source: each project's per-channel YAML (e.g. slack-config.yaml), which already uses the `_env` suffix convention that runtime channels.ResolveEnvVars honors. - forge-cli/channels/env.go: EnvVarsFromConfig(workDir, channels) reads each <channel>-config.yaml, extracts every `_env`-suffixed setting value, returns sorted/deduped env-var names plus a list of channels whose config file is missing. - forge-cli/build/channels_stage.go: ChannelsStage unions the helper's output into Spec.Requirements.EnvRequired so the existing K8s templates pick them up. Creates Requirements when channels are configured but no skills are. Inserted into the build pipeline between RequirementsStage and PolicyStage. - forge-cli/cmd/package.go: generateDockerCompose now accepts workDir and uses the helper instead of a hardcoded slack/telegram switch. Behavior change: SLACK_SIGNING_SECRET is no longer injected into docker-compose. The prior hardcoded switch listed it but the Slack adapter is Socket Mode and never reads it. Operators who need it can add `signing_secret_env: SLACK_SIGNING_SECRET` to slack-config.yaml. Tests: - channels/env_test.go: extraction, dedup, missing file, parse error. - build/channels_stage_test.go: union with skill envs, creation when Requirements is nil, no-op for projects without channels, missing config warns, end-to-end regression that runs ChannelsStage + K8sStage and asserts channel env vars appear via secretKeyRef in deployment.yaml and secrets.yaml. - cmd/package_test.go: existing test updated to seed channel YAMLs and assert the new YAML-driven env-var set (SIGNING_SECRET no longer expected). Adding a new channel adapter now requires zero edits to k8s_stage.go, requirements_stage.go, template_data.go, any template, or package.go — the adapter ships its own <name>-config.yaml template and the helper picks it up.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #50 —
forge buildandforge packagenow include communication-channel env vars (e.g.SLACK_BOT_TOKEN,TELEGRAM_BOT_TOKEN) in the generated Kubernetesdeployment.yamlandsecrets.yaml. They were silently dropped before; only the hardcoded path incmd/package.go(docker-compose) injected them.Approach
Both output paths now use a single canonical source: each project's per-channel YAML (
<workDir>/<channel>-config.yaml). The_envsuffix convention (bot_token_env: SLACK_BOT_TOKEN) is already the runtime contract viachannels.ResolveEnvVars— this PR just makes the build pipeline honor the same convention.forge-cli/channels/env.go(new)EnvVarsFromConfig(workDir, channels)returns the sorted/deduped union of env-var names across channel YAMLs, plus a list of channels whose config file is missing.forge-cli/build/channels_stage.go(new)ChannelsStageunions the helper's output intoSpec.Requirements.EnvRequired(creatingRequirementsifRequirementsStageleft it nil for channels-only projects). Inserted in the pipeline betweenRequirementsStageandPolicyStage. Missing channel YAMLs surface a build warning, not an error.forge-cli/cmd/package.gogenerateDockerComposenow acceptsworkDirand calls the same helper instead of a hardcodedcase "slack" / case "telegram"switch.forge-cli/cmd/build.go&build.ChannelsStage{}into the build pipeline.Templates (
deployment.yaml.tmpl,secrets.yaml.tmpl) are untouched — they already iterateRequiredEnvVars, so unioning channel env vars into that field is enough.Behavior change worth calling out
forge package --with-channelsno longer injectsSLACK_SIGNING_SECRETintodocker-compose.yaml. The prior hardcoded switch listed it, but the Slack adapter is Socket Mode (forge-plugins/channels/slack/slack.go:55-67) and never reads it. The shippedslack-config.yaml.tmplalso doesn't declare it. Switching to the YAML-driven source corrects that long-standing inaccuracy.Operators who need
SLACK_SIGNING_SECRETfor a custom adapter setup can addsigning_secret_env: SLACK_SIGNING_SECRETto theirslack-config.yaml— the helper will pick it up automatically. This flips the question from "is this in our hardcoded list?" to "is this in your project config?".Tests
New tests:
forge-cli/channels/env_test.go— extracts_envsuffix settings, ignores non-env settings (mode,webhook_path), dedups across channels, reports missing config files, returns clean empty results for no channels, surfaces parse errors.forge-cli/build/channels_stage_test.go:TestChannelsStage_UnionsWithSkillEnvRequired— channel env vars merge with skillEnvRequired.TestChannelsStage_PopulatesRequirementsWhenNil— channels-only projects.TestChannelsStage_NoChannels— no-op whencfg.Channelsis empty.TestChannelsStage_FlowsThroughToK8sManifests— end-to-end regression for Communication channel env vars are missing from generated Kubernetes manifests #50: withslack-config.yamlandtelegram-config.yamlon disk, runningChannelsStagethenK8sStageproduces adeployment.yamlandsecrets.yamlcontainingSLACK_APP_TOKEN,SLACK_BOT_TOKEN,TELEGRAM_BOT_TOKENreferenced viasecretKeyRef.TestChannelsStage_MissingConfigWarns— missing channel YAML produces a warning, build continues.Updated:
forge-cli/cmd/package_test.go—TestGenerateDockerComposenow seeds channel YAMLs in the temp workDir, passes the newworkDirparameter, asserts the YAML-declared vars are present, and assertsSLACK_SIGNING_SECRETis absent.Acceptance criteria from #50
channels: [slack, telegram]inforge.yaml,k8s/secrets.yamllists the declared channel env vars andk8s/deployment.yamlreferences them viasecretKeyRef.k8s_stage.go,requirements_stage.go,template_data.go, any template, orcmd/package.go. The new adapter ships its own<name>-config.yamltemplate throughforge initand the helper picks it up.docker-compose.yaml(--with-channels) andk8s/{deployment,secrets}.yamlproduce a consistent set of channel env vars from the same source.Test plan
forge init my-agent --framework forge, addchannels: [slack, telegram]toforge.yaml, runforge build. Confirmk8s/secrets.yamllistsSLACK_APP_TOKEN,SLACK_BOT_TOKEN,TELEGRAM_BOT_TOKENandk8s/deployment.yamlreferences them viasecretKeyRef.forge package --with-channels. Confirmdocker-compose.yamlcontains the same channel env-var set.channels: [slack]but deleteslack-config.yaml. Confirmforge buildsucceeds with a warning that mentions slack.custom_env: MY_CUSTOM_SECRETto a project'sslack-config.yaml. Re-runforge build. ConfirmMY_CUSTOM_SECRETflows into both the K8s manifest anddocker-compose.yamlwith no code changes.