Skip to content

Add support for team-managed configs (ConfigMaps) via GraphQL API#364

Merged
frodesundby merged 8 commits intomainfrom
configmap
Mar 18, 2026
Merged

Add support for team-managed configs (ConfigMaps) via GraphQL API#364
frodesundby merged 8 commits intomainfrom
configmap

Conversation

@frodesundby
Copy link
Contributor

  • Introduce configmap domain with models, queries, and activity log types
  • Add GraphQL schema for configs, including CRUD mutations and filtering
  • Implement authorization for config operations
  • Add config listing, value management, and usage tracking for teams, applications, and jobs
  • Update workload interfaces and models to support GetConfigs
  • Register configmap watcher and loader
  • Add database migration for config authorizations and role grants
  • Generate GraphQL code for new config types and connections

- Introduce configmap domain with models, queries, and activity log
  types
- Add GraphQL schema for configs, including CRUD mutations and filtering
- Implement authorization for config operations
- Add config listing, value management, and usage tracking for teams,
  applications, and jobs
- Update workload interfaces and models to support GetConfigs
- Register configmap watcher and loader
- Add database migration for config authorizations and role grants
- Generate GraphQL code for new config types and connections
Copy link
Contributor

@jhrv jhrv left a comment

Choose a reason for hiding this comment

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

Review

Bra PR. Følger secret-mønsteret og forenkler der det gir mening. Noen ting:

Sort etter slice i Workloads

configmap.resolvers.go — sorteringen skjer etter pagination.Slice, så du sorterer bare innenfor én side, ikke hele listen. Flytt sorteringen opp.

Applications() og Jobs() krysser environments

En Config tilhører ett environment, men begge resolverene bruker ListAllForTeam som går på tvers. En config i dev kan da vise apper fra prod som tilfeldigvis har en config med samme navn. Workloads() gjør det riktig med ListAllForTeamInEnvironment. Samme problem i InUse-filteret i sortfilter.go.

Delete sjekker ikke configIsManagedByConsole

De andre mutasjonene gjør det. Fin anledning til å ta #329 i samme slengen.

GetSecrets() mangler tom-streng guard

GetConfigs() har if v.ConfigMap != ""GetSecrets() har det ikke. Fiks gjerne begge veier.

Tester

Secret har tre integrasjonstester (secrets.lua, secrets_cross_team.lua, workload_secrets.lua) som dekker CRUD, cross-team authz og workload-relasjoner. Tilsvarende gir mening her:

  • configs.lua — CRUD-livssyklus, feiltilfeller (duplikater, unmanaged), authz for non-members
  • configs_cross_team.lua — Andre teams kan ikke mutere, men kan se verdier (ikke sensitive)
  • workload_configs.lua — Bidireksjonale relasjoner via envFrom/filesFrom fixtures

@thokra-nav
Copy link
Contributor

Mtp at denne er endret, kanskje bare starte med å støtte det fra starten?

@jhrv
Copy link
Contributor

jhrv commented Mar 17, 2026

Ikke negativ til det. Er det noen ulemper med å ta det separat men rett etterpå - og for både secret og config?

@thokra-nav
Copy link
Contributor

Ingen problem med å ta det som oppfølger nei, tenkte bare om det kanskje kan være litt mindre jobb dersom det blir med nå :)

Includes tests for config CRUD, cross-team access, workload usage,
and activity log entries. Adds test K8s resources for configs and
applications. Updates config activity log schema and related code.
Secrets use SystemAuthenticatedClient for all mutations too - ImpersonatedClient
is only used for reading secret values (which requires temporary RBAC). ConfigMaps
don't have sensitive values, so SystemAuthenticatedClient is correct.
ConfigMaps are not sensitive, and developers already have full RBAC access
to configmaps via nais:developer ClusterRole. Using ImpersonatedClient gives
us Kubernetes audit log entries tied to the actual user, not the nais-api
service account.
# Conflicts:
#	internal/graph/gengql/activitylog.generated.go
Copy link
Contributor

@thokra-nav thokra-nav left a comment

Choose a reason for hiding this comment

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

Utenom at jeg synes vi bør fjerne filteret på Config.activityLog så ser det fint ut :)
Alternativt lage et filter som er mer riktig for typen

@frodesundby frodesundby marked this pull request as ready for review March 18, 2026 09:42
@frodesundby frodesundby requested a review from a team as a code owner March 18, 2026 09:42
@frodesundby frodesundby requested review from Copilot March 18, 2026 09:43
Copy link
Contributor

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

Adds a new “configmap/config” domain to the API, exposing team-managed Kubernetes ConfigMaps via GraphQL (listing, lookup, CRUD/value mutations), wiring it into workload usage tracking, activity log, authz, watchers/loaders, and integration tests.

Changes:

  • Extend the Workload model and workload implementations (Application/Job) to report referenced ConfigMaps.
  • Introduce internal/workload/configmap with watcher-backed listing/querying, mutations, filtering/sorting, and activity log types.
  • Add GraphQL schema + generated bindings/resolvers, authz checks, watcher/loader registration, DB migration, and integration test coverage.

Reviewed changes

