Skip to content

feat: handle multiple env vars, add/update multiple, delete multiple#4093

Open
dan2k3k4 wants to merge 8 commits into
mainfrom
handle-multiple-env-vars
Open

feat: handle multiple env vars, add/update multiple, delete multiple#4093
dan2k3k4 wants to merge 8 commits into
mainfrom
handle-multiple-env-vars

Conversation

@dan2k3k4

@dan2k3k4 dan2k3k4 commented May 27, 2026

Copy link
Copy Markdown
Contributor

Closes #4092

Summary

Adds two new GraphQL mutations on the API service for batch environment variable operations, scoped to a single organization, project, or environment per call:

  • addOrUpdateEnvVariablesByName — create or update many variables
  • deleteEnvVariablesByName — delete many variables (idempotent)

Both return a structured EnvVariableBatchResult so callers can observe per-entry outcomes when a batch partially fails. See #4092 for the full API rationale, schema, error model, and acceptance criteria.

API surface

input EnvVariableEntryInput {
  name: String!
  value: String!
  scope: EnvVariableScope
}

input EnvVariablesByNameInput {
  organization: String
  project: String
  environment: String
  variables: [EnvVariableEntryInput!]!
}

input DeleteEnvVariablesByNameInput {
  organization: String
  project: String
  environment: String
  names: [String!]!
}

type EnvVariableBatchEntryResult {
  name: String!
  success: Boolean!
  envVariable: EnvKeyValue   # populated on success for upsert; null for delete
  error: String              # populated on per-entry failure
}

type EnvVariableBatchResult {
  successCount: Int!
  failureCount: Int!
  results: [EnvVariableBatchEntryResult!]!
}

addOrUpdateEnvVariablesByName(input: EnvVariablesByNameInput!): EnvVariableBatchResult!
deleteEnvVariablesByName(input: DeleteEnvVariablesByNameInput!): EnvVariableBatchResult!

Behavior

Targeting — exactly one of: organization-only, project-only, or project + environment. Any other combination is rejected.

Two-tier error model

  • Whole-batch errors (throw, no rows written): empty list, oversize batch, invalid target combo, target not found, permission denied, project restriction violated.
  • Per-entry errors (caught and reported in results, sibling entries continue): empty/blank name, deprecated internal_container_registry scope, DB constraint errors.

Delete is idempotent — a name that does not exist for the target reports success: true. This lets sync workflows declare "these N should not exist" without first querying.

Permission and project-restriction checks run once per call for the shared target, reusing the existing Keycloak scopes (env_var:project:add, env_var:environment:add:{type}, organization:addEnvVar, and the corresponding :delete scopes) — no new scopes were added.

Atomicity — per-entry try/catch in a loop, no DB transaction. Pre-flight validation makes mid-batch failures unlikely; when they happen, the result tells the caller exactly which entries persisted. Modeled on the existing processAddFacts pattern.

Audit log — one userActivityLogger entry per call summarizing the batch (envVarType, target name, count, successCount, failureCount, names list), not one per entry.

Batch size limit — default 20 entries, overridable via the BATCH_ENV_VARS_LIMIT env var on the API service (consistent with other env-driven config in services/api/src/util/config.ts). Oversize batches are rejected as a whole-batch error so the client knows to chunk. A TODO is left in the resolver noting that automatic server-side chunking could be added if usage warrants it.

Files changed

File Change
services/api/src/typeDefs.js Added 2 types, 3 inputs, 2 mutations
services/api/src/util/config.ts Added envVarsConfig.batchLimit
services/api/src/resources/env-variables/resolvers.ts Added resolveEnvVarBatchTarget, upsertEnvVarRowForTarget, deleteEnvVarRowByNameForTarget, enforceBatchSize helpers and the two new resolvers
services/api/src/resolvers.js Wired the two new resolvers into the Mutation map
tests/tasks/api/batch-add-project-variables.{gql,yaml} New Ansible task templates
tests/tasks/api/batch-delete-project-variables.{gql,yaml} New Ansible task templates
tests/tests/api/batch-project-variables.yaml Wrapper playbook (batch add 3 vars, batch delete 4 names including a non-existent one to verify idempotency)

The existing singular addOrUpdateEnvVariableByName / deleteEnvVariableByName resolvers are untouched — this change is purely additive. No DB migration. No new Keycloak scopes.

Example

mutation BatchAdd($input: EnvVariablesByNameInput!) {
  addOrUpdateEnvVariablesByName(input: $input) {
    successCount
    failureCount
    results {
      name
      success
      error
      envVariable { id scope name value }
    }
  }
}
{
  "input": {
    "project": "my-project",
    "environment": "main",
    "variables": [
      { "name": "API_TOKEN",  "value": "...", "scope": "RUNTIME" },
      { "name": "BUILD_FLAG", "value": "1",    "scope": "BUILD"   },
      { "name": "FEATURE_X",  "value": "on",   "scope": "GLOBAL"  }
    ]
  }
}

