Skip to content

feat(apps): declare envMappings per app; return in GET /api/connections#16

Merged
matoushavlena merged 1 commit intomainfrom
feat/connection-env-mappings
Apr 21, 2026
Merged

feat(apps): declare envMappings per app; return in GET /api/connections#16
matoushavlena merged 1 commit intomainfrom
feat/connection-env-mappings

Conversation

@matoushavlena
Copy link
Copy Markdown

@matoushavlena matoushavlena commented Apr 21, 2026

Summary

OneCLI now declares pod-env-var injection next to the app definition it belongs with, and returns those mappings in GET /api/connections so consumers don't need provider-specific knowledge.

// apps/web/src/lib/apps/gmail.ts
envMappings: googleWorkspaceEnvMappings  // [{ envName: "GOOGLE_WORKSPACE_CLI_TOKEN", placeholder: "humr:sentinel" }]

Consumer (Humr) reads connection.envMappings directly; no PATCH, no backfill, no per-connection metadata, no database migration.

Why

Previously Humr kept a hardcoded provider→env table mirrored across its TS + Go code. Adding a new Google app (Calendar, Sheets) to OneCLI required a Humr PR to teach the controller which env var the new provider contributed. That knowledge belongs with the app definition — OneCLI already owns the OAuth scopes, permissions, and client config for each provider.

What changes

  • Shared schema + typeapps/web/src/lib/env-mapping.ts (new): envMappingSchema (zod) + EnvMapping type via z.infer. Single source of truth. lib/validations/secret.ts now imports the schema instead of redefining it.
  • App registry fieldapps/web/src/lib/apps/types.ts: AppDefinition.envMappings?: EnvMapping[].
  • Shared Google helperapps/web/src/lib/apps/google-oauth.ts: googleWorkspaceEnvMappings const.
  • All 15 Google Workspace apps opt in — gmail, google-drive, google-calendar, google-sheets, google-docs, google-slides, google-forms, google-tasks, google-meet, google-classroom, google-admin, google-photos, google-analytics, google-search-console, google-health. All use the shared Google OAuth flow and the same bearer token works for all of them via gws.
  • Route joinapps/web/src/app/api/connections/route.ts: join envMappings from the registry into each connection row, same shape as the existing providerName join (widened the lookup from providerNameById to appById).

Test plan

  • pnpm --filter @onecli/web exec tsc --noEmit passes
  • pnpm --filter @onecli/web lint passes
  • cargo fmt --check + cargo clippy -- -D warnings pass
  • Manual probe: GET /api/connections with a gmail/calendar/drive/sheets connection returns envMappings: [{envName: "GOOGLE_WORKSPACE_CLI_TOKEN", placeholder: "humr:sentinel"}]; with a github/resend/spotify/youtube connection returns envMappings: null

Consumer

Unblocks kagenti/humr#262, which reads the field directly and populates the agent env on grant (editable like any other env).

@matoushavlena matoushavlena force-pushed the feat/connection-env-mappings branch from d276a5c to f2382dc Compare April 21, 2026 15:06
@matoushavlena matoushavlena changed the title feat(api): add PATCH /api/connections/:id for client-settable metadata feat(apps): declare envMappings per app; return in GET /api/connections Apr 21, 2026
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
When a user grants a connection (e.g. Google Drive) in the Configure
Agent dialog, any envMappings OneCLI declared for that app get appended
to the agent's editable env list. The user can then edit or remove the
entries like any other custom env var.