Copilot reviewed 46 out of 48 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
internal/workload/models.go Extends Workload interface with GetConfigs() for configmap usage tracking.
internal/workload/job/models.go Implements GetConfigs() for jobs; tightens GetSecrets() to skip empty refs.
internal/workload/application/models.go Implements GetConfigs() for applications; tightens GetSecrets() to skip empty refs.
internal/workload/configmap/sortfilter.go Adds sort/filter logic for configs, including “in use” filtering via workload references.
internal/workload/configmap/queries.go Implements listing, lookup, CRUD, and value mutations against ConfigMaps via dynamic client + activity logging.
internal/workload/configmap/node.go Registers config nodes with the global ident system (CFG).
internal/workload/configmap/models.go Defines Config models, GraphQL order/filter types, and conversion from K8s objects.
internal/workload/configmap/errors.go Adds GraphQL-friendly domain errors (unmanaged, already exists).
internal/workload/configmap/dataloader.go Registers watcher + loader context for configmaps.
internal/workload/configmap/activitylog.go Registers activity log transformers/filters for config events.
internal/kubernetes/watchers/watchers.go Registers/configures the new ConfigMap watcher in the watcher set.
internal/kubernetes/clientset.go Exports common “last modified” annotation constants used by configmap conversion.
internal/graph/schema/configmap.graphqls Adds GraphQL schema for configs (queries, mutations, connections, activity log types).
internal/graph/gengql/valkey.generated.go Regenerated GraphQL bindings referencing Team.configs / TeamEnvironment.config.
internal/graph/gengql/utilization.generated.go Regenerated GraphQL bindings referencing Team.configs / TeamEnvironment.config.
internal/graph/gengql/teams.generated.go Regenerated bindings for Team/TeamEnvironment/InventoryCounts config fields and resolvers.
internal/graph/gengql/sqlinstance.generated.go Regenerated bindings referencing Team.configs / TeamEnvironment.config.
internal/graph/gengql/serviceaccounts.generated.go Regenerated bindings referencing Team.configs.
internal/graph/gengql/secret.generated.go Regenerated bindings referencing Team.configs / TeamEnvironment.config.
internal/graph/gengql/schema.generated.go Regenerated root schema bindings for config mutations and node unions.
internal/graph/gengql/repository.generated.go Regenerated bindings referencing Team.configs.
internal/graph/gengql/reconcilers.generated.go Regenerated bindings referencing Team.configs.
internal/graph/gengql/postgres.generated.go Regenerated bindings referencing Team.configs / TeamEnvironment.config.
internal/graph/gengql/opensearch.generated.go Regenerated bindings referencing Team.configs / TeamEnvironment.config.
internal/graph/gengql/netpol.generated.go Regenerated bindings referencing Team.configs.
internal/graph/gengql/kafka.generated.go Regenerated bindings referencing Team.configs / TeamEnvironment.config.
internal/graph/gengql/jobs.generated.go Regenerated bindings adding Job.configs field plumbing.
internal/graph/gengql/issues.generated.go Regenerated bindings referencing TeamEnvironment.config and workload configs fields.
internal/graph/gengql/complexity.go Adds GraphQL complexity accounting for config-related connection fields.
internal/graph/gengql/bucket.generated.go Regenerated bindings referencing Team.configs / TeamEnvironment.config.
internal/graph/gengql/bigquery.generated.go Regenerated bindings referencing Team.configs / TeamEnvironment.config.
internal/graph/gengql/applications.generated.go Regenerated bindings adding Application.configs field plumbing.
internal/graph/gengql/alerts.generated.go Regenerated bindings referencing Team.configs / TeamEnvironment.config.
internal/graph/gengql/activitylog.generated.go Regenerated bindings to include config activity log entry types and Config as ActivityLogger.
internal/graph/configmap.resolvers.go Adds resolvers for config fields/mutations and usage relationships (apps/jobs/workloads).
internal/database/migrations/0060_add_config_authorizations.sql Adds DB authorizations + grants for config create/update/delete.
internal/cmd/api/http.go Wires configmap loader context into GraphQL request context.
internal/auth/authz/queries.go Adds authz helper functions for config create/update/delete.
integration_tests/workload_configs.lua Adds integration tests for workload→configs resolution.
integration_tests/k8s_resources/configs/staging/myteam/configmaps.yaml Adds configmap fixtures (managed/unmanaged) for staging.
integration_tests/k8s_resources/configs/staging/myteam/applications.yaml Adds application fixtures using configs via filesFrom.
integration_tests/k8s_resources/configs/dev/myteam/configmaps.yaml Adds configmap fixtures (managed/unmanaged) for dev.
integration_tests/k8s_resources/configs/dev/myteam/applications.yaml Adds application fixtures using configs via envFrom.
integration_tests/configs_cross_team.lua Adds cross-team access control tests for config read vs mutation authz.
integration_tests/configs.lua Adds comprehensive config CRUD/value + activity log integration tests.
.configs/gqlgen.yaml Adds configmap package to gqlgen autobind for schema/model mapping.

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

IsEnvVarName rejects valid ConfigMap keys containing hyphens and dots
(e.g. 'api-url', 'config.file'). IsConfigMapKey validates against
actual Kubernetes ConfigMap key rules and handles length validation
internally.
@frodesundby frodesundby merged commit f275814 into main Mar 18, 2026
10 checks passed
@frodesundby frodesundby deleted the configmap branch March 18, 2026 10:08
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.

4 participants