Verification

  • yarn workspace api run build — passes (TypeScript clean).
  • yarn workspace api run test — same 4 pre-existing snapshot/redis failures as main (notification, environment, advancedtasktoolbox, sshKey); no new failures introduced.
  • Local API loop available via make api-development for iterating on GraphQL changes without spinning up the full stack — used to verify mutations against the API.

Acceptance criteria (from #4092)

  • addOrUpdateEnvVariablesByName accepts org / project / environment-scoped batches and returns an EnvVariableBatchResult.
  • deleteEnvVariablesByName accepts the same scoping and returns an EnvVariableBatchResult; deleting a non-existent name reports success: true.
  • Whole-batch errors (target / permission / restriction / size / empty) throw and do not write any rows.
  • Per-entry errors (validation, DB constraint) are reported in results and do not abort sibling entries.
  • Permission and project-restriction checks run once per call for the shared target.
  • Existing singular mutations are unchanged.
  • Batch size limit defaults to 20, overridable via BATCH_ENV_VARS_LIMIT.
  • One audit log entry per call summarizing the batch.
  • Integration tests cover: project-scoped batch add, partial-failure reporting, delete with a missing name (idempotency).

@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown

Overview

Image reference testlagoon/api:main lagoon/api:ci-latest
- digest 9b0c85021dd9 91e0f6dfa99d
- tag main ci-latest
- vulnerabilities critical: 4 high: 65 medium: 61 low: 8 unspecified: 3 critical: 4 high: 65 medium: 61 low: 8 unspecified: 3
- platform linux/amd64 linux/amd64
- size 152 MB 183 MB (+31 MB)
- packages 1568 1568
Base Image node:22-alpine
also known as:
22-alpine3.23
22.22-alpine
22.22-alpine3.23
22.22.3-alpine
22.22.3-alpine3.23
jod-alpine
jod-alpine3.23
node:22-alpine
also known as:
22-alpine3.23
22.22-alpine
22.22-alpine3.23
22.22.3-alpine
22.22.3-alpine3.23
jod-alpine
jod-alpine3.23
- vulnerabilities critical: 0 high: 1 medium: 4 low: 0 critical: 0 high: 1 medium: 4 low: 0

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 adds batch GraphQL mutations to upsert and delete multiple environment variables in a single call, scoped to exactly one target (organization, project, or project+environment). It extends the API with a structured per-entry result model and adds Ansible-based integration tests to exercise the new behavior.

Changes:

  • Added GraphQL schema for EnvVariableBatchResult/EnvVariableBatchEntryResult plus new batch mutations and inputs.
  • Implemented batch resolver logic with shared target/permission/restriction checks and per-entry error handling.
  • Introduced a configurable batch size limit (BATCH_ENV_VARS_LIMIT) and added test playbooks/templates for batch add/delete.

Reviewed changes

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

Show a summary per file
File Description
services/api/src/typeDefs.js Adds new batch result types, inputs, and two new mutations to the GraphQL schema.
services/api/src/util/config.ts Adds envVarsConfig.batchLimit driven by BATCH_ENV_VARS_LIMIT.
services/api/src/resources/env-variables/resolvers.ts Implements batch target resolution, batch size enforcement, and the two new batch resolvers with audit logging.
services/api/src/resolvers.js Wires the new batch resolvers into the GraphQL Mutation map.
tests/tasks/api/batch-add-project-variables.{gql,yaml} Adds Ansible task + GraphQL template to test batch upsert at project scope.
tests/tasks/api/batch-delete-project-variables.{gql,yaml} Adds Ansible task + GraphQL template to test batch delete at project scope.
tests/tests/api/batch-project-variables.yaml Adds a wrapper playbook to run the batch add + batch delete test flow.

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

Comment thread services/api/src/resources/env-variables/resolvers.ts
Comment thread services/api/src/resources/env-variables/resolvers.ts
Comment thread services/api/src/resources/env-variables/resolvers.ts
Comment thread services/api/src/util/config.ts
Comment thread tests/tasks/api/batch-add-project-variables.gql
Comment thread tests/tasks/api/batch-delete-project-variables.yaml
Comment thread tests/tests/api/batch-project-variables.yaml Outdated
dan2k3k4 and others added 8 commits June 4, 2026 06:47
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@dan2k3k4 dan2k3k4 force-pushed the handle-multiple-env-vars branch from 97e0342 to c76f97b Compare June 4, 2026 04:47
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.

Batch Operations for Environment Variables via API

3 participants