Requires a companion OneCLI patch (kagenti/onecli#16) that adds
`envMappings` as a first-class field on the app registry and returns
it on `GET /api/connections`.

Why this over storing envs on the connection itself: envs belong with
the agent (that's the K8s resource that consumes them), and users may
reasonably want to tweak the env name or remove a mapping for a
specific agent without losing the grant. Humr has zero provider
knowledge — the env-injection contract lives in OneCLI next to the
OAuth config for each app.

- api-server-api: `AppConnectionView.envMappings?` for UI consumption
- api-server: passes through OneCLI's joined envMappings verbatim on
  `connections.list`
- ui: `EditAgentSecretsDialog.toggleApp` appends new app's envMappings
  to the agent env list on first grant (dedupe by env name — user-set
  wins); ungrant leaves envs alone so user edits aren't lost
- ui: `ConnectorsView` displays env names on each connection row so
  users can see what a grant will contribute
- docs: google-workspace README describes the new grant-time flow

Signed-off-by: Matous Havlena <havlenma@gmail.com>
@matoushavlena matoushavlena force-pushed the feat/connection-env-mappings branch from f2382dc to d75591c Compare April 21, 2026 15:17
Some apps go through CLIs that expect a specific env var name holding
the credential sentinel — `gws` for Google Workspace wants
`GOOGLE_WORKSPACE_CLI_TOKEN`. Declares this as a first-class field on
`AppDefinition`, co-located with the rest of the app's metadata (scopes,
permissions, OAuth config).

`GET /api/connections` now joins `envMappings` from the app registry
into each connection row, same shape as the existing `providerName`
join. Consumers (Humr) drop their provider→env table and just read the
field from the response — no client-side writes, no backfill, no
per-connection metadata.

Added only to `gmail` and `google-drive` for now (both share the same
`GOOGLE_WORKSPACE_CLI_TOKEN` via `googleWorkspaceEnvMappings`). Other
providers opt in by setting the field — no other code changes needed.

Signed-off-by: Matous Havlena <havlenma@gmail.com>
@matoushavlena matoushavlena force-pushed the feat/connection-env-mappings branch from d75591c to 7eb0498 Compare April 21, 2026 15:25
@matoushavlena matoushavlena merged commit b6be922 into main Apr 21, 2026
2 checks passed
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
…ump onecli

- Test fixture in connections-service.test.ts used literal Google provider
  names and env var strings. Humr's service is provider-agnostic (just
  passes OneCLI's joined fields to the view) — swap to a fictional
  `acme-app` / `ACME_TOKEN` fixture so the test asserts pass-through
  behavior without coupling to any specific provider.
- On ungrant, toggleApp now removes envs the app contributed *only if*
  they're still untouched (name + value match the declared mapping) AND
  no other still-granted app declares the same envName. The double guard
  protects shared envs (Gmail + Drive both want GOOGLE_WORKSPACE_CLI_TOKEN
  — ungranting Drive while Gmail is still granted must not drop the env)
  and user edits (an edited value signals intent the toggle shouldn't
  undo).
- Bump OneCLI image to 0.0.20 — ships the app-registry envMappings
  field this PR depends on (kagenti/onecli#16).

Signed-off-by: Matous Havlena <havlenma@gmail.com>
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
When a user grants a connection (e.g. Google Drive) in the Configure
Agent dialog, any envMappings OneCLI declared for that app get appended
to the agent's editable env list. The user can then edit or remove the
entries like any other custom env var. On ungrant, entries that are
still untouched (name + value match the declared mapping) and not
required by any other still-granted app are removed automatically.

Requires OneCLI 0.0.20+ which adds `envMappings` as a first-class field
on the app registry and returns it on `GET /api/connections`
(kagenti/onecli#16).

Why this over storing envs on the connection itself: envs belong with
the agent (that's the K8s resource that consumes them), and users may
reasonably want to tweak the env name or remove a mapping for a
specific agent without losing the grant. Humr has zero provider
knowledge — the env-injection contract lives in OneCLI next to the
OAuth config for each app.

- api-server-api: `AppConnectionView.envMappings?` for UI consumption
- api-server: passes through OneCLI's joined envMappings verbatim on
  `connections.list`; tests use a fictional provider fixture so they
  don't couple to any specific provider
- ui: `EditAgentSecretsDialog.toggleApp` appends new app's envMappings
  to the agent env list on first grant (dedupe by env name — user-set
  wins); on ungrant removes entries only if they match the declared
  mapping and no other still-granted app declares the same envName
- ui: `ConnectorsView` displays env names on each connection row so
  users can see what a grant will contribute
- deploy: bump OneCLI image to 0.0.20
- docs: google-workspace README describes the new grant-time flow

Signed-off-by: Matous Havlena <havlenma@gmail.com>
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
When a user grants a connection (e.g. Google Drive) in the Configure
Agent dialog, any envMappings OneCLI declared for that app get appended
to the agent's editable env list. The user can then edit or remove the
entries like any other custom env var. On ungrant, entries that are
still untouched (name + value match the declared mapping) and not
required by any other still-granted app are removed automatically.

Requires OneCLI 0.0.20+ which adds `envMappings` as a first-class field
on the app registry and returns it on `GET /api/connections`
(kagenti/onecli#16).

Why this over storing envs on the connection itself: envs belong with
the agent (that's the K8s resource that consumes them), and users may
reasonably want to tweak the env name or remove a mapping for a
specific agent without losing the grant. Humr has zero provider
knowledge — the env-injection contract lives in OneCLI next to the
OAuth config for each app.

- api-server-api: `AppConnectionView.envMappings?` for UI consumption
- api-server: passes through OneCLI's joined envMappings verbatim on
  `connections.list`; tests use a fictional provider fixture so they
  don't couple to any specific provider
- ui: `EditAgentSecretsDialog.toggleApp` appends new app's envMappings
  to the agent env list on first grant (dedupe by env name — user-set
  wins); on ungrant removes entries only if they match the declared
  mapping and no other still-granted app declares the same envName
- ui: `ConnectorsView` displays env names on each connection row so
  users can see what a grant will contribute
- deploy: bump OneCLI image to 0.0.20
- docs: google-workspace README describes the new grant-time flow

Signed-off-by: Matous Havlena <havlenma@gmail.com>
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
When a user grants a connection (e.g. Google Drive) in the Configure
Agent dialog, any envMappings OneCLI declared for that app get appended
to the agent's editable env list. The user can then edit or remove the
entries like any other custom env var. On ungrant, entries that are
still untouched (name + value match the declared mapping) and not
required by any other still-granted app are removed automatically.

Requires OneCLI 0.0.20+ which adds `envMappings` as a first-class field
on the app registry and returns it on `GET /api/connections`
(kagenti/onecli#16).

Why this over storing envs on the connection itself: envs belong with
the agent (that's the K8s resource that consumes them), and users may
reasonably want to tweak the env name or remove a mapping for a
specific agent without losing the grant. Humr has zero provider
knowledge — the env-injection contract lives in OneCLI next to the
OAuth config for each app.

- api-server-api: `AppConnectionView.envMappings?` for UI consumption
- api-server: passes through OneCLI's joined envMappings verbatim on
  `connections.list`; tests use a fictional provider fixture so they
  don't couple to any specific provider
- ui: `EditAgentSecretsDialog.toggleApp` appends new app's envMappings
  to the agent env list on first grant (dedupe by env name — user-set
  wins); on ungrant removes entries only if they match the declared
  mapping and no other still-granted app declares the same envName
- ui: `ConnectorsView` displays env names on each connection row so
  users can see what a grant will contribute
- deploy: bump OneCLI image to 0.0.20
- docs: google-workspace README describes the new grant-time flow

Signed-off-by: Matous Havlena <havlenma@gmail.com>
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
When a user grants a connection (e.g. Google Drive) in the Configure
Agent dialog, any envMappings OneCLI declared for that app get appended
to the agent's editable env list. The user can then edit or remove the
entries like any other custom env var. On ungrant, entries that are
still untouched (name + value match the declared mapping) and not
required by any other still-granted app are removed automatically.

Requires OneCLI 0.0.20+ which adds `envMappings` as a first-class field
on the app registry and returns it on `GET /api/connections`
(kagenti/onecli#16).

Why this over storing envs on the connection itself: envs belong with
the agent (that's the K8s resource that consumes them), and users may
reasonably want to tweak the env name or remove a mapping for a
specific agent without losing the grant. Humr has zero provider
knowledge — the env-injection contract lives in OneCLI next to the
OAuth config for each app.

- api-server-api: `AppConnectionView.envMappings?` for UI consumption
- api-server: passes through OneCLI's joined envMappings verbatim on
  `connections.list`; tests use a fictional provider fixture so they
  don't couple to any specific provider
- ui: `EditAgentSecretsDialog.toggleApp` appends new app's envMappings
  to the agent env list on first grant (dedupe by env name — user-set
  wins); on ungrant removes entries only if they match the declared
  mapping and no other still-granted app declares the same envName
- ui: `ConnectorsView` displays env names on each connection row so
  users can see what a grant will contribute
- deploy: bump OneCLI image to 0.0.20
- docs: google-workspace README describes the new grant-time flow

Signed-off-by: Matous Havlena <havlenma@gmail.com>
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
Extends ADR-024's "env declared by credential owner" principle to OAuth
app connections. Three rationale points: users shouldn't have to know
env var names; Humr shouldn't decide env names for OneCLI-owned
providers; agent templates shouldn't bake connection envs since
connections are a runtime choice.

Shipped in kagenti/onecli#16 + #262.

Signed-off-by: Matous Havlena <havlenma@gmail.com>
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
Extends ADR-024's "env declared by credential owner" principle to OAuth
app connections. Three rationale points: users shouldn't have to know
env var names; Humr shouldn't decide env names for OneCLI-owned
providers; agent templates shouldn't bake connection envs since
connections are a runtime choice.

Shipped in kagenti/onecli#16 + #262.

Signed-off-by: Matous Havlena <havlenma@gmail.com>
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
Extends ADR-024's "env declared by credential owner" principle to OAuth
app connections. Three rationale points: users shouldn't have to know
env var names; Humr shouldn't decide env names for OneCLI-owned
providers; agent templates shouldn't bake connection envs since
connections are a runtime choice.

Shipped in kagenti/onecli#16 + #262.

Signed-off-by: Matous Havlena <havlenma@gmail.com>
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
Slimmed the ADR from 143 lines to 43 — kept the decision, dropped
implementation detail (zod schemas, Prisma columns, key files,
verification blocks) that belongs in commit messages and PRs.

Unified the secret + connection paths under one principle: "the entity
that owns the credential declares which env vars it needs." The two
paths differ in storage (secret metadata vs OneCLI app registry) and
flow (controller-merged vs UI-populated) but share the rationale.

Captures the four guiding constraints: users shouldn't know env names;
Humr shouldn't decide env names for OneCLI-owned providers; templates
shouldn't bake connection envs; power users can still tweak per-agent.

Tracked in kagenti/onecli#9 (secrets), kagenti/onecli#16 +
#262 (connections).

Signed-off-by: Matous Havlena <havlenma@gmail.com>
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 21, 2026
Slimmed the ADR from 143 lines to 43 — kept the decision, dropped
implementation detail (zod schemas, Prisma columns, key files,
verification blocks) that belongs in commit messages and PRs.

Unified the secret + connection paths under one principle: "the entity
that owns the credential declares which env vars it needs." The two
paths differ in storage (secret metadata vs OneCLI app registry) and
flow (controller-merged vs UI-populated) but share the rationale.

Captures the four guiding constraints: users shouldn't know env names;
Humr shouldn't decide env names for OneCLI-owned providers; templates
shouldn't bake connection envs; power users can still tweak per-agent.

Tracked in kagenti/onecli#9 (secrets), kagenti/onecli#16 +
#262 (connections).

Signed-off-by: Matous Havlena <havlenma@gmail.com>
matoushavlena added a commit to kagenti/humr that referenced this pull request Apr 22, 2026
Slimmed the ADR from 143 lines to 43 — kept the decision, dropped
implementation detail (zod schemas, Prisma columns, key files,
verification blocks) that belongs in commit messages and PRs.

Unified the secret + connection paths under one principle: "the entity
that owns the credential declares which env vars it needs." The two
paths differ in storage (secret metadata vs OneCLI app registry) and
flow (controller-merged vs UI-populated) but share the rationale.

Captures the four guiding constraints: users shouldn't know env names;
Humr shouldn't decide env names for OneCLI-owned providers; templates
shouldn't bake connection envs; power users can still tweak per-agent.

Tracked in kagenti/onecli#9 (secrets), kagenti/onecli#16 +
#262 (connections).

Signed-off-by: Matous Havlena <havlenma@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants