* makes folder title a selectable field and fixes cyclic import with selectable field utils
* make gofmt
* include metadata.name and metadata.namespace as default selectable fields in BuildGetAttrsFn() for selectable fields
* refactor team members endpoint to work with unistore
* define response and parse results
* make gofmt
* update legacy search to use teamRef for querying
* add unit tests for rest members
* add integration tests
* Add ownerRef to search result
* Remove unneeded test
* feat(search): return owner refs in dashboard search endpoint
- Refs are returned as string array:
`[ "iam.grafana.app/Team/test-team", "iam.grafana.app/User/test-user" ]`
* chore(search): update client and cleanup previous changes
---------
Co-authored-by: Rafael Paulovic <rafael.paulovic@grafana.com>
* Include all known manifests. Initialize SelectableFields in existing builders.
* Move AppManifests to separate file.
* Add code-generation and CI check for app_manifests.go
* Extract common code from custom builders into NewIndexableDocumentFromValue.
* Return error from BuildSelectableFields when object and kind don't match.
* Make title mandatory in spec
* Add mandatory title validation for Connection resources
- Add validation in factory.Validate() to require non-empty title field
- Add unit tests for title validation (with and without title)
- Update all existing tests to include title field in Connection specs
- Fixed 35 connection objects across 4 integration test files
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* Frontend: Use Ready condition instead of state field in ConnectionStatusBadge
Changes the ConnectionStatusBadge component to read the Ready condition
from the Connection status instead of the deprecated state field. This
aligns the frontend with Kubernetes condition patterns.
The badge now:
- Reads the Ready condition (type="Ready") from status.conditions
- Shows "Connected" (green) when Ready condition status is "True"
- Shows "Disconnected" (red) when Ready condition status is "False"
- Shows "Unknown" (grey) when no Ready condition exists
Updated tests to include Ready conditions in mock Connection objects.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Backend: Remove state field from Connection status
Removes the deprecated `state` field from ConnectionStatus in favor of
using the Ready condition directly. This simplifies the status structure
and aligns with Kubernetes patterns.
Changes:
- Remove ConnectionState type and state field from ConnectionStatus
- Remove state field patches from connection controller
- Update CUE schema to remove state field
- Update integration tests to check Ready condition instead of state
- Regenerate backend code and frontend API clients
The Ready condition now serves as the single source of truth for
connection readiness. Frontend already reads from Ready condition
(see parent PR).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Regenerate client
* Format connection_test.go with goimports
* Fix TypeScript error in ConnectionStatusBadge test
Remove state field from mock ConnectionStatus to match the backend API
after state field removal. The state field no longer exists in the
ConnectionStatus type.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* Registration of enterprise only features in operators
* Move more things into lazy loading mode
* Fix some issues with initializing
* Use lazy method for token exchange client
* implement receiver testing domain service
* register the testing service in ngalert service
* declare a new subresource "test" for receiver resource
* implement request handler for integration testing
* integration tests for new endpoint
---------
Co-authored-by: Tito Lins <tito.linsesilva@grafana.com>
* Add quota status in repository status
* Provisioning: Refactor QuotaSetter to QuotaGetter with context
- Rename QuotaSetter interface to QuotaGetter to better reflect retrieval semantics
- Add context and namespace parameters to GetQuotaStatus method for future dynamic implementations
- Update controller to only patch quota status when values change
- Fix missing quotaGetter parameter in repo_operator.go
- Update all tests to use new interface and method signature
This design allows quota fetching to move out of the critical reconciliation path
and supports future per-namespace quota implementations.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Provisioning: Use cfg fields instead of re-reading config in repo_operator
- Replace direct config reads with cfg.ProvisioningAllowImageRendering,
cfg.ProvisioningMinSyncInterval, and cfg.ProvisioningAllowedTargets
- Fixes inconsistent defaults (allow_image_rendering was false, now true;
min_sync_interval was 1m, now 10s as per setting.go)
- Add comment noting operator may move to enterprise for enterprise-specific
quota implementations and dependencies
- Ensures single source of truth for all provisioning config defaults
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Provisioning: Fix config defaults in repo_operator by reading sections
- Change allow_image_rendering default from false to true (matching setting.go)
- Change min_sync_interval default from 1 minute to 10 seconds (matching setting.go)
- Read quota config directly via SectionWithEnvOverrides to follow repo_operator convention
(max_resources_per_repository=0, max_repositories=10)
- Add comments documenting defaults and noting operator may move to enterprise
repository for enterprise-specific quota implementations
All config values now read using the SectionWithEnvOverrides pattern with
consistent defaults matching pkg/setting/setting.go.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Revert defaults for allowImageRendering and minSyncInterval
Keep original defaults (false and 1 minute) as they were in repo_operator.go.
Only add quota config reading via SectionWithEnvOverrides.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* Unified Storage: Remove index_scoring_model config, always use BM25
The index_scoring_model configuration was a temporary option to switch
between TFIDF and BM25 scoring models. This removes the config and
hardcodes BM25 as the scoring model for all bleve indexes.
* Unified Storage: update tests with BM25 scores
* Apps: update go mod and wire
* Create dashboard validator app
- Generate scaffolding
- Create DashboardCompatibilityScore Kind in CUE
* Create app.go file and define app configuration, custom route and basic handler for that route
* Wire dashvalidator app with grafana
* Add 'check' endpoint to manifest, fix issue with grafana core depedencies
* Fix linting
* Fix codeowners
* Fix go workspace
* Add dashvalidator app to Dockerfile for Go workspace validation
* run gen-go
* run again make gen-go
* update go work
* Update dashvalidator go.mod to newest go version and add new directives replacements
- The replacement directives were related to plugins (semconv and
plugins)
- Ran also go mod tidy and make update-workspace
* Fix issue related to go.mod and enterprise
* update workspace with latest changes
* ran make update-workspace
* Gate app with dashboardValidatorApp feature toggle
* Apply pr feedback
* Provisioning: Add max_repositories config setting
- Add ProvisioningMaxRepositories config field to Cfg struct
- Read max_repositories from [provisioning] section (defaults to 0 = unlimited)
- Add maxRepositories field to APIBuilder with SetMaxRepositories HACK method
- Update VerifyAgainstExistingRepositoriesValidator to use configurable limit
- Add MaxRepositories field to RepositoryViewList settings API
- Update settings endpoint to return MaxRepositories
- Add unit tests for unlimited and custom limit scenarios
- Update integration test to verify MaxRepositories field
Follows the same pattern as max_resources_per_repository to avoid
changing factory method signatures.
* Regenerate frontend
* Optimize: Add early return when unlimited repositories
* Add HACK comments for -1 unlimited workaround
* Fix comment: clarify 0 in config means unlimited
* Refactor: Use RepositoryLimits struct instead of SetMaxRepositories
- Create RepositoryLimits struct similar to QuotaLimits
- Replace SetMaxRepositories with SetRepositoryLimits method
- Update validator to use RepositoryLimits struct
- Keep HACK comments explaining the -1 unlimited workaround
* Fix settings endpoint and add integration tests
- Settings endpoint now returns actual config value (not -1 HACK)
- Add integration tests for default (10), unlimited (0), and configured (1000)
- Update testinfra HACK to handle 0 vs not set distinction
- Use RepositoryLimits struct instead of individual setters
* Refactor: Add MaxRepositories to QuotaLimits struct
- Add MaxRepositories field to QuotaLimits instead of separate RepositoryLimits
- Update SetRepositoryLimits to SetQuotaLimits
- Remove separate limits.go file
- Update all references to use QuotaLimits
* Fix comment: SetRepositoryLimits -> SetQuotaLimits
* Refactor: Centralize HACK logic in NewHackyQuota function
- Create NewHackyQuota function to encapsulate repository limit conversion logic
- Move HACK logic (0 -> -1 for unlimited) from register.go to quotas package
- Update register.go to use NewHackyQuota instead of inline conversion
- Add comprehensive tests for NewHackyQuota conversion logic
- Store quotaLimits in APIBuilder struct for reuse across validator and sync worker
- Simplify Validate() method by removing inline HACK logic
* Update NewHackyQuota to default to 10 when maxRepositories is 0
- Change HACK logic: 0 now defaults to 10 instead of converting to -1 (unlimited)
- Update tests to reflect new default behavior
- Update QuotaLimits struct comment to reflect current behavior
- Keep -1 as the way to explicitly set unlimited (used in tests)
* Remove -1 HACK from verify.go, use 0 for unlimited
- Remove -1 HACK check in verify.go, use 0 directly for unlimited
- Update NewHackyQuota to pass through 0 as-is (no conversion)
- Update tests to use 0 instead of -1 for unlimited
- Simplify logic: config defaults to 10, 0 means unlimited
* Update NewHackyQuota to handle -1 → 0, 0 → 10, N → N conversion
- NewHackyQuota now converts: -1 → 0 (unlimited), 0 → 10 (default), N → N
- Update register.go to convert config 0 (unlimited) to -1 before calling NewHackyQuota
- Add test case for -1 → 0 conversion
- Update comments to reflect the conversion logic
* Remove SetMaxResourcesPerRepository from SyncWorker, use quota limits only
- Remove maxResourcesPerRepository field from SyncWorker struct
- Remove SetMaxResourcesPerRepository method
- Remove fallback logic, use quotaLimits directly
- Update tests to use SetQuotaLimits instead of SetMaxResourcesPerRepository
* Replace separate SetMaxRepositories/SetMaxResourcesPerRepository with SetQuotas
- Remove maxResourcesPerRepository and maxRepositories fields from APIBuilder
- Replace SetMaxRepositories and SetMaxResourcesPerRepository with single SetQuotas method
- Update routes.go to use quotaLimits.MaxRepositories
- Consolidate HACK logic into single method
* Remove quotaLimitsSet field from SyncWorker
- Remove quotaLimitsSet tracking field
- Update routes.go to use quotaLimits.MaxRepositories directly
- Simplify SetQuotaLimits method
* Fix routes.go to use quotaLimits.MaxRepositories
* Remove comment from routes.go
* Remove HACK comments from testinfra.go
* Format and lint code
* Fix linting issues: use switch statement and fix formatting
* Provisioning: Add granular condition reasons for Connection Controller
This change enhances the Ready condition on Connection resources by adding
granular reasons that distinguish between different types of failures,
enabling better automation and user guidance.
**New Condition Reasons:**
1. **`InvalidConfiguration`**: Configuration issue with spec format or
structure (validation errors, invalid fields, secret errors). User must
fix configuration. Automation should NOT retry.
2. **`AuthenticationFailed`**: Authentication or authorization failed
(invalid credentials, wrong app ID, expired token, insufficient
permissions). User must fix credentials. Automation should NOT retry.
3. **`ServiceUnavailable`**: External service issue (API down, network
timeout). Issue is transient and outside user control. Automation CAN
retry with standard backoff.
4. **`RateLimited`**: External service is rate limiting requests. User may
need to take action (upgrade plan, reduce load). Automation should retry
with longer backoff and respect Retry-After headers.
**Error Classification Logic:**
HTTP status codes are mapped to condition reasons:
- 422 (validation), 500/502 (secret/build) → InvalidConfiguration
- 400/401/403 (auth errors) → AuthenticationFailed
- 503/504 (service unavailable) → ServiceUnavailable
- 429 (rate limit) → RateLimited
- Unknown errors → InvalidConfiguration (safer, prompts investigation)
**Benefits:**
- **kubectl users**: Distinguish auth failures from config issues at a glance
- **Automation**: Implement appropriate retry logic per reason type
- **UI**: Provide actionable guidance based on specific failure reason
- **Stability**: Reasons align with Kubernetes CRD conventions and can be
extended in the future without breaking changes
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Provisioning: Extract actual HTTP status codes from GitHub API errors
This commit updates the GitHub connection implementation to extract and return
actual HTTP status codes from GitHub API responses, enabling proper error
classification in the connection controller's Ready condition.
Changes:
1. **GitHub Client (client.go)**:
- Added sentinel errors for common HTTP status codes:
- ErrUnauthorized (401): Authentication failed
- ErrForbidden (403): Access forbidden
- ErrRateLimited (429): Rate limited
- ErrServiceUnavailable (503): GitHub unavailable
- Added extractHTTPError() to map GitHub ErrorResponse status codes to sentinel errors
- Updated all client methods to use extractHTTPError()
2. **GitHub Connection (connection.go)**:
- Updated Test() method to extract HTTP status codes from sentinel errors
- Maps errors to appropriate status codes in TestResults:
- 401/403 → ReasonAuthenticationFailed
- 429 → ReasonRateLimited
- 503 → ReasonServiceUnavailable
- Default to 400 for unknown errors
3. **API Constants (health.go)**:
- Renamed ReasonInvalidConfiguration → ReasonInvalidSpec
4. **Tests**:
- Added tests for 401, 403, and 429 error scenarios in connection_test.go
- Updated test expectations to match new behavior
- All unit and integration tests pass
This enables the connection controller to properly classify GitHub API errors
and set the appropriate Ready condition reason (InvalidSpec, AuthenticationFailed,
ServiceUnavailable, or RateLimited) based on the actual HTTP status code returned
by the GitHub API.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Revert "Provisioning: Extract actual HTTP status codes from GitHub API errors"
This reverts commit b13b2c323e.
* Provisioning: Add ErrAuthentication for GitHub connection error detection
This commit adds a specific authentication error sentinel in the GitHub
connection package to distinguish authentication failures from other errors.
Changes:
1. **GitHub Client (client.go)**:
- Added ErrAuthentication sentinel error for 401/403 responses
- Updated GetApp() and GetAppInstallation() to check for 401/403 status codes
- Returns ErrAuthentication when GitHub API returns authentication errors
2. **GitHub Connection (connection.go)**:
- Updated Test() method to check for ErrAuthentication
- Returns 401 (Unauthorized) when authentication fails
- Returns 422 (Unprocessable Entity) for generic/spec errors instead of 400
- Returns 503 (Service Unavailable) when GitHub is down
3. **Connection Health Controller (connection_health.go)**:
- Simplified classification logic to only handle actual error codes:
- 401/403 → AuthenticationFailed
- 503 → ServiceUnavailable
- Everything else → InvalidConfiguration (default)
- Removed RateLimited classification (not currently detected)
4. **Tests**:
- Updated connection tests to expect 422 instead of 400 for generic errors
- Added test for authentication error (401) scenario
- Updated classification tests to match simplified logic
- All unit and integration tests pass
This enables proper detection of authentication errors while keeping the
classification logic simple and aligned with what the GitHub connection
actually returns.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Provisioning: Rename ReasonInvalidConfiguration to ReasonInvalidSpec
This commit renames the condition reason constant from ReasonInvalidConfiguration
to ReasonInvalidSpec for better alignment with Kubernetes naming conventions.
Changes:
1. **API Constants (health.go)**:
- Renamed ReasonInvalidConfiguration → ReasonInvalidSpec
- Updated constant value from "InvalidConfiguration" to "InvalidSpec"
2. **Updated all references across codebase**:
- Controller files (connection_health.go, conditions.go)
- Unit tests (connection_health_test.go, conditions_test.go, health_test.go)
- Integration tests (connection_test.go)
3. **Fixed integration test expectations**:
- Invalid installation ID test now expects ReasonInvalidSpec (not AuthenticationFailed)
- Invalid app ID mismatch test now expects ReasonInvalidSpec (not AuthenticationFailed)
- These are configuration errors, not authentication errors
All tests pass with the new naming.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* Provisioning: Add Quota condition to track repository resource limits
Add an aggregated Quota condition to Repository status that tracks when
repositories exceed configured quota limits. This provides visibility into
resource usage without affecting repository health/Ready status.
Key changes:
- Add ConditionTypeQuota and reason constants (WithinQuota, QuotaUnlimited,
ResourceQuotaReached, ResourceQuotaExceeded)
- Add max_resources_per_repository setting (0 = unlimited by default)
- Update sync worker to set Quota condition after stats update
- Add unit tests for BuildQuotaCondition and integration tests
The design is extensible for future quota types (storage, API rate limits, etc.).
* Refactor: Move quota evaluation to dedicated quotas package
Move QuotaLimits and quota evaluation logic from controller package to
a new apps/provisioning/pkg/quotas package. This improves separation of
concerns and makes the quota logic reusable.
Changes:
- Create apps/provisioning/pkg/quotas package with QuotaLimits struct
- Move BuildQuotaCondition to QuotaLimits.EvaluateCondition method
- Move quota unit tests to quotas package
- Update sync worker to use new quotas package
- Add comment explaining why quotas are evaluated in sync worker
(pull) rather than controller: sync worker performs reconciliation,
cleans up resources, and updates stats, making it the natural place
to evaluate quotas against actual resource state.
* HACK: Use setter method for maxResourcesPerRepository to avoid changing NewAPIBuilder
Avoid changing NewAPIBuilder signature by using SetMaxResourcesPerRepository
setter method. This prevents requiring changes in the enterprise repository.
This should be moved to NewAPIBuilder parameters once we can coordinate
the change across repositories.
* HACK: Add NewSyncWorkerWithoutQuotaLimit helper for enterprise compatibility
Add NewSyncWorkerWithoutQuotaLimit helper function to maintain backward
compatibility with enterprise code that hasn't been updated to pass
maxResourcesPerRepository parameter. Enterprise code should be updated
to use NewSyncWorker with the maxResourcesPerRepository parameter.
This function should be removed once enterprise code is updated.
* HACK: Use setter method for maxResourcesPerRepository in SyncWorker
Avoid changing NewSyncWorker signature by using SetMaxResourcesPerRepository
setter method. This prevents requiring changes in the enterprise repository.
This should be moved to NewSyncWorker parameters once we can coordinate
the change across repositories.
* Provisioning: bound Repo and Connection token update to controller resync interval
* fixing test for mysql and postgres
* unskipping test
* addressing comments
* addressing comments
* fixing unit tests