From a2d6098be3b1ea664ab07f45afd0d16f2b390709 Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Sat, 4 Apr 2026 21:48:47 +0530 Subject: [PATCH 01/30] feat: make executor event handling timeout configurable --- internal/engine/handler.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/engine/handler.go b/internal/engine/handler.go index 3a00ec7599..a6d5354e83 100644 --- a/internal/engine/handler.go +++ b/internal/engine/handler.go @@ -37,6 +37,7 @@ type ExecutorEventHandler struct { handlerMiddleware []message.HandlerMiddleware wgEntityEventExecution *sync.WaitGroup executor Executor + executionTimeout time.Duration // cancels are a set of cancel functions for current entity events in flight. // This allows us to cancel rule evaluation directly when terminationContext // is cancelled. @@ -56,6 +57,7 @@ func NewExecutorEventHandler( wgEntityEventExecution: &sync.WaitGroup{}, handlerMiddleware: handlerMiddleware, executor: executor, + executionTimeout: DefaultExecutionTimeout, } go func() { <-ctx.Done() @@ -115,7 +117,7 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { time.Sleep(ArtifactSignatureWaitPeriod) } - ctx, cancel := context.WithTimeout(msgCtx, DefaultExecutionTimeout) + ctx, cancel := context.WithTimeout(msgCtx, e.executionTimeout) defer cancel() defer func() { e.lock.Lock() From bafd7a1952915ffc65968b35687312ebcea44d2b Mon Sep 17 00:00:00 2001 From: Evan Anderson Date: Thu, 2 Apr 2026 07:33:50 -0700 Subject: [PATCH 02/30] Add VEX / ignore mitigations for CVE-2026-34040 (#6243) * Add VEX / ignore mitigations for CVE-2026-34040 * Update Trivy action to work with code scanning --- .github/workflows/security.yml | 22 +++++++++++++++++++++ .trivy.yml | 1 + .trivyignore.yaml | 7 +++---- .vex/minder.openvex.json | 36 ++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 .vex/minder.openvex.json diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 3df136d0cc..87cf13ad69 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -11,6 +11,9 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Make results directory + run: mkdir -p ../results + - name: Code Security Scan uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 with: @@ -19,21 +22,40 @@ jobs: trivy-config: .trivy.yml exit-code: 1 ignore-unfixed: true + trivyignores: .trivyignore.yaml + format: sarif + output: code-results.sarif env: TRIVY_DB_REPOSITORY: ghcr.io/aquasecurity/trivy-db,public.ecr.aws/aquasecurity/trivy-db TRIVY_USERNAME: ${{ github.actor }} TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} + - name: Upload Trivy scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: code-results.sarif + category: code-scan + - name: Helm Security Scan uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0 if: always() with: + skip-setup-trivy: true scan-type: 'config' trivy-config: .trivy.yml exit-code: 1 ignore-unfixed: true scan-ref: ./deployment/helm + format: sarif + output: helm-results.sarif env: TRIVY_DB_REPOSITORY: ghcr.io/aquasecurity/trivy-db,public.ecr.aws/aquasecurity/trivy-db TRIVY_USERNAME: ${{ github.actor }} TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload Trivy scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: helm-results.sarif + category: infra-scan + \ No newline at end of file diff --git a/.trivy.yml b/.trivy.yml index 004dd491fa..db8f2cfe09 100644 --- a/.trivy.yml +++ b/.trivy.yml @@ -15,3 +15,4 @@ scan: - docs/ - ".cache/trivy/" - internal/engine/ingester/deps/testdata/ + - examples/rules-and-profiles/ diff --git a/.trivyignore.yaml b/.trivyignore.yaml index c1bef9a652..245fbc0bee 100644 --- a/.trivyignore.yaml +++ b/.trivyignore.yaml @@ -1,5 +1,4 @@ vulnerabilities: - - id: CVE-2024-42473 - # We actually use go-tuf v2. v0.7.0 (which is vulnerable) is merely - # a transitive dependency and we're not affected by the CVE. - - id: CVE-2024-47534 + # Fixed only in github.com/moby/moby, but requires a migration from github.com/docker/docker. + # The actual vulnerability is in AuthZ plugins, which Minder does not implement or build. + - id: CVE-2026-34040 diff --git a/.vex/minder.openvex.json b/.vex/minder.openvex.json new file mode 100644 index 0000000000..1ff9654b3b --- /dev/null +++ b/.vex/minder.openvex.json @@ -0,0 +1,36 @@ +{ + "@context": "https://openvex.dev/ns/v0.2.0", + "@id": "pkg:golang/github.com/mindersec/minder", + "author": "Evan Anderson", + "created": "2026-04-01T18:43:05Z", + "version": 1, + "statements": [ + { + "vulnerability": { + "name": "CVE-2026-34040", + "description": "Moby has AuthZ plugin bypass when provided oversized request bodies.", + "aliases": [ + "GHSA-x744-4wpc-v9h2", + "CVE-2026-34040" + ] + }, + "status": "not_affected", + "justification": "vulnerable_code_not_in_execute_path", + "impact_statement": "Minder does not build or use Docker API Authz plugins.", + "products": [ + { + "@id": "pkg:golang/github.com/mindersec/minder", + "identifiers": { + "purl": "pkg:golang/github.com/mindersec/minder" + } + }, + { + "@id": "pkg:golang/github.com/mindersec/minder/tools", + "identifiers": { + "purl": "pkg:golang/github.com/mindersec/minder/tools" + } + } + ] + } + ] +} \ No newline at end of file From adcaff8c1a8cc6939dbd6fb9ed7d012a3e686985 Mon Sep 17 00:00:00 2001 From: Daksh Pathak Date: Fri, 3 Apr 2026 00:40:38 +0530 Subject: [PATCH 03/30] =?UTF-8?q?feat(inventory):=20add=20evaluation=5Fout?= =?UTF-8?q?puts=20table=20for=20persisting=20structur=E2=80=A6=20(#6211)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(inventory): add evaluation_outputs table for persisting structured eval data Implements Phase 1 of the Inventory Gathering feature (Issues #6192 and #6105). Changes: - Add evaluation_outputs table via migration 000116 - Add sqlc queries: InsertEvaluationOutput, GetEvaluationOutput, DeleteEvaluationOutputsByEvaluationIDs - Extend StoreEvaluationStatus to accept and persist structured output - Regenerate sqlc models, querier interface, and mocks Signed-off-by: daksh.pathak.ug24@nsut.ac.in * Update database/query/eval_outputs.sql Co-authored-by: Evan Anderson * chore(gen): run make gen for eval-outputs * Address PR review feedback: fix eval outputs error handling and sql param --------- Signed-off-by: daksh.pathak.ug24@nsut.ac.in Co-authored-by: Evan Anderson --- .../000116_evaluation_outputs.down.sql | 8 +++ .../000116_evaluation_outputs.up.sql | 16 +++++ database/mock/store.go | 44 ++++++++++++ database/query/eval_outputs.sql | 24 +++++++ internal/db/eval_outputs.sql.go | 69 +++++++++++++++++++ internal/db/models.go | 6 ++ internal/db/querier.go | 5 ++ internal/engine/eval_status.go | 6 ++ internal/engine/executor_test.go | 2 +- internal/history/mock/service.go | 8 +-- internal/history/service.go | 21 +++++- internal/history/service_test.go | 2 +- 12 files changed, 204 insertions(+), 7 deletions(-) create mode 100644 database/migrations/000116_evaluation_outputs.down.sql create mode 100644 database/migrations/000116_evaluation_outputs.up.sql create mode 100644 database/query/eval_outputs.sql create mode 100644 internal/db/eval_outputs.sql.go diff --git a/database/migrations/000116_evaluation_outputs.down.sql b/database/migrations/000116_evaluation_outputs.down.sql new file mode 100644 index 0000000000..c38540a39f --- /dev/null +++ b/database/migrations/000116_evaluation_outputs.down.sql @@ -0,0 +1,8 @@ +-- SPDX-FileCopyrightText: Copyright 2026 The Minder Authors +-- SPDX-License-Identifier: Apache-2.0 + +BEGIN; + +DROP TABLE IF EXISTS evaluation_outputs; + +COMMIT; diff --git a/database/migrations/000116_evaluation_outputs.up.sql b/database/migrations/000116_evaluation_outputs.up.sql new file mode 100644 index 0000000000..22d3ecc10f --- /dev/null +++ b/database/migrations/000116_evaluation_outputs.up.sql @@ -0,0 +1,16 @@ +-- SPDX-FileCopyrightText: Copyright 2026 The Minder Authors +-- SPDX-License-Identifier: Apache-2.0 + +BEGIN; + +-- evaluation_outputs stores structured output and debug text from rule +-- evaluations. It is keyed as a child of evaluation_statuses so that +-- output data can be retained/purged independently of the compact +-- status rows. +CREATE TABLE evaluation_outputs ( + id UUID NOT NULL REFERENCES evaluation_statuses(id) ON DELETE CASCADE PRIMARY KEY, + output JSONB, + debug TEXT +); + +COMMIT; diff --git a/database/mock/store.go b/database/mock/store.go index 8de7c82c5a..80ececc10b 100644 --- a/database/mock/store.go +++ b/database/mock/store.go @@ -549,6 +549,21 @@ func (mr *MockStoreMockRecorder) DeleteEvaluationHistoryByIDs(ctx, evaluationids return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEvaluationHistoryByIDs", reflect.TypeOf((*MockStore)(nil).DeleteEvaluationHistoryByIDs), ctx, evaluationids) } +// DeleteEvaluationOutputsByEvaluationIDs mocks base method. +func (m *MockStore) DeleteEvaluationOutputsByEvaluationIDs(ctx context.Context, evaluationids []uuid.UUID) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteEvaluationOutputsByEvaluationIDs", ctx, evaluationids) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteEvaluationOutputsByEvaluationIDs indicates an expected call of DeleteEvaluationOutputsByEvaluationIDs. +func (mr *MockStoreMockRecorder) DeleteEvaluationOutputsByEvaluationIDs(ctx, evaluationids any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEvaluationOutputsByEvaluationIDs", reflect.TypeOf((*MockStore)(nil).DeleteEvaluationOutputsByEvaluationIDs), ctx, evaluationids) +} + // DeleteExpiredSessionStates mocks base method. func (m *MockStore) DeleteExpiredSessionStates(ctx context.Context) (int64, error) { m.ctrl.T.Helper() @@ -1091,6 +1106,21 @@ func (mr *MockStoreMockRecorder) GetEvaluationHistory(ctx, arg any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEvaluationHistory", reflect.TypeOf((*MockStore)(nil).GetEvaluationHistory), ctx, arg) } +// GetEvaluationOutput mocks base method. +func (m *MockStore) GetEvaluationOutput(ctx context.Context, id uuid.UUID) (db.EvaluationOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEvaluationOutput", ctx, id) + ret0, _ := ret[0].(db.EvaluationOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetEvaluationOutput indicates an expected call of GetEvaluationOutput. +func (mr *MockStoreMockRecorder) GetEvaluationOutput(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEvaluationOutput", reflect.TypeOf((*MockStore)(nil).GetEvaluationOutput), ctx, id) +} + // GetFeatureInProject mocks base method. func (m *MockStore) GetFeatureInProject(ctx context.Context, arg db.GetFeatureInProjectParams) (json.RawMessage, error) { m.ctrl.T.Helper() @@ -2386,6 +2416,20 @@ func (mr *MockStoreMockRecorder) UpsertBundle(ctx, arg any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertBundle", reflect.TypeOf((*MockStore)(nil).UpsertBundle), ctx, arg) } +// UpsertEvaluationOutput mocks base method. +func (m *MockStore) UpsertEvaluationOutput(ctx context.Context, arg db.UpsertEvaluationOutputParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpsertEvaluationOutput", ctx, arg) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpsertEvaluationOutput indicates an expected call of UpsertEvaluationOutput. +func (mr *MockStoreMockRecorder) UpsertEvaluationOutput(ctx, arg any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertEvaluationOutput", reflect.TypeOf((*MockStore)(nil).UpsertEvaluationOutput), ctx, arg) +} + // UpsertInstallationID mocks base method. func (m *MockStore) UpsertInstallationID(ctx context.Context, arg db.UpsertInstallationIDParams) (db.ProviderGithubAppInstallation, error) { m.ctrl.T.Helper() diff --git a/database/query/eval_outputs.sql b/database/query/eval_outputs.sql new file mode 100644 index 0000000000..67fd15ad98 --- /dev/null +++ b/database/query/eval_outputs.sql @@ -0,0 +1,24 @@ +-- SPDX-FileCopyrightText: Copyright 2026 The Minder Authors +-- SPDX-License-Identifier: Apache-2.0 + +-- name: UpsertEvaluationOutput :exec +INSERT INTO evaluation_outputs( + id, + output, + debug +) VALUES ( + $1, + sqlc.arg(output)::jsonb, + sqlc.narg(debug) +) +ON CONFLICT (id) DO UPDATE +SET output = COALESCE(sqlc.arg(output)::jsonb, evaluation_outputs.output), + debug = COALESCE(sqlc.narg(debug), evaluation_outputs.debug); + +-- name: GetEvaluationOutput :one +SELECT * FROM evaluation_outputs +WHERE id = $1; + +-- name: DeleteEvaluationOutputsByEvaluationIDs :execrows +DELETE FROM evaluation_outputs +WHERE id = ANY(sqlc.slice(evaluationIds)::uuid[]); diff --git a/internal/db/eval_outputs.sql.go b/internal/db/eval_outputs.sql.go new file mode 100644 index 0000000000..48fa6c1229 --- /dev/null +++ b/internal/db/eval_outputs.sql.go @@ -0,0 +1,69 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: eval_outputs.sql + +package db + +import ( + "context" + "database/sql" + "encoding/json" + + "github.com/google/uuid" + "github.com/lib/pq" +) + +const deleteEvaluationOutputsByEvaluationIDs = `-- name: DeleteEvaluationOutputsByEvaluationIDs :execrows +DELETE FROM evaluation_outputs +WHERE id = ANY($1::uuid[]) +` + +func (q *Queries) DeleteEvaluationOutputsByEvaluationIDs(ctx context.Context, evaluationids []uuid.UUID) (int64, error) { + result, err := q.db.ExecContext(ctx, deleteEvaluationOutputsByEvaluationIDs, pq.Array(evaluationids)) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + +const getEvaluationOutput = `-- name: GetEvaluationOutput :one +SELECT id, output, debug FROM evaluation_outputs +WHERE id = $1 +` + +func (q *Queries) GetEvaluationOutput(ctx context.Context, id uuid.UUID) (EvaluationOutput, error) { + row := q.db.QueryRowContext(ctx, getEvaluationOutput, id) + var i EvaluationOutput + err := row.Scan(&i.ID, &i.Output, &i.Debug) + return i, err +} + +const upsertEvaluationOutput = `-- name: UpsertEvaluationOutput :exec + +INSERT INTO evaluation_outputs( + id, + output, + debug +) VALUES ( + $1, + $2::jsonb, + $3 +) +ON CONFLICT (id) DO UPDATE +SET output = COALESCE($2::jsonb, evaluation_outputs.output), + debug = COALESCE($3, evaluation_outputs.debug) +` + +type UpsertEvaluationOutputParams struct { + ID uuid.UUID `json:"id"` + Output json.RawMessage `json:"output"` + Debug sql.NullString `json:"debug"` +} + +// SPDX-FileCopyrightText: Copyright 2026 The Minder Authors +// SPDX-License-Identifier: Apache-2.0 +func (q *Queries) UpsertEvaluationOutput(ctx context.Context, arg UpsertEvaluationOutputParams) error { + _, err := q.db.ExecContext(ctx, upsertEvaluationOutput, arg.ID, arg.Output, arg.Debug) + return err +} diff --git a/internal/db/models.go b/internal/db/models.go index 215654cdaf..70d8df5caf 100644 --- a/internal/db/models.go +++ b/internal/db/models.go @@ -540,6 +540,12 @@ type EntityProfile struct { Migrated bool `json:"migrated"` } +type EvaluationOutput struct { + ID uuid.UUID `json:"id"` + Output pqtype.NullRawMessage `json:"output"` + Debug sql.NullString `json:"debug"` +} + type EvaluationRuleEntity struct { ID uuid.UUID `json:"id"` RuleID uuid.UUID `json:"rule_id"` diff --git a/internal/db/querier.go b/internal/db/querier.go index e822ad5033..5c6286796f 100644 --- a/internal/db/querier.go +++ b/internal/db/querier.go @@ -63,6 +63,7 @@ type Querier interface { // DeleteEntity removes an entity from the entity_instances table for a project. DeleteEntity(ctx context.Context, arg DeleteEntityParams) error DeleteEvaluationHistoryByIDs(ctx context.Context, evaluationids []uuid.UUID) (int64, error) + DeleteEvaluationOutputsByEvaluationIDs(ctx context.Context, evaluationids []uuid.UUID) (int64, error) DeleteExpiredSessionStates(ctx context.Context) (int64, error) DeleteInstallationIDByAppID(ctx context.Context, appInstallationID int64) error // DeleteInvitation deletes an invitation by its code. This is intended to be @@ -122,6 +123,7 @@ type Querier interface { // GetEntityByName retrieves an entity by its name for a project or hierarchy of projects. GetEntityByName(ctx context.Context, arg GetEntityByNameParams) (EntityInstance, error) GetEvaluationHistory(ctx context.Context, arg GetEvaluationHistoryParams) (GetEvaluationHistoryRow, error) + GetEvaluationOutput(ctx context.Context, id uuid.UUID) (EvaluationOutput, error) // GetFeatureInProject verifies if a feature is available for a specific project. // It returns the settings for the feature if it is available. GetFeatureInProject(ctx context.Context, arg GetFeatureInProjectParams) (json.RawMessage, error) @@ -278,6 +280,9 @@ type Querier interface { // SPDX-License-Identifier: Apache-2.0 // Bundles -- UpsertBundle(ctx context.Context, arg UpsertBundleParams) error + // SPDX-FileCopyrightText: Copyright 2026 The Minder Authors + // SPDX-License-Identifier: Apache-2.0 + UpsertEvaluationOutput(ctx context.Context, arg UpsertEvaluationOutputParams) error UpsertInstallationID(ctx context.Context, arg UpsertInstallationIDParams) (ProviderGithubAppInstallation, error) UpsertLatestEvaluationStatus(ctx context.Context, arg UpsertLatestEvaluationStatusParams) error UpsertProfileForEntity(ctx context.Context, arg UpsertProfileForEntityParams) (EntityProfile, error) diff --git a/internal/engine/eval_status.go b/internal/engine/eval_status.go index 5e56cf0294..5e7d16bc08 100644 --- a/internal/engine/eval_status.go +++ b/internal/engine/eval_status.go @@ -114,6 +114,11 @@ func (e *executor) createOrUpdateEvalStatus( logger.Err(err).Msg("error marshalling checkpoint") } + var evalOutput any + if res := params.GetEvalResult(); res != nil { + evalOutput = res.Output + } + // Log result in the evaluation history tables err = e.querier.WithTransactionErr(func(qtx db.ExtendQuerier) error { evalID, err := e.historyService.StoreEvaluationStatus( @@ -125,6 +130,7 @@ func (e *executor) createOrUpdateEvalStatus( params.EntityID, params.GetEvalErr(), chkpjs, + evalOutput, ) if err != nil { return err diff --git a/internal/engine/executor_test.go b/internal/engine/executor_test.go index c274e9f64b..ee671ea848 100644 --- a/internal/engine/executor_test.go +++ b/internal/engine/executor_test.go @@ -150,7 +150,7 @@ func TestExecutor_handleEntityEvent(t *testing.T) { historyService := mockhistory.NewMockEvaluationHistoryService(ctrl) historyService.EXPECT(). StoreEvaluationStatus( - gomock.Any(), gomock.Any(), ruleInstanceID, profileID, db.EntitiesRepository, repositoryID, gomock.Any(), gomock.Any()). + gomock.Any(), gomock.Any(), ruleInstanceID, profileID, db.EntitiesRepository, repositoryID, gomock.Any(), gomock.Any(), gomock.Any()). Return(evaluationID, nil) mockStore.EXPECT(). diff --git a/internal/history/mock/service.go b/internal/history/mock/service.go index 04cff7026b..4ff33fcbf2 100644 --- a/internal/history/mock/service.go +++ b/internal/history/mock/service.go @@ -59,16 +59,16 @@ func (mr *MockEvaluationHistoryServiceMockRecorder) ListEvaluationHistory(ctx, q } // StoreEvaluationStatus mocks base method. -func (m *MockEvaluationHistoryService) StoreEvaluationStatus(ctx context.Context, qtx db.Querier, ruleID, profileID uuid.UUID, entityType db.Entities, entityID uuid.UUID, evalError error, marshaledCheckpoint []byte) (uuid.UUID, error) { +func (m *MockEvaluationHistoryService) StoreEvaluationStatus(ctx context.Context, qtx db.Querier, ruleID, profileID uuid.UUID, entityType db.Entities, entityID uuid.UUID, evalError error, marshaledCheckpoint []byte, output any) (uuid.UUID, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StoreEvaluationStatus", ctx, qtx, ruleID, profileID, entityType, entityID, evalError, marshaledCheckpoint) + ret := m.ctrl.Call(m, "StoreEvaluationStatus", ctx, qtx, ruleID, profileID, entityType, entityID, evalError, marshaledCheckpoint, output) ret0, _ := ret[0].(uuid.UUID) ret1, _ := ret[1].(error) return ret0, ret1 } // StoreEvaluationStatus indicates an expected call of StoreEvaluationStatus. -func (mr *MockEvaluationHistoryServiceMockRecorder) StoreEvaluationStatus(ctx, qtx, ruleID, profileID, entityType, entityID, evalError, marshaledCheckpoint any) *gomock.Call { +func (mr *MockEvaluationHistoryServiceMockRecorder) StoreEvaluationStatus(ctx, qtx, ruleID, profileID, entityType, entityID, evalError, marshaledCheckpoint, output any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreEvaluationStatus", reflect.TypeOf((*MockEvaluationHistoryService)(nil).StoreEvaluationStatus), ctx, qtx, ruleID, profileID, entityType, entityID, evalError, marshaledCheckpoint) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreEvaluationStatus", reflect.TypeOf((*MockEvaluationHistoryService)(nil).StoreEvaluationStatus), ctx, qtx, ruleID, profileID, entityType, entityID, evalError, marshaledCheckpoint, output) } diff --git a/internal/history/service.go b/internal/history/service.go index 25653cfa0f..3004f02380 100644 --- a/internal/history/service.go +++ b/internal/history/service.go @@ -7,11 +7,13 @@ package history import ( "context" "database/sql" + "encoding/json" "errors" "fmt" "slices" "github.com/google/uuid" + "github.com/rs/zerolog" "github.com/mindersec/minder/internal/db" evalerrors "github.com/mindersec/minder/internal/engine/errors" @@ -24,7 +26,9 @@ import ( // EvaluationHistoryService contains methods to add/query data in the history table. type EvaluationHistoryService interface { // StoreEvaluationStatus stores the result of this evaluation in the history table. - // Returns the UUID of the evaluation status, and the UUID of the rule-entity + // Returns the UUID of the evaluation status, and the UUID of the rule-entity. + // If output is non-nil, it is JSON-encoded and persisted in the evaluation_outputs table. + // output should be a Go struct suitable for JSON encoding. StoreEvaluationStatus( ctx context.Context, qtx db.Querier, @@ -34,6 +38,7 @@ type EvaluationHistoryService interface { entityID uuid.UUID, evalError error, marshaledCheckpoint []byte, + output any, ) (uuid.UUID, error) // ListEvaluationHistory returns a list of evaluations stored // in the history table. @@ -83,6 +88,7 @@ func (e *evaluationHistoryService) StoreEvaluationStatus( entityID uuid.UUID, evalError error, marshaledCheckpoint []byte, + output any, ) (uuid.UUID, error) { var ruleEntityID uuid.UUID status := evalerrors.ErrorAsEvalStatus(evalError) @@ -122,6 +128,19 @@ func (e *evaluationHistoryService) StoreEvaluationStatus( return uuid.Nil, fmt.Errorf("error while creating new evaluation status for rule/entity %s: %w", ruleEntityID, err) } + // Persist structured output if provided + if output != nil { + outputJSON, err := json.Marshal(output) + if err != nil { + zerolog.Ctx(ctx).Error().Err(err).Msg("failed to convert rule output to JSON") + } else if err := qtx.UpsertEvaluationOutput(ctx, db.UpsertEvaluationOutputParams{ + ID: evaluationID, + Output: outputJSON, + }); err != nil { + return evaluationID, fmt.Errorf("error storing extended output for rule/entity %s: %w", ruleEntityID, err) + } + } + return evaluationID, nil } diff --git a/internal/history/service_test.go b/internal/history/service_test.go index 8c65cb3e69..f9df6d9983 100644 --- a/internal/history/service_test.go +++ b/internal/history/service_test.go @@ -110,7 +110,7 @@ func TestStoreEvaluationStatus(t *testing.T) { // provider manager is not used by this function service := NewEvaluationHistoryService(nil) id, err := service.StoreEvaluationStatus( - ctx, store, ruleID, profileID, scenario.EntityType, entityID, errTest, []byte("{}")) + ctx, store, ruleID, profileID, scenario.EntityType, entityID, errTest, []byte("{}"), nil) if scenario.ExpectedError == "" { require.Equal(t, evaluationID, id) require.NoError(t, err) From 327e7a37f5790bd899274b98c1a7a65d71368e99 Mon Sep 17 00:00:00 2001 From: Daksh Pathak Date: Fri, 3 Apr 2026 05:50:22 +0530 Subject: [PATCH 04/30] test(projects/features): add unit tests for feature flag helpers (#6246) --- internal/projects/features/features_test.go | 105 ++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 internal/projects/features/features_test.go diff --git a/internal/projects/features/features_test.go b/internal/projects/features/features_test.go new file mode 100644 index 0000000000..df1f50379f --- /dev/null +++ b/internal/projects/features/features_test.go @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: Copyright 2026 The Minder Authors +// SPDX-License-Identifier: Apache-2.0 + +package features + +import ( + "context" + "database/sql" + "testing" + + "github.com/google/uuid" + "go.uber.org/mock/gomock" + + mockdb "github.com/mindersec/minder/database/mock" + "github.com/mindersec/minder/internal/db" +) + +func TestProjectAllowsPrivateRepos(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + sqlData []byte + sqlErr error + want bool + }{ + { + name: "enabled", + sqlData: []byte(`{}`), + want: true, + }, + { + name: "disabled when feature not found", + sqlErr: sql.ErrNoRows, + want: false, + }, + { + name: "disabled on store error", + sqlErr: sql.ErrConnDone, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + store := mockdb.NewMockStore(ctrl) + projectID := uuid.New() + store.EXPECT(). + GetFeatureInProject(gomock.Any(), gomock.Any()). + Return(tt.sqlData, tt.sqlErr) + if got := ProjectAllowsPrivateRepos(context.Background(), store, projectID); got != tt.want { + t.Errorf("ProjectAllowsPrivateRepos() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestProjectAllowsProjectHierarchyOperations(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + sqlData []byte + sqlErr error + want bool + }{ + { + name: "enabled", + sqlData: []byte(`{}`), + want: true, + }, + { + name: "disabled when feature not found", + sqlErr: sql.ErrNoRows, + want: false, + }, + { + name: "disabled on store error", + sqlErr: sql.ErrConnDone, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + store := mockdb.NewMockStore(ctrl) + projectID := uuid.New() + store.EXPECT(). + GetFeatureInProject(gomock.Any(), db.GetFeatureInProjectParams{ + ProjectID: projectID, + Feature: projectHierarchyOperationsEnabledFlag, + }). + Return(tt.sqlData, tt.sqlErr) + if got := ProjectAllowsProjectHierarchyOperations(context.Background(), store, projectID); got != tt.want { + t.Errorf("ProjectAllowsProjectHierarchyOperations() = %v, want %v", got, tt.want) + } + }) + } +} From d3da8bf3ed6c472889bc105cb9924c1738c16b7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 21:02:37 -0700 Subject: [PATCH 05/30] build(deps): bump github.com/go-jose/go-jose/v4 from 4.1.3 to 4.1.4 (#6259) Bumps [github.com/go-jose/go-jose/v4](https://github.com/go-jose/go-jose) from 4.1.3 to 4.1.4. - [Release notes](https://github.com/go-jose/go-jose/releases) - [Commits](https://github.com/go-jose/go-jose/compare/v4.1.3...v4.1.4) --- updated-dependencies: - dependency-name: github.com/go-jose/go-jose/v4 dependency-version: 4.1.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f7340994fd..08328d1c37 100644 --- a/go.mod +++ b/go.mod @@ -197,7 +197,7 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-chi/chi/v5 v5.2.5 // indirect - github.com/go-jose/go-jose/v4 v4.1.3 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/swag/cmdutils v0.25.4 // indirect github.com/go-openapi/swag/conv v0.25.5 // indirect diff --git a/go.sum b/go.sum index 71d8410cae..647197e2ab 100644 --- a/go.sum +++ b/go.sum @@ -460,8 +460,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= -github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= From 15daf07933c60dd950ba75fea585a5695253fbef Mon Sep 17 00:00:00 2001 From: Krrish Biswas Date: Fri, 3 Apr 2026 22:29:26 +0530 Subject: [PATCH 06/30] Resolve flaky TestGetGrpcConnection and upgrade dependencies (#6264) fix(test): resolve flaky TestGetGrpcConnection and upgrade dependencies This commit fixes the flakiness in TestGetGrpcConnection by replacing the hardcoded port 9 with a dynamically assigned closed port. It also upgrades the Go version and BuildKit to resolve several high-severity security vulnerabilities. --- go.mod | 2 +- internal/util/cli/credentials_test.go | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 08328d1c37..48826aa9b8 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/mindersec/minder -go 1.25.6 +go 1.25.8 require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20250912141014-52f32327d4b0.1 diff --git a/internal/util/cli/credentials_test.go b/internal/util/cli/credentials_test.go index 709894c0ce..f99d4235a4 100644 --- a/internal/util/cli/credentials_test.go +++ b/internal/util/cli/credentials_test.go @@ -103,6 +103,12 @@ func TestGetGrpcConnection(t *testing.T) { grpcPort, err := strconv.Atoi(grpcPortStr) require.NoError(t, err) + // Get a guaranteed-closed ephemeral port for the legacy fallback test + ln, err := net.Listen("tcp", "localhost:0") + require.NoError(t, err) + closedPort := ln.Addr().(*net.TCPAddr).Port + ln.Close() + tests := []struct { name string externalName bool @@ -145,7 +151,7 @@ func TestGetGrpcConnection(t *testing.T) { }, { name: "Defaults connect to legacy endpoint", - overridePort: 9, // discard service, generally not listening + overridePort: closedPort, allowInsecure: true, expectedLegacy: 1, expectedError: "error unmarshaling credentials: EOF", From 6abe7ac81b611b286ee279d80e67c2673194c017 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 12:01:17 -0700 Subject: [PATCH 07/30] build(deps): bump the tools group in /tools with 4 updates (#6230) Bumps the tools group in /tools with 4 updates: [github.com/bufbuild/buf](https://github.com/bufbuild/buf), [github.com/golangci/golangci-lint/v2](https://github.com/golangci/golangci-lint), [github.com/openfga/cli](https://github.com/openfga/cli) and [golang.org/x/tools](https://github.com/golang/tools). Updates `github.com/bufbuild/buf` from 1.66.0 to 1.66.1 - [Release notes](https://github.com/bufbuild/buf/releases) - [Changelog](https://github.com/bufbuild/buf/blob/main/CHANGELOG.md) - [Commits](https://github.com/bufbuild/buf/compare/v1.66.0...v1.66.1) Updates `github.com/golangci/golangci-lint/v2` from 2.11.2 to 2.11.4 - [Release notes](https://github.com/golangci/golangci-lint/releases) - [Changelog](https://github.com/golangci/golangci-lint/blob/main/CHANGELOG.md) - [Commits](https://github.com/golangci/golangci-lint/compare/v2.11.2...v2.11.4) Updates `github.com/openfga/cli` from 0.7.10 to 0.7.12 - [Release notes](https://github.com/openfga/cli/releases) - [Changelog](https://github.com/openfga/cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/openfga/cli/compare/v0.7.10...v0.7.12) Updates `golang.org/x/tools` from 0.42.0 to 0.43.0 - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.42.0...v0.43.0) --- updated-dependencies: - dependency-name: github.com/bufbuild/buf dependency-version: 1.66.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: tools - dependency-name: github.com/golangci/golangci-lint/v2 dependency-version: 2.11.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: tools - dependency-name: github.com/openfga/cli dependency-version: 0.7.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: tools - dependency-name: golang.org/x/tools dependency-version: 0.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: tools ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/go.mod | 58 ++++++++++++------------- tools/go.sum | 120 +++++++++++++++++++++++++-------------------------- 2 files changed, 89 insertions(+), 89 deletions(-) diff --git a/tools/go.mod b/tools/go.mod index 323d5de60e..46deb3d5f5 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -3,21 +3,21 @@ module github.com/mindersec/minder/tools go 1.25.6 require ( - github.com/bufbuild/buf v1.66.0 + github.com/bufbuild/buf v1.66.1 github.com/daixiang0/gci v0.14.0 github.com/go-critic/go-critic v0.14.3 - github.com/golangci/golangci-lint/v2 v2.11.2 + github.com/golangci/golangci-lint/v2 v2.11.4 github.com/gotesttools/gotestfmt/v2 v2.5.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 github.com/mikefarah/yq/v4 v4.52.4 github.com/norwoodj/helm-docs v1.14.2 github.com/oapi-codegen/oapi-codegen/v2 v2.6.0 - github.com/openfga/cli v0.7.10 + github.com/openfga/cli v0.7.12 github.com/pseudomuto/protoc-gen-doc v1.5.1 github.com/sqlc-dev/sqlc v1.30.0 go.uber.org/mock v0.6.0 golang.org/x/lint v0.0.0-20241112194109-818c5a804067 - golang.org/x/tools v0.42.0 + golang.org/x/tools v0.43.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.1 google.golang.org/protobuf v1.36.11 mvdan.cc/gofumpt v0.9.2 @@ -90,7 +90,7 @@ require ( github.com/bombsimon/wsl/v5 v5.6.0 // indirect github.com/breml/bidichk v0.3.3 // indirect github.com/breml/errchkjson v0.4.1 // indirect - github.com/bufbuild/protocompile v0.14.2-0.20260202185951-d02d3732d113 // indirect + github.com/bufbuild/protocompile v0.14.2-0.20260306221011-519528254156 // indirect github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 // indirect github.com/butuzov/ireturn v0.4.0 // indirect github.com/butuzov/mirror v1.3.0 // indirect @@ -119,7 +119,7 @@ require ( github.com/dimchansky/utfbom v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect - github.com/docker/cli v29.2.1+incompatible // indirect + github.com/docker/cli v29.3.0+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v28.5.2+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.5 // indirect @@ -131,7 +131,7 @@ require ( github.com/emirpasic/gods v1.18.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect github.com/ettle/strcase v0.2.0 // indirect - github.com/fatih/color v1.18.0 // indirect + github.com/fatih/color v1.19.0 // indirect github.com/fatih/structtag v1.2.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/firefart/nonamedreturns v1.0.6 // indirect @@ -175,7 +175,7 @@ require ( github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e // indirect github.com/google/cel-go v0.27.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/go-containerregistry v0.21.0 // indirect + github.com/google/go-containerregistry v0.21.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gordonklaus/ineffassign v0.2.0 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect @@ -265,12 +265,12 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/openfga/api/proto v0.0.0-20260319214821-f153694bfc20 // indirect - github.com/openfga/go-sdk v0.7.4 // indirect + github.com/openfga/go-sdk v0.7.5 // indirect github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20251202173232-1e8bf16f1dce // indirect github.com/openfga/openfga v1.13.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect + github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect github.com/pganalyze/pg_query_go/v6 v6.1.0 // indirect github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb // indirect github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 // indirect @@ -299,20 +299,20 @@ require ( github.com/rung/go-safecast v1.0.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryancurrah/gomodguard v1.4.1 // indirect - github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect + github.com/ryanrolds/sqlclosecheck v0.6.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect github.com/schollz/progressbar/v3 v3.19.0 // indirect - github.com/securego/gosec/v2 v2.24.7 // indirect + github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08 // indirect github.com/segmentio/asm v1.2.1 // indirect github.com/segmentio/encoding v0.5.3 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.4 // indirect github.com/sivchari/containedctx v1.0.3 // indirect - github.com/sonatard/noctx v0.5.0 // indirect + github.com/sonatard/noctx v0.5.1 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/sourcegraph/go-diff v0.7.0 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect @@ -361,13 +361,13 @@ require ( go.lsp.dev/protocol v0.12.0 // indirect go.lsp.dev/uri v0.3.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect - go.opentelemetry.io/otel v1.41.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect + go.opentelemetry.io/otel v1.42.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 // indirect - go.opentelemetry.io/otel/metric v1.41.0 // indirect - go.opentelemetry.io/otel/sdk v1.41.0 // indirect - go.opentelemetry.io/otel/trace v1.41.0 // indirect + go.opentelemetry.io/otel/metric v1.42.0 // indirect + go.opentelemetry.io/otel/sdk v1.42.0 // indirect + go.opentelemetry.io/otel/trace v1.42.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -375,20 +375,20 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v4 v4.0.0-rc.4 // indirect - golang.org/x/crypto v0.48.0 // indirect + golang.org/x/crypto v0.49.0 // indirect golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/net v0.51.0 // indirect + golang.org/x/mod v0.34.0 // indirect + golang.org/x/net v0.52.0 // indirect golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 // indirect - golang.org/x/term v0.40.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/time v0.14.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c // indirect + golang.org/x/term v0.41.0 // indirect + golang.org/x/text v0.35.0 // indirect + golang.org/x/time v0.15.0 // indirect gonum.org/v1/gonum v0.17.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect google.golang.org/grpc v1.79.3 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect diff --git a/tools/go.sum b/tools/go.sum index 37716aa7c2..14b7299235 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -147,10 +147,10 @@ github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDw github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s= github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= -github.com/bufbuild/buf v1.66.0 h1:6kksYJpu6r45bvPJSTwNSwRqiAjrwB9YyU7skjNzFVo= -github.com/bufbuild/buf v1.66.0/go.mod h1:tWVlwtIPZ7kzlCB9D0hbbfrroT0GNCybPdPQXq1i1Ac= -github.com/bufbuild/protocompile v0.14.2-0.20260202185951-d02d3732d113 h1:nxt1QhP9rMQNFhHTdcNFwJ9wKCSdBjd28gz+qGDv4kM= -github.com/bufbuild/protocompile v0.14.2-0.20260202185951-d02d3732d113/go.mod h1:cxhE8h+14t0Yxq2H9MV/UggzQ1L0gh0t2tJobITWsBE= +github.com/bufbuild/buf v1.66.1 h1:wqmmU+6uoxB/eYDOmXq2To4qEXvOJN7gR6L9AxrPL1E= +github.com/bufbuild/buf v1.66.1/go.mod h1:Vd3ELm8IePWaDJaS9FLy94FFOnLrjLi4mDxmXtw9Xio= +github.com/bufbuild/protocompile v0.14.2-0.20260306221011-519528254156 h1:XOfIInPVufMjifwy3fli8qQVsGHWVCDVY/zp6elAOsY= +github.com/bufbuild/protocompile v0.14.2-0.20260306221011-519528254156/go.mod h1:cxhE8h+14t0Yxq2H9MV/UggzQ1L0gh0t2tJobITWsBE= github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 h1:V1xulAoqLqVg44rY97xOR+mQpD2N+GzhMHVwJ030WEU= github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1/go.mod h1:c5D8gWRIZ2HLWO3gXYTtUfw/hbJyD8xikv2ooPxnklQ= github.com/butuzov/ireturn v0.4.0 h1:+s76bF/PfeKEdbG8b54aCocxXmi0wvYdOVsWxVO7n8E= @@ -228,8 +228,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/cli v29.2.1+incompatible h1:n3Jt0QVCN65eiVBoUTZQM9mcQICCJt3akW4pKAbKdJg= -github.com/docker/cli v29.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v29.3.0+incompatible h1:z3iWveU7h19Pqx7alZES8j+IeFQZ1lhTwb2F+V9SVvk= +github.com/docker/cli v29.3.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= @@ -258,8 +258,8 @@ github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9 github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -366,8 +366,8 @@ github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarog github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= -github.com/golangci/golangci-lint/v2 v2.11.2 h1:4Icd3mEqthcFcFww8L67OBtfKB/obXxko8aFUMqP/5w= -github.com/golangci/golangci-lint/v2 v2.11.2/go.mod h1:wexdFBIQNhHNhDe1oqzlGFE5dYUqlfccWJKWjoWF1GI= +github.com/golangci/golangci-lint/v2 v2.11.4 h1:GK+UlZBN5y7rh2PBnHA93XLSX6RaF7uhzJQ3JwU1wuA= +github.com/golangci/golangci-lint/v2 v2.11.4/go.mod h1:ODQDCASMA3VqfZYIbbQLpTRTzV7O/vjmIRF6u8NyFwI= github.com/golangci/golines v0.15.0 h1:Qnph25g8Y1c5fdo1X7GaRDGgnMHgnxh4Gk4VfPTtRx0= github.com/golangci/golines v0.15.0/go.mod h1:AZjXd23tbHMpowhtnGlj9KCNsysj72aeZVVHnVcZx10= github.com/golangci/misspell v0.8.0 h1:qvxQhiE2/5z+BVRo1kwYA8yGz+lOlu5Jfvtx2b04Jbg= @@ -392,8 +392,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-containerregistry v0.21.0 h1:ocqxUOczFwAZQBMNE7kuzfqvDe0VWoZxQMOesXreCDI= -github.com/google/go-containerregistry v0.21.0/go.mod h1:ctO5aCaewH4AK1AumSF5DPW+0+R+d2FmylMJdp5G7p0= +github.com/google/go-containerregistry v0.21.2 h1:vYaMU4nU55JJGFC9JR/s8NZcTjbE9DBBbvusTW9NeS0= +github.com/google/go-containerregistry v0.21.2/go.mod h1:ctO5aCaewH4AK1AumSF5DPW+0+R+d2FmylMJdp5G7p0= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc= github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= @@ -648,10 +648,10 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/openfga/api/proto v0.0.0-20260319214821-f153694bfc20 h1:xdVG0EDz9Z9Uhd7YZ5OMN1F8tkAz/Dpgdjxd0cuTBJo= github.com/openfga/api/proto v0.0.0-20260319214821-f153694bfc20/go.mod h1:XDX4qYNBUM2Rsa2AbKPh+oocZc2zgme+EF2fFC6amVU= -github.com/openfga/cli v0.7.10 h1:yQnlRvhkWuQosbSE7wu7zH/2aJV7bRMpgij4SHhSgeA= -github.com/openfga/cli v0.7.10/go.mod h1:3LVgwIyE+wOrKmMw8snUwRB6SuBEw04VktGcBeLRggw= -github.com/openfga/go-sdk v0.7.4 h1:WBZDjl5Aqy1pFsDCL9LGZ5teJsYh42giFWA7G4AHfkw= -github.com/openfga/go-sdk v0.7.4/go.mod h1:jGyDrPZauqrGM89iSqvjVwwF80fKCTOIERGZ+X3H4pI= +github.com/openfga/cli v0.7.12 h1:8Ui55c0N6pNQmWw/CcJCFASt5zJMfxrgWdkZtNv7VLU= +github.com/openfga/cli v0.7.12/go.mod h1:A1J6uxMdxdp0I4KFsPPCGoR3w4C4GWepUMSjnny4oTs= +github.com/openfga/go-sdk v0.7.5 h1:Z1YL264hkBzrg1ejRVSzGRMjnG+ha4aexAA6b45F9+Q= +github.com/openfga/go-sdk v0.7.5/go.mod h1:VfBl0/Ipr0LMX9ftnk2t4EPJ3x6ptW7CD8n/K31D2PY= github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20251202173232-1e8bf16f1dce h1:9ufUx4ZNLTbk1/VYb7dPGvHyjoAicm4imeVF8OEv3YE= github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20251202173232-1e8bf16f1dce/go.mod h1:EbSJVzbk2+UyLx4i1t7Fi1yZEg+2pk2ZdnVg3jas1JA= github.com/openfga/openfga v1.13.1 h1:rOdJymjHeBHGxd24gnvwc4eXTPVsFcx1YzjQuRCBQSo= @@ -669,8 +669,8 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 h1:KPpdlQLZcHfTMQRi6bFQ7ogNO0ltFT4PmtwTLW4W+14= -github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 h1:rh2lKw/P/EqHa724vYH2+VVQ1YnW4u6EOXl0PMAovZE= +github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pganalyze/pg_query_go/v6 v6.1.0 h1:jG5ZLhcVgL1FAw4C/0VNQaVmX1SUJx71wBGdtTtBvls= github.com/pganalyze/pg_query_go/v6 v6.1.0/go.mod h1:nvTHIuoud6e1SfrUaFwHqT0i4b5Nr+1rPWVds3B5+50= github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= @@ -742,8 +742,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g= github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I= -github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= -github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= +github.com/ryanrolds/sqlclosecheck v0.6.0 h1:pEyL9okISdg1F1SEpJNlrEotkTGerv5BMk7U4AG0eVg= +github.com/ryanrolds/sqlclosecheck v0.6.0/go.mod h1:xyX16hsDaCMXHrMJ3JMzGf5OpDfHTOTTQrT7HOFUmeU= github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= @@ -756,8 +756,8 @@ github.com/sashamelentyev/usestdlibvars v1.29.0 h1:8J0MoRrw4/NAXtjQqTHrbW9NN+3iM github.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8= github.com/schollz/progressbar/v3 v3.19.0 h1:Ea18xuIRQXLAUidVDox3AbwfUhD0/1IvohyTutOIFoc= github.com/schollz/progressbar/v3 v3.19.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec= -github.com/securego/gosec/v2 v2.24.7 h1:3k5yJnrhT1TTdsG0ZsnenlfCcT+7Y/+zeCPHbL7QAn8= -github.com/securego/gosec/v2 v2.24.7/go.mod h1:AdDJbjcG/XxFgVv7pW19vMNYlFM6+Q6Qy3t6lWAUcEY= +github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08 h1:AoLtJX4WUtZkhhUUMFy3GgecAALp/Mb4S1iyQOA2s0U= +github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08/go.mod h1:+XLCJiRE95ga77XInNELh2M6zQP+PdqiT9Zpm0D9Wpk= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w= @@ -776,8 +776,8 @@ github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= -github.com/sonatard/noctx v0.5.0 h1:e/jdaqAsuWVOKQ0P6NWiIdDNHmHT5SwuuSfojFjzwrw= -github.com/sonatard/noctx v0.5.0/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas= +github.com/sonatard/noctx v0.5.1 h1:wklWg9c9ZYugOAk7qG4yP4PBrlQsmSLPTvW1K4PRQMs= +github.com/sonatard/noctx v0.5.1/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= @@ -904,24 +904,24 @@ go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo= go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0= -go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c= -go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 h1:ao6Oe+wSebTlQ1OEht7jlYTzQKE+pnx/iNywFvTbuuI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0/go.mod h1:u3T6vz0gh/NVzgDgiwkgLxpsSF6PaPmo2il0apGJbls= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= +go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= +go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 h1:mq/Qcf28TWz719lE3/hMB4KkyDuLJIvgJnFGcd0kEUI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0/go.mod h1:yk5LXEYhsL2htyDNJbEq7fWzNEigeEdV5xBF/Y+kAv0= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 h1:inYW9ZhgqiDqh6BioM7DVHHzEGVq76Db5897WLGZ5Go= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0/go.mod h1:Izur+Wt8gClgMJqO/cZ8wdeeMryJ/xxiOVgFSSfpDTY= -go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ= -go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps= -go.opentelemetry.io/otel/sdk v1.41.0 h1:YPIEXKmiAwkGl3Gu1huk1aYWwtpRLeskpV+wPisxBp8= -go.opentelemetry.io/otel/sdk v1.41.0/go.mod h1:ahFdU0G5y8IxglBf0QBJXgSe7agzjE4GiTJ6HT9ud90= -go.opentelemetry.io/otel/sdk/metric v1.41.0 h1:siZQIYBAUd1rlIWQT2uCxWJxcCO7q3TriaMlf08rXw8= -go.opentelemetry.io/otel/sdk/metric v1.41.0/go.mod h1:HNBuSvT7ROaGtGI50ArdRLUnvRTRGniSUZbxiWxSO8Y= -go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0= -go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis= +go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= +go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= +go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= +go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= +go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA= +go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= +go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= +go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -954,8 +954,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= @@ -979,8 +979,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1002,8 +1002,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= -golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1050,18 +1050,18 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 h1:bTLqdHv7xrGlFbvf5/TXNxy/iUwwdkjhqQTJDjW7aj0= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4/go.mod h1:g5NllXBEermZrmR51cJDQxmJUHUOfRAaNyWBM+R+548= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c h1:6a8FdnNk6bTXBjR4AGKFgUKuo+7GnR3FX5L7CbveeZc= +golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c/go.mod h1:TpUTTEp9frx7rTdLpC9gFG9kdI7zVLFTFFlqaH2Cncw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= -golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1070,10 +1070,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1096,8 +1096,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -1113,10 +1113,10 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d h1:EocjzKLywydp5uZ5tJ79iP6Q0UjDnyiHkGRWxuPBP8s= -google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:48U2I+QQUYhsFrg2SY6r+nJzeOtjey7j//WBESw+qyQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d h1:t/LOSXPJ9R0B6fnZNyALBRfZBH0Uy0gT+uR+SJ6syqQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4= +google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= From 6f131a0827adc7dc0800c062302afb687f6650bd Mon Sep 17 00:00:00 2001 From: Sachin Kumar <69066918+sachin9058@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:36:15 +0530 Subject: [PATCH 08/30] Add pre-validation for repo register command to prevent unnecessary auth flow (#6249) * :sparkles: Improve CLI help for repo command with examples Signed-off-by: Sachin Kumar * fix: correct repo command from add to register in CLI examples Signed-off-by: Sachin Kumar * :sparkles: Add pre-validation for repo register to validate flags before auth - Validate required inputs (--provider, --name/--all) - Prevent unnecessary authentication flow when input is incomplete - Improve CLI UX with clear error messages and examples Signed-off-by: Sachin Kumar * :sparkles: Fix validation logic for repo register command - Remove duplicate validation from RegisterCmd - Allow --all without requiring --provider - Use Cobra flags for validation consistency Signed-off-by: Sachin Kumar --------- Signed-off-by: Sachin Kumar --- cmd/cli/app/repo/repo.go | 17 +++++++++++++++-- cmd/cli/app/repo/repo_register.go | 18 +++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/cmd/cli/app/repo/repo.go b/cmd/cli/app/repo/repo.go index 83f8fa5e0e..ee25d130fe 100644 --- a/cmd/cli/app/repo/repo.go +++ b/cmd/cli/app/repo/repo.go @@ -13,8 +13,21 @@ import ( // RepoCmd is the root command for the repo subcommands var RepoCmd = &cobra.Command{ Use: "repo", - Short: "Manage repositories", - Long: `The repo commands allow the management of repositories within Minder.`, + Short: "Manage repositories within a Minder project", + Long: `Manage repositories within a Minder project. + +This command allows you to list, add, and manage repositories +connected to Minder for security analysis and policy enforcement.`, + Example: ` + # List repositories + minder repo list + + # Register a repository + minder repo register --name my-repo --provider github + + # Delete a repository + minder repo delete --name my-repo +`, RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Usage() }, diff --git a/cmd/cli/app/repo/repo_register.go b/cmd/cli/app/repo/repo_register.go index be341017d8..932e2fe60b 100644 --- a/cmd/cli/app/repo/repo_register.go +++ b/cmd/cli/app/repo/repo_register.go @@ -25,7 +25,23 @@ var repoRegisterCmd = &cobra.Command{ Use: "register", Short: "Register a repository", Long: `The repo register subcommand is used to register a repo within Minder.`, - RunE: cli.GRPCClientWrapRunE(RegisterCmd), + + PreRunE: func(_ *cobra.Command, _ []string) error { + inputRepoList := viper.GetStringSlice("name") + registerAll := viper.GetBool("all") + + if len(inputRepoList) > 0 && registerAll { + return fmt.Errorf("cannot use --name and --all together") + } + + if len(inputRepoList) == 0 && !registerAll { + return fmt.Errorf("must provide either --name or --all") + } + + return nil + }, + + RunE: cli.GRPCClientWrapRunE(RegisterCmd), } // RegisterCmd represents the register command to register a repo with minder From fddf2aa8e084c9a213e7dcfd3e7a97723d6dd5d0 Mon Sep 17 00:00:00 2001 From: Sachin Kumar <69066918+sachin9058@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:46:52 +0530 Subject: [PATCH 09/30] Move internal/engine/errors to pkg/engine/errors to reduce coupling (#6252) * Move internal/engine/errors to pkg/engine/errors to reduce coupling Signed-off-by: Sachin Kumar * fix: resolve lint issues --------- Signed-off-by: Sachin Kumar --- cmd/dev/app/rule_type/rttst.go | 2 +- internal/engine/actions/actions.go | 2 +- internal/engine/actions/alert/noop/noop.go | 2 +- .../actions/alert/pull_request_comment/pull_request_comment.go | 2 +- .../alert/pull_request_comment/pull_request_comment_test.go | 2 +- .../engine/actions/alert/security_advisory/security_advisory.go | 2 +- .../actions/alert/security_advisory/security_advisory_test.go | 2 +- .../actions/remediate/gh_branch_protect/gh_branch_protect.go | 2 +- internal/engine/actions/remediate/noop/noop.go | 2 +- internal/engine/actions/remediate/pull_request/pull_request.go | 2 +- .../engine/actions/remediate/pull_request/pull_request_test.go | 2 +- internal/engine/actions/remediate/rest/rest.go | 2 +- .../eval/homoglyphs/application/invisible_characters_eval.go | 2 +- .../homoglyphs/application/invisible_characters_eval_test.go | 2 +- .../engine/eval/homoglyphs/application/mixed_scripts_eval.go | 2 +- .../eval/homoglyphs/application/mixed_scripts_eval_test.go | 2 +- internal/engine/eval/jq/jq.go | 2 +- internal/engine/eval/jq/jq_test.go | 2 +- internal/engine/eval/rego/lib_test.go | 2 +- internal/engine/eval/rego/rego_test.go | 2 +- internal/engine/eval/rego/result.go | 2 +- internal/engine/eval/rego/result_test.go | 2 +- internal/engine/eval/trusty/trusty.go | 2 +- internal/engine/eval/trusty/trusty_test.go | 2 +- internal/engine/eval/vulncheck/vulncheck.go | 2 +- internal/engine/eval/vulncheck/vulncheck_test.go | 2 +- internal/engine/eval_status.go | 2 +- internal/engine/executor.go | 2 +- internal/engine/ingester/artifact/artifact.go | 2 +- internal/engine/ingester/artifact/artifact_test.go | 2 +- internal/engine/ingester/builtin/builtin.go | 2 +- internal/engine/ingester/builtin/builtin_test.go | 2 +- internal/engine/interfaces/interface.go | 2 +- internal/history/service.go | 2 +- internal/logger/telemetry_store.go | 2 +- internal/logger/telemetry_store_test.go | 2 +- internal/providers/github/common.go | 2 +- {internal => pkg}/engine/errors/errors.go | 0 {internal => pkg}/engine/errors/errors_test.go | 1 - pkg/engine/v1/rtengine/engine.go | 2 +- 40 files changed, 38 insertions(+), 39 deletions(-) rename {internal => pkg}/engine/errors/errors.go (100%) rename {internal => pkg}/engine/errors/errors_test.go (99%) diff --git a/cmd/dev/app/rule_type/rttst.go b/cmd/dev/app/rule_type/rttst.go index 44b82be66a..c109cccb90 100644 --- a/cmd/dev/app/rule_type/rttst.go +++ b/cmd/dev/app/rule_type/rttst.go @@ -21,7 +21,6 @@ import ( "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/internal/engine/actions" "github.com/mindersec/minder/internal/engine/entities" - "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/rego" engif "github.com/mindersec/minder/internal/engine/interfaces" "github.com/mindersec/minder/internal/engine/options" @@ -38,6 +37,7 @@ import ( minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" serverconfig "github.com/mindersec/minder/pkg/config/server" v1datasources "github.com/mindersec/minder/pkg/datasources/v1" + "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/selectors" "github.com/mindersec/minder/pkg/engine/v1/rtengine" entProps "github.com/mindersec/minder/pkg/entities/properties" diff --git a/internal/engine/actions/actions.go b/internal/engine/actions/actions.go index a80add334c..fdc6c494aa 100644 --- a/internal/engine/actions/actions.go +++ b/internal/engine/actions/actions.go @@ -19,9 +19,9 @@ import ( "github.com/mindersec/minder/internal/engine/actions/alert" "github.com/mindersec/minder/internal/engine/actions/remediate" "github.com/mindersec/minder/internal/engine/actions/remediate/pull_request" - enginerr "github.com/mindersec/minder/internal/engine/errors" engif "github.com/mindersec/minder/internal/engine/interfaces" minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + enginerr "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/profiles/models" provinfv1 "github.com/mindersec/minder/pkg/providers/v1" diff --git a/internal/engine/actions/alert/noop/noop.go b/internal/engine/actions/alert/noop/noop.go index 2f0c2cf1a3..42989816cb 100644 --- a/internal/engine/actions/alert/noop/noop.go +++ b/internal/engine/actions/alert/noop/noop.go @@ -12,8 +12,8 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" - enginerr "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/interfaces" + enginerr "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/profiles/models" ) diff --git a/internal/engine/actions/alert/pull_request_comment/pull_request_comment.go b/internal/engine/actions/alert/pull_request_comment/pull_request_comment.go index 5daa483fd0..f827c4956f 100644 --- a/internal/engine/actions/alert/pull_request_comment/pull_request_comment.go +++ b/internal/engine/actions/alert/pull_request_comment/pull_request_comment.go @@ -19,11 +19,11 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" "github.com/mindersec/minder/internal/db" - enginerr "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/interfaces" pbinternal "github.com/mindersec/minder/internal/proto" "github.com/mindersec/minder/internal/util" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + enginerr "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/profiles/models" provifv1 "github.com/mindersec/minder/pkg/providers/v1" ) diff --git a/internal/engine/actions/alert/pull_request_comment/pull_request_comment_test.go b/internal/engine/actions/alert/pull_request_comment/pull_request_comment_test.go index ade286667d..7499d93ad7 100644 --- a/internal/engine/actions/alert/pull_request_comment/pull_request_comment_test.go +++ b/internal/engine/actions/alert/pull_request_comment/pull_request_comment_test.go @@ -15,11 +15,11 @@ import ( "go.uber.org/mock/gomock" "github.com/mindersec/minder/internal/db" - enginerr "github.com/mindersec/minder/internal/engine/errors" engif "github.com/mindersec/minder/internal/engine/interfaces" pbinternal "github.com/mindersec/minder/internal/proto" mockghclient "github.com/mindersec/minder/internal/providers/github/mock" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + enginerr "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/profiles/models" ) diff --git a/internal/engine/actions/alert/security_advisory/security_advisory.go b/internal/engine/actions/alert/security_advisory/security_advisory.go index 2648d3253c..7c9c9860af 100644 --- a/internal/engine/actions/alert/security_advisory/security_advisory.go +++ b/internal/engine/actions/alert/security_advisory/security_advisory.go @@ -18,11 +18,11 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" "github.com/mindersec/minder/internal/db" - enginerr "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/interfaces" pbinternal "github.com/mindersec/minder/internal/proto" "github.com/mindersec/minder/internal/util" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + enginerr "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/profiles/models" provifv1 "github.com/mindersec/minder/pkg/providers/v1" ) diff --git a/internal/engine/actions/alert/security_advisory/security_advisory_test.go b/internal/engine/actions/alert/security_advisory/security_advisory_test.go index bd694e139f..5925175675 100644 --- a/internal/engine/actions/alert/security_advisory/security_advisory_test.go +++ b/internal/engine/actions/alert/security_advisory/security_advisory_test.go @@ -16,11 +16,11 @@ import ( "go.uber.org/mock/gomock" "github.com/mindersec/minder/internal/db" - enginerr "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/interfaces" pbinternal "github.com/mindersec/minder/internal/proto" mockghclient "github.com/mindersec/minder/internal/providers/github/mock" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + enginerr "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/profiles/models" ) diff --git a/internal/engine/actions/remediate/gh_branch_protect/gh_branch_protect.go b/internal/engine/actions/remediate/gh_branch_protect/gh_branch_protect.go index 33912394ce..8f9b781529 100644 --- a/internal/engine/actions/remediate/gh_branch_protect/gh_branch_protect.go +++ b/internal/engine/actions/remediate/gh_branch_protect/gh_branch_protect.go @@ -18,11 +18,11 @@ import ( "github.com/rs/zerolog/log" "google.golang.org/protobuf/reflect/protoreflect" - engerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/interfaces" mindergh "github.com/mindersec/minder/internal/providers/github" "github.com/mindersec/minder/internal/util" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + engerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/profiles/models" provifv1 "github.com/mindersec/minder/pkg/providers/v1" ) diff --git a/internal/engine/actions/remediate/noop/noop.go b/internal/engine/actions/remediate/noop/noop.go index 7c106fdf32..bffb4e2766 100644 --- a/internal/engine/actions/remediate/noop/noop.go +++ b/internal/engine/actions/remediate/noop/noop.go @@ -12,8 +12,8 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" - enginerr "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/interfaces" + enginerr "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/profiles/models" ) diff --git a/internal/engine/actions/remediate/pull_request/pull_request.go b/internal/engine/actions/remediate/pull_request/pull_request.go index dc0dbeda26..a40e3eac5a 100644 --- a/internal/engine/actions/remediate/pull_request/pull_request.go +++ b/internal/engine/actions/remediate/pull_request/pull_request.go @@ -24,10 +24,10 @@ import ( "google.golang.org/protobuf/proto" "github.com/mindersec/minder/internal/db" - enginerr "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/interfaces" "github.com/mindersec/minder/internal/util" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + enginerr "github.com/mindersec/minder/pkg/engine/errors" engifv1 "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/profiles/models" provifv1 "github.com/mindersec/minder/pkg/providers/v1" diff --git a/internal/engine/actions/remediate/pull_request/pull_request_test.go b/internal/engine/actions/remediate/pull_request/pull_request_test.go index 4e4a39349d..d5091eb2ab 100644 --- a/internal/engine/actions/remediate/pull_request/pull_request_test.go +++ b/internal/engine/actions/remediate/pull_request/pull_request_test.go @@ -28,7 +28,6 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/types/known/structpb" - "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/interfaces" "github.com/mindersec/minder/internal/providers/credentials" "github.com/mindersec/minder/internal/providers/github/clients" @@ -37,6 +36,7 @@ import ( "github.com/mindersec/minder/internal/providers/ratecache" "github.com/mindersec/minder/internal/providers/telemetry" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + "github.com/mindersec/minder/pkg/engine/errors" interfaces2 "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/profiles/models" provifv1 "github.com/mindersec/minder/pkg/providers/v1" diff --git a/internal/engine/actions/remediate/rest/rest.go b/internal/engine/actions/remediate/rest/rest.go index f586f3e4f1..ba196c596a 100644 --- a/internal/engine/actions/remediate/rest/rest.go +++ b/internal/engine/actions/remediate/rest/rest.go @@ -19,10 +19,10 @@ import ( "github.com/rs/zerolog/log" "google.golang.org/protobuf/reflect/protoreflect" - engerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/interfaces" "github.com/mindersec/minder/internal/util" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + engerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/profiles/models" provifv1 "github.com/mindersec/minder/pkg/providers/v1" ) diff --git a/internal/engine/eval/homoglyphs/application/invisible_characters_eval.go b/internal/engine/eval/homoglyphs/application/invisible_characters_eval.go index 5c03443afb..14925c70a6 100644 --- a/internal/engine/eval/homoglyphs/application/invisible_characters_eval.go +++ b/internal/engine/eval/homoglyphs/application/invisible_characters_eval.go @@ -8,10 +8,10 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/homoglyphs/communication" "github.com/mindersec/minder/internal/engine/eval/homoglyphs/domain" "github.com/mindersec/minder/internal/engine/eval/templates" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" ) diff --git a/internal/engine/eval/homoglyphs/application/invisible_characters_eval_test.go b/internal/engine/eval/homoglyphs/application/invisible_characters_eval_test.go index eba25ec03b..f8cf0a1c5d 100644 --- a/internal/engine/eval/homoglyphs/application/invisible_characters_eval_test.go +++ b/internal/engine/eval/homoglyphs/application/invisible_characters_eval_test.go @@ -8,9 +8,9 @@ import ( "github.com/stretchr/testify/require" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/homoglyphs/domain" "github.com/mindersec/minder/internal/engine/eval/templates" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" ) func TestInvisibleCharactersEvaluationDetailRendering(t *testing.T) { diff --git a/internal/engine/eval/homoglyphs/application/mixed_scripts_eval.go b/internal/engine/eval/homoglyphs/application/mixed_scripts_eval.go index e1589e788b..487ef958fb 100644 --- a/internal/engine/eval/homoglyphs/application/mixed_scripts_eval.go +++ b/internal/engine/eval/homoglyphs/application/mixed_scripts_eval.go @@ -9,10 +9,10 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/homoglyphs/communication" "github.com/mindersec/minder/internal/engine/eval/homoglyphs/domain" "github.com/mindersec/minder/internal/engine/eval/templates" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" ) diff --git a/internal/engine/eval/homoglyphs/application/mixed_scripts_eval_test.go b/internal/engine/eval/homoglyphs/application/mixed_scripts_eval_test.go index 33ee9ad1b3..3764f88f30 100644 --- a/internal/engine/eval/homoglyphs/application/mixed_scripts_eval_test.go +++ b/internal/engine/eval/homoglyphs/application/mixed_scripts_eval_test.go @@ -8,9 +8,9 @@ import ( "github.com/stretchr/testify/require" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/homoglyphs/domain" "github.com/mindersec/minder/internal/engine/eval/templates" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" ) func TestEvaluationDetailRendering(t *testing.T) { diff --git a/internal/engine/eval/jq/jq.go b/internal/engine/eval/jq/jq.go index d8392783c1..dafcfeaa18 100644 --- a/internal/engine/eval/jq/jq.go +++ b/internal/engine/eval/jq/jq.go @@ -13,10 +13,10 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/templates" "github.com/mindersec/minder/internal/util" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" ) diff --git a/internal/engine/eval/jq/jq_test.go b/internal/engine/eval/jq/jq_test.go index 74d69b6a30..a1adbd10cb 100644 --- a/internal/engine/eval/jq/jq_test.go +++ b/internal/engine/eval/jq/jq_test.go @@ -11,10 +11,10 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/structpb" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/jq" "github.com/mindersec/minder/internal/engine/eval/templates" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" ) diff --git a/internal/engine/eval/rego/lib_test.go b/internal/engine/eval/rego/lib_test.go index 44ffbff47a..cda7e0739a 100644 --- a/internal/engine/eval/rego/lib_test.go +++ b/internal/engine/eval/rego/lib_test.go @@ -15,10 +15,10 @@ import ( billyutil "github.com/go-git/go-billy/v5/util" "github.com/stretchr/testify/require" - engerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/rego" "github.com/mindersec/minder/internal/engine/options" minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + engerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/flags" ) diff --git a/internal/engine/eval/rego/rego_test.go b/internal/engine/eval/rego/rego_test.go index 088a485742..8bdf3dfe0d 100644 --- a/internal/engine/eval/rego/rego_test.go +++ b/internal/engine/eval/rego/rego_test.go @@ -12,13 +12,13 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" - engerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/rego" "github.com/mindersec/minder/internal/engine/options" "github.com/mindersec/minder/internal/util/ptr" minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" v1datasources "github.com/mindersec/minder/pkg/datasources/v1" v1mockds "github.com/mindersec/minder/pkg/datasources/v1/mock" + engerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" ) diff --git a/internal/engine/eval/rego/result.go b/internal/engine/eval/rego/result.go index 76bd05aae0..5de529d33e 100644 --- a/internal/engine/eval/rego/result.go +++ b/internal/engine/eval/rego/result.go @@ -13,10 +13,10 @@ import ( "github.com/open-policy-agent/opa/v1/rego" "google.golang.org/protobuf/reflect/protoreflect" - engerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/templates" pbinternal "github.com/mindersec/minder/internal/proto" minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + engerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" ) diff --git a/internal/engine/eval/rego/result_test.go b/internal/engine/eval/rego/result_test.go index d60a517fb3..77d96913e4 100644 --- a/internal/engine/eval/rego/result_test.go +++ b/internal/engine/eval/rego/result_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/require" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/templates" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" ) func TestEvaluationDetailRendering(t *testing.T) { diff --git a/internal/engine/eval/trusty/trusty.go b/internal/engine/eval/trusty/trusty.go index e504727fa7..94d460bfe4 100644 --- a/internal/engine/eval/trusty/trusty.go +++ b/internal/engine/eval/trusty/trusty.go @@ -17,10 +17,10 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" "github.com/mindersec/minder/internal/constants" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/pr_actions" "github.com/mindersec/minder/internal/engine/eval/templates" pbinternal "github.com/mindersec/minder/internal/proto" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" ) diff --git a/internal/engine/eval/trusty/trusty_test.go b/internal/engine/eval/trusty/trusty_test.go index 3808eb2e24..f4f8e3c10b 100644 --- a/internal/engine/eval/trusty/trusty_test.go +++ b/internal/engine/eval/trusty/trusty_test.go @@ -13,11 +13,11 @@ import ( trustytypes "github.com/stacklok/trusty-sdk-go/pkg/v2/types" "github.com/stretchr/testify/require" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/pr_actions" "github.com/mindersec/minder/internal/engine/eval/templates" pbinternal "github.com/mindersec/minder/internal/proto" mock_github "github.com/mindersec/minder/internal/providers/github/mock" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" provifv1 "github.com/mindersec/minder/pkg/providers/v1" ) diff --git a/internal/engine/eval/vulncheck/vulncheck.go b/internal/engine/eval/vulncheck/vulncheck.go index 6aac03e9ee..184fd48fab 100644 --- a/internal/engine/eval/vulncheck/vulncheck.go +++ b/internal/engine/eval/vulncheck/vulncheck.go @@ -14,10 +14,10 @@ import ( "github.com/rs/zerolog" "google.golang.org/protobuf/reflect/protoreflect" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/templates" eoptions "github.com/mindersec/minder/internal/engine/options" pbinternal "github.com/mindersec/minder/internal/proto" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/flags" ) diff --git a/internal/engine/eval/vulncheck/vulncheck_test.go b/internal/engine/eval/vulncheck/vulncheck_test.go index 91e6037e30..004dec8909 100644 --- a/internal/engine/eval/vulncheck/vulncheck_test.go +++ b/internal/engine/eval/vulncheck/vulncheck_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/require" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval/templates" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" ) func TestEvaluationDetailRendering(t *testing.T) { diff --git a/internal/engine/eval_status.go b/internal/engine/eval_status.go index 5e7d16bc08..c263d56dc5 100644 --- a/internal/engine/eval_status.go +++ b/internal/engine/eval_status.go @@ -14,8 +14,8 @@ import ( "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/internal/engine/entities" - evalerrors "github.com/mindersec/minder/internal/engine/errors" engif "github.com/mindersec/minder/internal/engine/interfaces" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/profiles/models" ) diff --git a/internal/engine/executor.go b/internal/engine/executor.go index 5a58457753..c219f13dcc 100644 --- a/internal/engine/executor.go +++ b/internal/engine/executor.go @@ -17,7 +17,6 @@ import ( "github.com/mindersec/minder/internal/engine/actions/alert" "github.com/mindersec/minder/internal/engine/actions/remediate" "github.com/mindersec/minder/internal/engine/entities" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/ingestcache" engif "github.com/mindersec/minder/internal/engine/interfaces" eoptions "github.com/mindersec/minder/internal/engine/options" @@ -28,6 +27,7 @@ import ( "github.com/mindersec/minder/internal/providers/manager" provsel "github.com/mindersec/minder/internal/providers/selectors" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/selectors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/flags" diff --git a/internal/engine/ingester/artifact/artifact.go b/internal/engine/ingester/artifact/artifact.go index cd4d68fe8c..837b9ecd72 100644 --- a/internal/engine/ingester/artifact/artifact.go +++ b/internal/engine/ingester/artifact/artifact.go @@ -14,12 +14,12 @@ import ( "github.com/sigstore/sigstore-go/pkg/fulcio/certificate" "google.golang.org/protobuf/proto" - evalerrors "github.com/mindersec/minder/internal/engine/errors" artif "github.com/mindersec/minder/internal/providers/artifact" "github.com/mindersec/minder/internal/verifier" "github.com/mindersec/minder/internal/verifier/sigstore/container" "github.com/mindersec/minder/internal/verifier/verifyif" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/entities/v1/checkpoints" provifv1 "github.com/mindersec/minder/pkg/providers/v1" diff --git a/internal/engine/ingester/artifact/artifact_test.go b/internal/engine/ingester/artifact/artifact_test.go index 94e4abe8c4..3f3afe298c 100644 --- a/internal/engine/ingester/artifact/artifact_test.go +++ b/internal/engine/ingester/artifact/artifact_test.go @@ -13,7 +13,6 @@ import ( "go.uber.org/mock/gomock" "google.golang.org/protobuf/types/known/timestamppb" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/providers/credentials" "github.com/mindersec/minder/internal/providers/github/clients" mockghclient "github.com/mindersec/minder/internal/providers/github/mock" @@ -23,6 +22,7 @@ import ( "github.com/mindersec/minder/internal/verifier/verifyif" mockverify "github.com/mindersec/minder/internal/verifier/verifyif/mock" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" provinfv1 "github.com/mindersec/minder/pkg/providers/v1" ) diff --git a/internal/engine/ingester/builtin/builtin.go b/internal/engine/ingester/builtin/builtin.go index df39e2a6a4..ad37e3612d 100644 --- a/internal/engine/ingester/builtin/builtin.go +++ b/internal/engine/ingester/builtin/builtin.go @@ -15,9 +15,9 @@ import ( "github.com/go-git/go-billy/v5" "google.golang.org/protobuf/reflect/protoreflect" - evalerrors "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/util" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/entities/v1/checkpoints" "github.com/mindersec/minder/pkg/rule_methods" diff --git a/internal/engine/ingester/builtin/builtin_test.go b/internal/engine/ingester/builtin/builtin_test.go index 497a172991..c26055b7c1 100644 --- a/internal/engine/ingester/builtin/builtin_test.go +++ b/internal/engine/ingester/builtin/builtin_test.go @@ -13,8 +13,8 @@ import ( "github.com/stretchr/testify/assert" "google.golang.org/protobuf/reflect/protoreflect" - evalerrors "github.com/mindersec/minder/internal/engine/errors" pb "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" ) func TestBuiltInWorks(t *testing.T) { diff --git a/internal/engine/interfaces/interface.go b/internal/engine/interfaces/interface.go index 083630d3fd..a1076855c5 100644 --- a/internal/engine/interfaces/interface.go +++ b/internal/engine/interfaces/interface.go @@ -14,7 +14,7 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" "github.com/mindersec/minder/internal/db" - evalerrors "github.com/mindersec/minder/internal/engine/errors" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/profiles/models" ) diff --git a/internal/history/service.go b/internal/history/service.go index 3004f02380..8f81b675b1 100644 --- a/internal/history/service.go +++ b/internal/history/service.go @@ -16,9 +16,9 @@ import ( "github.com/rs/zerolog" "github.com/mindersec/minder/internal/db" - evalerrors "github.com/mindersec/minder/internal/engine/errors" propertiessvc "github.com/mindersec/minder/internal/entities/properties/service" "github.com/mindersec/minder/internal/providers/manager" + evalerrors "github.com/mindersec/minder/pkg/engine/errors" ) //go:generate go run go.uber.org/mock/mockgen -package mock_$GOPACKAGE -destination=./mock/$GOFILE -source=./$GOFILE diff --git a/internal/logger/telemetry_store.go b/internal/logger/telemetry_store.go index 0e54d66746..16e5fcb7e6 100644 --- a/internal/logger/telemetry_store.go +++ b/internal/logger/telemetry_store.go @@ -12,8 +12,8 @@ import ( "github.com/mindersec/minder/internal/engine/actions/alert" "github.com/mindersec/minder/internal/engine/actions/remediate" - "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/interfaces" + "github.com/mindersec/minder/pkg/engine/errors" ) type key int diff --git a/internal/logger/telemetry_store_test.go b/internal/logger/telemetry_store_test.go index bde9620ed0..2672ff4883 100644 --- a/internal/logger/telemetry_store_test.go +++ b/internal/logger/telemetry_store_test.go @@ -13,9 +13,9 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" - enginerr "github.com/mindersec/minder/internal/engine/errors" engif "github.com/mindersec/minder/internal/engine/interfaces" "github.com/mindersec/minder/internal/logger" + enginerr "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/profiles/models" ) diff --git a/internal/providers/github/common.go b/internal/providers/github/common.go index 97d4ab9853..665cda995d 100644 --- a/internal/providers/github/common.go +++ b/internal/providers/github/common.go @@ -24,13 +24,13 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" "github.com/mindersec/minder/internal/db" - engerrors "github.com/mindersec/minder/internal/engine/errors" gitclient "github.com/mindersec/minder/internal/providers/git" "github.com/mindersec/minder/internal/providers/github/ghcr" "github.com/mindersec/minder/internal/providers/github/properties" "github.com/mindersec/minder/internal/providers/ratecache" minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" config "github.com/mindersec/minder/pkg/config/server" + engerrors "github.com/mindersec/minder/pkg/engine/errors" provifv1 "github.com/mindersec/minder/pkg/providers/v1" ) diff --git a/internal/engine/errors/errors.go b/pkg/engine/errors/errors.go similarity index 100% rename from internal/engine/errors/errors.go rename to pkg/engine/errors/errors.go diff --git a/internal/engine/errors/errors_test.go b/pkg/engine/errors/errors_test.go similarity index 99% rename from internal/engine/errors/errors_test.go rename to pkg/engine/errors/errors_test.go index 549210c374..1e5e223b16 100644 --- a/internal/engine/errors/errors_test.go +++ b/pkg/engine/errors/errors_test.go @@ -1,6 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2024 The Minder Authors // SPDX-License-Identifier: Apache-2.0 - package errors import ( diff --git a/pkg/engine/v1/rtengine/engine.go b/pkg/engine/v1/rtengine/engine.go index 4a0b4ebdc8..30d40bd68f 100644 --- a/pkg/engine/v1/rtengine/engine.go +++ b/pkg/engine/v1/rtengine/engine.go @@ -12,11 +12,11 @@ import ( "github.com/rs/zerolog" "google.golang.org/protobuf/reflect/protoreflect" - enginerr "github.com/mindersec/minder/internal/engine/errors" "github.com/mindersec/minder/internal/engine/eval" "github.com/mindersec/minder/internal/engine/ingestcache" "github.com/mindersec/minder/internal/engine/ingester" minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" + enginerr "github.com/mindersec/minder/pkg/engine/errors" "github.com/mindersec/minder/pkg/engine/v1/interfaces" "github.com/mindersec/minder/pkg/profiles" ) From 94f8c1169eaa9360e3321103b296a413f4eb6678 Mon Sep 17 00:00:00 2001 From: Dharun Date: Sat, 4 Apr 2026 01:22:06 +0530 Subject: [PATCH 10/30] Remove git_pr_diffs flag (#6258) * removed git_pr_diffs feature flag Signed-off-by: DharunMR * removed the flag from testcase Signed-off-by: DharunMR --------- Signed-off-by: DharunMR --- internal/controlplane/handlers_ruletype.go | 23 ---------------------- internal/engine/eval/rego/lib.go | 16 +++++++-------- internal/engine/eval/rego/lib_test.go | 3 --- pkg/flags/constants.go | 2 -- 4 files changed, 7 insertions(+), 37 deletions(-) diff --git a/internal/controlplane/handlers_ruletype.go b/internal/controlplane/handlers_ruletype.go index a8aeabc1c6..7b18d73e63 100644 --- a/internal/controlplane/handlers_ruletype.go +++ b/internal/controlplane/handlers_ruletype.go @@ -23,11 +23,9 @@ import ( "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/internal/engine/engcontext" - "github.com/mindersec/minder/internal/engine/ingester/git" "github.com/mindersec/minder/internal/logger" "github.com/mindersec/minder/internal/util" minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" - "github.com/mindersec/minder/pkg/flags" "github.com/mindersec/minder/pkg/ruletypes" ) @@ -176,11 +174,6 @@ func (s *Server) CreateRuleType( return nil, util.UserVisibleError(codes.InvalidArgument, "%s", err) } - ruleDef := crt.GetRuleType().GetDef() - if err := checkRuleDefinitionFlags(ctx, s.featureFlags, ruleDef); err != nil { - return nil, err - } - newRuleType, err := db.WithTransaction(s.store, func(qtx db.ExtendQuerier) (*minderv1.RuleType, error) { return s.ruleTypes.CreateRuleType(ctx, projectID, uuid.Nil, crt.GetRuleType(), qtx) }) @@ -200,17 +193,6 @@ func (s *Server) CreateRuleType( }, nil } -func checkRuleDefinitionFlags( - ctx context.Context, featureFlags flags.Interface, ruleDef *minderv1.RuleType_Definition) *util.NiceStatus { - usesGitPR := ruleDef.GetIngest().GetType() == git.GitRuleDataIngestType && - ruleDef.GetInEntity() == minderv1.PullRequestEntity.String() - if usesGitPR && !flags.Bool(ctx, featureFlags, flags.GitPRDiffs) { - return util.UserVisibleError(codes.InvalidArgument, "Git pull request ingest is disabled") - } - - return nil -} - // UpdateRuleType is a method to update a rule type func (s *Server) UpdateRuleType( ctx context.Context, @@ -234,11 +216,6 @@ func (s *Server) UpdateRuleType( return nil, util.UserVisibleError(codes.InvalidArgument, "%s", err) } - ruleDef := urt.GetRuleType().GetDef() - if err := checkRuleDefinitionFlags(ctx, s.featureFlags, ruleDef); err != nil { - return nil, err - } - updatedRuleType, err := db.WithTransaction(s.store, func(qtx db.ExtendQuerier) (*minderv1.RuleType, error) { return s.ruleTypes.UpdateRuleType(ctx, projectID, uuid.Nil, urt.GetRuleType(), qtx) }) diff --git a/internal/engine/eval/rego/lib.go b/internal/engine/eval/rego/lib.go index 41ae9bbb0e..fdbb5cde03 100644 --- a/internal/engine/eval/rego/lib.go +++ b/internal/engine/eval/rego/lib.go @@ -50,20 +50,18 @@ var MinderRegoLib = []func(res *interfaces.Ingested) func(*rego.Rego){ ParseYaml, ParseToml, JQIsTrue, + BaseFileExists, + BaseFileLs, + BaseFileLsGlob, + BaseFileHTTPType, + BaseFileRead, + BaseFileWalk, + BaseListGithubActions, } // MinderRegoLibExperiments contains Minder-specific functions which // should only be exposed when the given experiment is enabled. var MinderRegoLibExperiments = map[flags.Experiment][]func(res *interfaces.Ingested) func(*rego.Rego){ - flags.GitPRDiffs: { - BaseFileExists, - BaseFileLs, - BaseFileLsGlob, - BaseFileHTTPType, - BaseFileRead, - BaseFileWalk, - BaseListGithubActions, - }, flags.DependencyExtract: { DependencyExtract, BaseDependencyExtract, diff --git a/internal/engine/eval/rego/lib_test.go b/internal/engine/eval/rego/lib_test.go index cda7e0739a..3b84925ab4 100644 --- a/internal/engine/eval/rego/lib_test.go +++ b/internal/engine/eval/rego/lib_test.go @@ -64,8 +64,6 @@ func TestFileExistsInBase(t *testing.T) { _, err := fs.Create("foo") require.NoError(t, err, "could not create file") - featureClient := &flags.FakeClient{} - featureClient.Data = map[string]any{"git_pr_diffs": true} e, err := rego.NewRegoEvaluator( &minderv1.RuleType_Definition_Eval_Rego{ Type: rego.DenyByDefaultEvaluationType.String(), @@ -78,7 +76,6 @@ allow { base_file.exists("foo") }`, }, - options.WithFlagsClient(featureClient), ) require.NoError(t, err, "could not create evaluator") diff --git a/pkg/flags/constants.go b/pkg/flags/constants.go index 1fe01f0278..5091ec819f 100644 --- a/pkg/flags/constants.go +++ b/pkg/flags/constants.go @@ -10,8 +10,6 @@ const ( GitLabProvider Experiment = "gitlab_provider" // AlternateMessageDriver enables an an alternate message driver. AlternateMessageDriver Experiment = "alternate_message_driver" - // GitPRDiffs enables the git ingester for pull requests. - GitPRDiffs Experiment = "git_pr_diffs" // DependencyExtract enables functions to perform dependency extraction. DependencyExtract Experiment = "dependency_extract" // ProjectCreateDelete enables creating top-level projects and deleting them. From fcf4ad6f235d4c8b40234dd173110165f97225ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 12:52:31 -0700 Subject: [PATCH 11/30] build(deps): bump lodash from 4.17.23 to 4.18.1 in /docs (#6260) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1) --- updated-dependencies: - dependency-name: lodash dependency-version: 4.18.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 3c75eb14a4..d93b776b3d 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -14167,9 +14167,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash-es": { From cd51b274fabb3db0d803cba03fac958f6cc70154 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 15:08:25 -0700 Subject: [PATCH 12/30] Auto-generated cli documentation update - 2026-04-03 12:06:15 (#6267) Update documentation Co-authored-by: evankanderson --- docs/docs/ref/cli/minder.md | 2 +- docs/docs/ref/cli/minder_repo.md | 22 ++++++++++++++++++++-- docs/docs/ref/cli/minder_repo_delete.md | 2 +- docs/docs/ref/cli/minder_repo_get.md | 2 +- docs/docs/ref/cli/minder_repo_list.md | 2 +- docs/docs/ref/cli/minder_repo_reconcile.md | 2 +- docs/docs/ref/cli/minder_repo_register.md | 2 +- 7 files changed, 26 insertions(+), 8 deletions(-) diff --git a/docs/docs/ref/cli/minder.md b/docs/docs/ref/cli/minder.md index 0e40b27a01..842fc9f094 100644 --- a/docs/docs/ref/cli/minder.md +++ b/docs/docs/ref/cli/minder.md @@ -35,7 +35,7 @@ https://mindersec.github.io/ * [minder project](minder_project.md) - Manage project within a minder control plane * [minder provider](minder_provider.md) - Manage providers within a minder control plane * [minder quickstart](minder_quickstart.md) - Quickstart minder -* [minder repo](minder_repo.md) - Manage repositories +* [minder repo](minder_repo.md) - Manage repositories within a Minder project * [minder ruletype](minder_ruletype.md) - Manage rule types * [minder set-project](minder_set-project.md) - Move the current context to another project * [minder version](minder_version.md) - Print minder CLI version diff --git a/docs/docs/ref/cli/minder_repo.md b/docs/docs/ref/cli/minder_repo.md index 6d6d3b48fa..9ff8e59b85 100644 --- a/docs/docs/ref/cli/minder_repo.md +++ b/docs/docs/ref/cli/minder_repo.md @@ -3,16 +3,34 @@ title: minder repo --- ## minder repo -Manage repositories +Manage repositories within a Minder project ### Synopsis -The repo commands allow the management of repositories within Minder. +Manage repositories within a Minder project. + +This command allows you to list, add, and manage repositories +connected to Minder for security analysis and policy enforcement. ``` minder repo [flags] ``` +### Examples + +``` + + # List repositories + minder repo list + + # Register a repository + minder repo register --name my-repo --provider github + + # Delete a repository + minder repo delete --name my-repo + +``` + ### Options ``` diff --git a/docs/docs/ref/cli/minder_repo_delete.md b/docs/docs/ref/cli/minder_repo_delete.md index e3669c90a3..c2f4ccf26c 100644 --- a/docs/docs/ref/cli/minder_repo_delete.md +++ b/docs/docs/ref/cli/minder_repo_delete.md @@ -37,5 +37,5 @@ minder repo delete [flags] ### SEE ALSO -* [minder repo](minder_repo.md) - Manage repositories +* [minder repo](minder_repo.md) - Manage repositories within a Minder project diff --git a/docs/docs/ref/cli/minder_repo_get.md b/docs/docs/ref/cli/minder_repo_get.md index 4962a2c413..620c4d79b4 100644 --- a/docs/docs/ref/cli/minder_repo_get.md +++ b/docs/docs/ref/cli/minder_repo_get.md @@ -38,5 +38,5 @@ minder repo get [flags] ### SEE ALSO -* [minder repo](minder_repo.md) - Manage repositories +* [minder repo](minder_repo.md) - Manage repositories within a Minder project diff --git a/docs/docs/ref/cli/minder_repo_list.md b/docs/docs/ref/cli/minder_repo_list.md index 8f08a1aa11..aad2d2d7ad 100644 --- a/docs/docs/ref/cli/minder_repo_list.md +++ b/docs/docs/ref/cli/minder_repo_list.md @@ -36,5 +36,5 @@ minder repo list [flags] ### SEE ALSO -* [minder repo](minder_repo.md) - Manage repositories +* [minder repo](minder_repo.md) - Manage repositories within a Minder project diff --git a/docs/docs/ref/cli/minder_repo_reconcile.md b/docs/docs/ref/cli/minder_repo_reconcile.md index d816c64a82..1ea41358ee 100644 --- a/docs/docs/ref/cli/minder_repo_reconcile.md +++ b/docs/docs/ref/cli/minder_repo_reconcile.md @@ -38,5 +38,5 @@ minder repo reconcile [flags] ### SEE ALSO -* [minder repo](minder_repo.md) - Manage repositories +* [minder repo](minder_repo.md) - Manage repositories within a Minder project diff --git a/docs/docs/ref/cli/minder_repo_register.md b/docs/docs/ref/cli/minder_repo_register.md index 86f4a85592..e8250344c9 100644 --- a/docs/docs/ref/cli/minder_repo_register.md +++ b/docs/docs/ref/cli/minder_repo_register.md @@ -37,5 +37,5 @@ minder repo register [flags] ### SEE ALSO -* [minder repo](minder_repo.md) - Manage repositories +* [minder repo](minder_repo.md) - Manage repositories within a Minder project From ae91fc20aebd2ebe7b02a9a0cec5e6a3c9db0057 Mon Sep 17 00:00:00 2001 From: Aabid Sattar Date: Sat, 4 Apr 2026 09:23:11 +0530 Subject: [PATCH 13/30] =?UTF-8?q?fix(metrics):=20swap=20incorrectly=20assi?= =?UTF-8?q?gned=20entity=20and=20profile=20duration=20m=E2=80=A6=20(#6270)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix(metrics): swap incorrectly assigned entity and profile duration metrics Signed-off-by: theycallmeaabie --- internal/engine/metrics.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/engine/metrics.go b/internal/engine/metrics.go index 2b4c9c8ba2..b0aa902605 100644 --- a/internal/engine/metrics.go +++ b/internal/engine/metrics.go @@ -48,15 +48,15 @@ func NewExecutorMetrics(meterFactory meters.MeterFactory) (*ExecutorMetrics, err return nil, fmt.Errorf("failed to create alert counter: %w", err) } - profileDuration, err := meter.Int64Histogram("eval.entity.duration", - metric.WithDescription("Time taken to evaluate all profiles against an entity"), + profileDuration, err := meter.Int64Histogram("eval.profile.duration", + metric.WithDescription("Time taken to evaluate a single profile against an entity"), metric.WithUnit("milliseconds")) if err != nil { return nil, fmt.Errorf("failed to create profile histogram: %w", err) } - entityDuration, err := meter.Int64Histogram("eval.profile.duration", - metric.WithDescription("Time taken to evaluate a single profile against an entity"), + entityDuration, err := meter.Int64Histogram("eval.entity.duration", + metric.WithDescription("Time taken to evaluate all profiles against an entity"), metric.WithUnit("milliseconds")) if err != nil { return nil, fmt.Errorf("failed to create entity histogram: %w", err) From 06783945a043f6c673e5aa74c9a120f3d83ef15a Mon Sep 17 00:00:00 2001 From: Dharun Date: Sat, 4 Apr 2026 09:53:02 +0530 Subject: [PATCH 14/30] removed dependency_extract feature flag (#6272) * removed dependency_extract feature flag Signed-off-by: DharunMR * solved lint issues Signed-off-by: DharunMR --------- Signed-off-by: DharunMR --- internal/engine/eval/rego/eval.go | 2 +- internal/engine/eval/rego/lib.go | 22 ++++------------------ internal/engine/eval/rego/lib_test.go | 3 --- pkg/flags/constants.go | 2 -- 4 files changed, 5 insertions(+), 24 deletions(-) diff --git a/internal/engine/eval/rego/eval.go b/internal/engine/eval/rego/eval.go index be9ef3ea54..ff8c27f9b2 100644 --- a/internal/engine/eval/rego/eval.go +++ b/internal/engine/eval/rego/eval.go @@ -145,7 +145,7 @@ func (e *Evaluator) Eval( } // Initialize the built-in minder library rego functions - regoFuncOptions = append(regoFuncOptions, instantiateRegoLib(ctx, e.featureFlags, res)...) + regoFuncOptions = append(regoFuncOptions, instantiateRegoLib(res)...) // If the evaluator has data sources defined, expose their functions regoFuncOptions = append(regoFuncOptions, buildDataSourceOptions(res, e.datasources)...) diff --git a/internal/engine/eval/rego/lib.go b/internal/engine/eval/rego/lib.go index fdbb5cde03..a0ebe110ef 100644 --- a/internal/engine/eval/rego/lib.go +++ b/internal/engine/eval/rego/lib.go @@ -33,7 +33,6 @@ import ( "github.com/mindersec/minder/internal/deps/scalibr" "github.com/mindersec/minder/internal/util" "github.com/mindersec/minder/pkg/engine/v1/interfaces" - "github.com/mindersec/minder/pkg/flags" ) // MinderRegoLib contains the minder-specific functions for rego @@ -57,29 +56,16 @@ var MinderRegoLib = []func(res *interfaces.Ingested) func(*rego.Rego){ BaseFileRead, BaseFileWalk, BaseListGithubActions, + DependencyExtract, + BaseDependencyExtract, } -// MinderRegoLibExperiments contains Minder-specific functions which -// should only be exposed when the given experiment is enabled. -var MinderRegoLibExperiments = map[flags.Experiment][]func(res *interfaces.Ingested) func(*rego.Rego){ - flags.DependencyExtract: { - DependencyExtract, - BaseDependencyExtract, - }, -} - -func instantiateRegoLib(ctx context.Context, featureFlags flags.Interface, res *interfaces.Ingested) []func(*rego.Rego) { +func instantiateRegoLib(res *interfaces.Ingested) []func(*rego.Rego) { var lib []func(*rego.Rego) for _, f := range MinderRegoLib { lib = append(lib, f(res)) } - for flag, funcs := range MinderRegoLibExperiments { - if flags.Bool(ctx, featureFlags, flag) { - for _, f := range funcs { - lib = append(lib, f(res)) - } - } - } + return lib } diff --git a/internal/engine/eval/rego/lib_test.go b/internal/engine/eval/rego/lib_test.go index 3b84925ab4..11a7c09511 100644 --- a/internal/engine/eval/rego/lib_test.go +++ b/internal/engine/eval/rego/lib_test.go @@ -1231,8 +1231,6 @@ require ( require.NoError(t, billyutil.WriteFile(fs, "foo/go.mod", []byte(goMod), 0644)) require.NoError(t, billyutil.WriteFile(fs, "requirements.txt", []byte("PyYAML>=5.3.1"), 0644)) - featureClient := &flags.FakeClient{} - featureClient.Data = map[string]any{"dependency_extract": true} e, err := rego.NewRegoEvaluator( &minderv1.RuleType_Definition_Eval_Rego{ Type: rego.DenyByDefaultEvaluationType.String(), @@ -1253,7 +1251,6 @@ allow if { } `, }, - options.WithFlagsClient(featureClient), ) require.NoError(t, err, "could not create evaluator") diff --git a/pkg/flags/constants.go b/pkg/flags/constants.go index 5091ec819f..8730be78f5 100644 --- a/pkg/flags/constants.go +++ b/pkg/flags/constants.go @@ -10,8 +10,6 @@ const ( GitLabProvider Experiment = "gitlab_provider" // AlternateMessageDriver enables an an alternate message driver. AlternateMessageDriver Experiment = "alternate_message_driver" - // DependencyExtract enables functions to perform dependency extraction. - DependencyExtract Experiment = "dependency_extract" // ProjectCreateDelete enables creating top-level projects and deleting them. ProjectCreateDelete Experiment = "project_create_delete" // AuthenticatedDataSources enables provider authentication for data sources. From 064834f06c9a8105e9edef76c883da83c3186454 Mon Sep 17 00:00:00 2001 From: Sachin Kumar <69066918+sachin9058@users.noreply.github.com> Date: Sat, 4 Apr 2026 09:53:15 +0530 Subject: [PATCH 15/30] Decouple pkg/engine/errors from internal/db using adapter layer (#6266) * Move internal/engine/errors to pkg/engine/errors to reduce coupling Signed-off-by: Sachin Kumar * fix: resolve lint issues * refactor: decouple engine errors from internal/db via adapter layer * fix: add package comment and correct license header * fix: cleanup imports and resolve lint issues * fix: update generated protobuf files --------- Signed-off-by: Sachin Kumar --- internal/adapters/db/errors.go | 142 ++++++++++++++++++ internal/engine/actions/actions.go | 7 +- .../pull_request_comment.go | 5 +- .../security_advisory/security_advisory.go | 5 +- .../remediate/pull_request/pull_request.go | 3 +- internal/engine/eval/rego/rego_test.go | 7 +- internal/engine/eval_status.go | 7 +- internal/engine/executor.go | 7 +- internal/history/service.go | 6 +- internal/logger/telemetry_store.go | 8 +- pkg/engine/errors/errors.go | 139 +---------------- 11 files changed, 180 insertions(+), 156 deletions(-) create mode 100644 internal/adapters/db/errors.go diff --git a/internal/adapters/db/errors.go b/internal/adapters/db/errors.go new file mode 100644 index 0000000000..324ba2b30d --- /dev/null +++ b/internal/adapters/db/errors.go @@ -0,0 +1,142 @@ +// SPDX-FileCopyrightText: Copyright 2026 The Minder Authors +// SPDX-License-Identifier: Apache-2.0 + +// Package dbadapter provides database-specific error mappings between +// engine errors and database status types. +package dbadapter + +import ( + "errors" + "fmt" + + "github.com/mindersec/minder/internal/db" + engineerrors "github.com/mindersec/minder/pkg/engine/errors" + "github.com/mindersec/minder/pkg/engine/v1/interfaces" +) + +// ErrorAsEvalStatus returns the evaluation status for a given error +func ErrorAsEvalStatus(err error) db.EvalStatusTypes { + if errors.Is(err, interfaces.ErrEvaluationFailed) { + return db.EvalStatusTypesFailure + } else if errors.Is(err, interfaces.ErrEvaluationSkipped) { + return db.EvalStatusTypesSkipped + } else if err != nil { + return db.EvalStatusTypesError + } + return db.EvalStatusTypesSuccess +} + +// ErrorAsEvalDetails returns the evaluation details for a given error +func ErrorAsEvalDetails(err error) string { + var evalErr *engineerrors.EvaluationError + if errors.As(err, &evalErr) && evalErr.Template != "" { + return evalErr.Details() + } + if errors.As(err, &evalErr) { + return evalErr.Msg + } + if err != nil { + return err.Error() + } + return "" +} + +// ErrorAsRemediationStatus returns the remediation status for a given error +func ErrorAsRemediationStatus(err error) db.RemediationStatusTypes { + if err == nil { + return db.RemediationStatusTypesSuccess + } + + switch { + case errors.Is(err, engineerrors.ErrActionFailed): + return db.RemediationStatusTypesFailure + case errors.Is(err, engineerrors.ErrActionSkipped): + return db.RemediationStatusTypesSkipped + case errors.Is(err, engineerrors.ErrActionNotAvailable): + return db.RemediationStatusTypesNotAvailable + case errors.Is(err, engineerrors.ErrActionPending): + return db.RemediationStatusTypesPending + } + return db.RemediationStatusTypesError +} + +// RemediationStatusAsError returns the remediation status for a given error +func RemediationStatusAsError(prevStatus *db.ListRuleEvaluationsByProfileIdRow) error { + if prevStatus == nil { + return engineerrors.ErrActionSkipped + } + + s := prevStatus.RemStatus + switch s { + case db.RemediationStatusTypesSuccess: + return nil + case db.RemediationStatusTypesFailure: + return engineerrors.ErrActionFailed + case db.RemediationStatusTypesSkipped: + return engineerrors.ErrActionSkipped + case db.RemediationStatusTypesNotAvailable: + return engineerrors.ErrActionNotAvailable + case db.RemediationStatusTypesPending: + return engineerrors.ErrActionPending + case db.RemediationStatusTypesError: + return fmt.Errorf("generic remediation error status: %s", s) + } + return fmt.Errorf("generic remediation error status: %s", s) +} + +// ErrorAsAlertStatus returns the alert status for a given error +func ErrorAsAlertStatus(err error) db.AlertStatusTypes { + if err == nil { + return db.AlertStatusTypesOn + } + + switch { + case errors.Is(err, engineerrors.ErrActionTurnedOff): + return db.AlertStatusTypesOff + case errors.Is(err, engineerrors.ErrActionFailed): + return db.AlertStatusTypesError + case errors.Is(err, engineerrors.ErrActionSkipped): + return db.AlertStatusTypesSkipped + case errors.Is(err, engineerrors.ErrActionNotAvailable): + return db.AlertStatusTypesNotAvailable + } + return db.AlertStatusTypesError +} + +// AlertStatusAsError returns the error for a given alert status +func AlertStatusAsError(prevStatus *db.ListRuleEvaluationsByProfileIdRow) error { + if prevStatus == nil { + return errors.New("no previous alert state") + } + + s := prevStatus.AlertStatus + + switch s { + case db.AlertStatusTypesOn: + return nil + case db.AlertStatusTypesOff: + return engineerrors.ErrActionTurnedOff + case db.AlertStatusTypesError: + return engineerrors.ErrActionFailed + case db.AlertStatusTypesSkipped: + return engineerrors.ErrActionSkipped + case db.AlertStatusTypesNotAvailable: + return engineerrors.ErrActionNotAvailable + } + return fmt.Errorf("unknown alert status: %s", s) +} + +// EvalErrorAsString returns the evaluation error as a string +func EvalErrorAsString(err error) string { + return string(ErrorAsEvalStatus(err)) +} + +// RemediationErrorAsString returns the remediation error as a string +func RemediationErrorAsString(err error) string { + return string(ErrorAsRemediationStatus(err)) +} + +// AlertErrorAsString returns the alert error as a string +func AlertErrorAsString(err error) string { + return string(ErrorAsAlertStatus(err)) +} diff --git a/internal/engine/actions/actions.go b/internal/engine/actions/actions.go index fdc6c494aa..e1f6052728 100644 --- a/internal/engine/actions/actions.go +++ b/internal/engine/actions/actions.go @@ -15,6 +15,7 @@ import ( "github.com/rs/zerolog" "google.golang.org/protobuf/reflect/protoreflect" + dbadapter "github.com/mindersec/minder/internal/adapters/db" "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/internal/engine/actions/alert" "github.com/mindersec/minder/internal/engine/actions/remediate" @@ -138,7 +139,7 @@ func (rae *RuleActionsEngine) processAction( // shouldRemediate returns the action command for remediation taking into account previous evaluations func shouldRemediate(prevEvalFromDb *db.ListRuleEvaluationsByProfileIdRow, evalErr error) engif.ActionCmd { // Get current evaluation status - newEval := enginerr.ErrorAsEvalStatus(evalErr) + newEval := dbadapter.ErrorAsEvalStatus(evalErr) // Get previous Remediation status prevRemediation := db.RemediationStatusTypesSkipped @@ -187,7 +188,7 @@ func shouldAlert( remType string, ) engif.ActionCmd { // Get current evaluation status - newEval := enginerr.ErrorAsEvalStatus(evalErr) + newEval := dbadapter.ErrorAsEvalStatus(evalErr) // Get previous Alert status prevAlert := db.AlertStatusTypesSkipped @@ -242,7 +243,7 @@ func (rae *RuleActionsEngine) isSkippable(ctx context.Context, actionType engif. var skipAction bool logger := zerolog.Ctx(ctx).Info(). - Str("eval_status", string(enginerr.ErrorAsEvalStatus(evalErr))). + Str("eval_status", string(dbadapter.ErrorAsEvalStatus(evalErr))). Str("action", string(actionType)) // Get the profile option set for this action type diff --git a/internal/engine/actions/alert/pull_request_comment/pull_request_comment.go b/internal/engine/actions/alert/pull_request_comment/pull_request_comment.go index f827c4956f..c5748dd95b 100644 --- a/internal/engine/actions/alert/pull_request_comment/pull_request_comment.go +++ b/internal/engine/actions/alert/pull_request_comment/pull_request_comment.go @@ -18,6 +18,7 @@ import ( "github.com/rs/zerolog" "google.golang.org/protobuf/reflect/protoreflect" + dbadapter "github.com/mindersec/minder/internal/adapters/db" "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/internal/engine/interfaces" pbinternal "github.com/mindersec/minder/internal/proto" @@ -236,7 +237,7 @@ func (*Alert) runDoNothing(ctx context.Context, params *paramsPR) (json.RawMessa logger.Debug().Msg("Running do nothing") // Return the previous alert status. - err := enginerr.AlertStatusAsError(params.prevStatus) + err := dbadapter.AlertStatusAsError(params.prevStatus) // If there is a valid alert metadata, return it too if params.prevStatus != nil { return params.prevStatus.AlertMetadata, err @@ -273,7 +274,7 @@ func (alert *Alert) getParamsForPRComment( } tmplParams := &PrCommentTemplateParams{ - EvalErrorDetails: enginerr.ErrorAsEvalDetails(params.GetEvalErr()), + EvalErrorDetails: dbadapter.ErrorAsEvalDetails(params.GetEvalErr()), } if params.GetEvalResult() != nil { diff --git a/internal/engine/actions/alert/security_advisory/security_advisory.go b/internal/engine/actions/alert/security_advisory/security_advisory.go index 7c9c9860af..c9e87fd71b 100644 --- a/internal/engine/actions/alert/security_advisory/security_advisory.go +++ b/internal/engine/actions/alert/security_advisory/security_advisory.go @@ -17,6 +17,7 @@ import ( "github.com/rs/zerolog" "google.golang.org/protobuf/reflect/protoreflect" + dbadapter "github.com/mindersec/minder/internal/adapters/db" "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/internal/engine/interfaces" pbinternal "github.com/mindersec/minder/internal/proto" @@ -367,7 +368,7 @@ func (alert *Alert) getParamsForSecurityAdvisory( } result.Summary = summaryStr.String() - result.Template.EvaluationError = enginerr.ErrorAsEvalDetails(params.GetEvalErr()) + result.Template.EvaluationError = dbadapter.ErrorAsEvalDetails(params.GetEvalErr()) var descriptionStr strings.Builder // Get the description template depending if remediation is available @@ -402,7 +403,7 @@ func (*Alert) runDoNothing(ctx context.Context, params *paramsSA) (json.RawMessa logger.Debug().Msg("Running do nothing") // Return the previous alert status. - err := enginerr.AlertStatusAsError(params.prevStatus) + err := dbadapter.AlertStatusAsError(params.prevStatus) // If there is a valid alert metadata, return it too if params.prevStatus != nil { return params.prevStatus.AlertMetadata, err diff --git a/internal/engine/actions/remediate/pull_request/pull_request.go b/internal/engine/actions/remediate/pull_request/pull_request.go index a40e3eac5a..079ef6d321 100644 --- a/internal/engine/actions/remediate/pull_request/pull_request.go +++ b/internal/engine/actions/remediate/pull_request/pull_request.go @@ -23,6 +23,7 @@ import ( "github.com/rs/zerolog" "google.golang.org/protobuf/proto" + dbadapter "github.com/mindersec/minder/internal/adapters/db" "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/internal/engine/interfaces" "github.com/mindersec/minder/internal/util" @@ -577,7 +578,7 @@ func (*Remediator) runDoNothing(ctx context.Context, p *paramsPR) (json.RawMessa logger.Debug().Msg("Running do nothing") // Return the previous remediation status. - err := enginerr.RemediationStatusAsError(p.prevStatus) + err := dbadapter.RemediationStatusAsError(p.prevStatus) // If there is a valid remediation metadata, return it too if p.prevStatus != nil { return p.prevStatus.RemMetadata, err diff --git a/internal/engine/eval/rego/rego_test.go b/internal/engine/eval/rego/rego_test.go index 8bdf3dfe0d..e8b39af954 100644 --- a/internal/engine/eval/rego/rego_test.go +++ b/internal/engine/eval/rego/rego_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + dbadapter "github.com/mindersec/minder/internal/adapters/db" "github.com/mindersec/minder/internal/engine/eval/rego" "github.com/mindersec/minder/internal/engine/options" "github.com/mindersec/minder/internal/util/ptr" @@ -634,7 +635,7 @@ func TestConstraintsJSONOutput(t *testing.T) { require.ErrorIs(t, err, interfaces.ErrEvaluationFailed, "should have failed the evaluation") // check that the error payload msg is JSON in the expected format - errmsg := engerrors.ErrorAsEvalDetails(err) + errmsg := dbadapter.ErrorAsEvalDetails(err) var errDetails []struct { ActionsNotAllowed []string `json:"actions_not_allowed"` } @@ -684,7 +685,7 @@ violations[{"msg": msg}] { require.ErrorIs(t, err, interfaces.ErrEvaluationFailed, "should have failed the evaluation") // check that the error payload msg is JSON in the expected format - errmsg := engerrors.ErrorAsEvalDetails(err) + errmsg := dbadapter.ErrorAsEvalDetails(err) var errDetails []struct { Msg string `json:"msg"` } @@ -720,7 +721,7 @@ func TestOutputTypePassedIntoRule(t *testing.T) { require.Error(t, err, "should have failed the evaluation") require.ErrorIs(t, err, interfaces.ErrEvaluationFailed, "should have failed the evaluation") - errmsg := engerrors.ErrorAsEvalDetails(err) + errmsg := dbadapter.ErrorAsEvalDetails(err) assert.Contains(t, errmsg, "extra actions found in workflows but not allowed in the profile", "should have the expected error message") assert.Contains(t, errmsg, "three", "should have the expected content") assert.Equal(t, []any{`extra actions found in workflows but not allowed in the profile: ["three"]`}, res.Output) diff --git a/internal/engine/eval_status.go b/internal/engine/eval_status.go index c263d56dc5..dc7bce1ded 100644 --- a/internal/engine/eval_status.go +++ b/internal/engine/eval_status.go @@ -12,6 +12,7 @@ import ( "github.com/rs/zerolog" + dbadapter "github.com/mindersec/minder/internal/adapters/db" "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/internal/engine/entities" engif "github.com/mindersec/minder/internal/engine/interfaces" @@ -99,13 +100,13 @@ func (e *executor) createOrUpdateEvalStatus( return nil } - status := evalerrors.ErrorAsEvalStatus(params.GetEvalErr()) + status := dbadapter.ErrorAsEvalStatus(params.GetEvalErr()) e.metrics.CountEvalStatus(ctx, status, params.EntityType) - remediationStatus := evalerrors.ErrorAsRemediationStatus(params.GetActionsErr().RemediateErr) + remediationStatus := dbadapter.ErrorAsRemediationStatus(params.GetActionsErr().RemediateErr) e.metrics.CountRemediationStatus(ctx, remediationStatus) - alertStatus := evalerrors.ErrorAsAlertStatus(params.GetActionsErr().AlertErr) + alertStatus := dbadapter.ErrorAsAlertStatus(params.GetActionsErr().AlertErr) e.metrics.CountAlertStatus(ctx, alertStatus) chckpoint := params.GetIngestResult().GetCheckpoint() diff --git a/internal/engine/executor.go b/internal/engine/executor.go index c219f13dcc..02db1087f5 100644 --- a/internal/engine/executor.go +++ b/internal/engine/executor.go @@ -11,6 +11,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + dbadapter "github.com/mindersec/minder/internal/adapters/db" datasourceservice "github.com/mindersec/minder/internal/datasources/service" "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/internal/engine/actions" @@ -312,16 +313,16 @@ func logEval( ) { evalLog := params.DecorateLogger( zerolog.Ctx(ctx).With(). - Str("eval_status", string(evalerrors.ErrorAsEvalStatus(params.GetEvalErr()))). + Str("eval_status", string(dbadapter.ErrorAsEvalStatus(params.GetEvalErr()))). Str("project_id", inf.ProjectID.String()). Logger()) // log evaluation result and actions status evalLog.Info(). Str("action", string(remediate.ActionType)). - Str("action_status", string(evalerrors.ErrorAsRemediationStatus(params.GetActionsErr().RemediateErr))). + Str("action_status", string(dbadapter.ErrorAsRemediationStatus(params.GetActionsErr().RemediateErr))). Str("action", string(alert.ActionType)). - Str("action_status", string(evalerrors.ErrorAsAlertStatus(params.GetActionsErr().AlertErr))). + Str("action_status", string(dbadapter.ErrorAsAlertStatus(params.GetActionsErr().AlertErr))). Msg("entity evaluation - completed") // log business logic diff --git a/internal/history/service.go b/internal/history/service.go index 8f81b675b1..b18f426c0d 100644 --- a/internal/history/service.go +++ b/internal/history/service.go @@ -15,10 +15,10 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + dbadapter "github.com/mindersec/minder/internal/adapters/db" "github.com/mindersec/minder/internal/db" propertiessvc "github.com/mindersec/minder/internal/entities/properties/service" "github.com/mindersec/minder/internal/providers/manager" - evalerrors "github.com/mindersec/minder/pkg/engine/errors" ) //go:generate go run go.uber.org/mock/mockgen -package mock_$GOPACKAGE -destination=./mock/$GOFILE -source=./$GOFILE @@ -91,8 +91,8 @@ func (e *evaluationHistoryService) StoreEvaluationStatus( output any, ) (uuid.UUID, error) { var ruleEntityID uuid.UUID - status := evalerrors.ErrorAsEvalStatus(evalError) - details := evalerrors.ErrorAsEvalDetails(evalError) + status := dbadapter.ErrorAsEvalStatus(evalError) + details := dbadapter.ErrorAsEvalDetails(evalError) params := paramsFromEntity(ruleID, entityID) diff --git a/internal/logger/telemetry_store.go b/internal/logger/telemetry_store.go index 16e5fcb7e6..7fbb16dd14 100644 --- a/internal/logger/telemetry_store.go +++ b/internal/logger/telemetry_store.go @@ -10,10 +10,10 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + dbadapter "github.com/mindersec/minder/internal/adapters/db" "github.com/mindersec/minder/internal/engine/actions/alert" "github.com/mindersec/minder/internal/engine/actions/remediate" "github.com/mindersec/minder/internal/engine/interfaces" - "github.com/mindersec/minder/pkg/engine/errors" ) type key int @@ -131,7 +131,7 @@ func (ts *TelemetryStore) AddRuleEval( red := RuleEvalData{ RuleType: RuleType{Name: ruleTypeName, ID: evalInfo.GetRule().RuleTypeID}, Profile: Profile{Name: evalInfo.GetProfile().Name, ID: evalInfo.GetProfile().ID}, - EvalResult: errors.EvalErrorAsString(evalInfo.GetEvalErr()), + EvalResult: dbadapter.EvalErrorAsString(evalInfo.GetEvalErr()), Actions: map[interfaces.ActionType]ActionEvalData{}, } @@ -139,11 +139,11 @@ func (ts *TelemetryStore) AddRuleEval( actionCfg := p.ActionConfig red.Actions[remediate.ActionType] = ActionEvalData{ State: actionCfg.Remediate.String(), - Result: errors.RemediationErrorAsString(evalInfo.GetActionsErr().RemediateErr), + Result: dbadapter.RemediationErrorAsString(evalInfo.GetActionsErr().RemediateErr), } red.Actions[alert.ActionType] = ActionEvalData{ State: actionCfg.Alert.String(), - Result: errors.AlertErrorAsString(evalInfo.GetActionsErr().AlertErr), + Result: dbadapter.AlertErrorAsString(evalInfo.GetActionsErr().AlertErr), } } diff --git a/pkg/engine/errors/errors.go b/pkg/engine/errors/errors.go index 9357b47a7c..ab083fdd5c 100644 --- a/pkg/engine/errors/errors.go +++ b/pkg/engine/errors/errors.go @@ -12,7 +12,6 @@ import ( "strings" "text/template" - "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/pkg/engine/v1/interfaces" ) @@ -178,136 +177,30 @@ type ActionsError struct { AlertMeta json.RawMessage } -// ErrorAsEvalStatus returns the evaluation status for a given error -func ErrorAsEvalStatus(err error) db.EvalStatusTypes { - if errors.Is(err, interfaces.ErrEvaluationFailed) { - return db.EvalStatusTypesFailure - } else if errors.Is(err, interfaces.ErrEvaluationSkipped) { - return db.EvalStatusTypesSkipped - } else if err != nil { - return db.EvalStatusTypesError - } - return db.EvalStatusTypesSuccess -} - -// ErrorAsEvalDetails returns the evaluation details for a given error -func ErrorAsEvalDetails(err error) string { - var evalErr *EvaluationError - if errors.As(err, &evalErr) && evalErr.Template != "" { - return evalErr.Details() - } - if errors.As(err, &evalErr) { - return evalErr.Msg - } - if err != nil { - return err.Error() - } - return "" -} - -// ErrorAsRemediationStatus returns the remediation status for a given error -func ErrorAsRemediationStatus(err error) db.RemediationStatusTypes { - if err == nil { - return db.RemediationStatusTypesSuccess - } - - switch err != nil { - case errors.Is(err, ErrActionFailed): - return db.RemediationStatusTypesFailure - case errors.Is(err, ErrActionSkipped): - return db.RemediationStatusTypesSkipped - case errors.Is(err, ErrActionNotAvailable): - return db.RemediationStatusTypesNotAvailable - case errors.Is(err, ErrActionPending): - return db.RemediationStatusTypesPending - } - return db.RemediationStatusTypesError -} - -// RemediationStatusAsError returns the remediation status for a given error -func RemediationStatusAsError(prevStatus *db.ListRuleEvaluationsByProfileIdRow) error { - if prevStatus == nil { - return ErrActionSkipped - } - - s := prevStatus.RemStatus - switch s { - case db.RemediationStatusTypesSuccess: - return nil - case db.RemediationStatusTypesFailure: - return ErrActionFailed - case db.RemediationStatusTypesSkipped: - return ErrActionSkipped - case db.RemediationStatusTypesNotAvailable: - return ErrActionNotAvailable - case db.RemediationStatusTypesPending: - return ErrActionPending - case db.RemediationStatusTypesError: - return fmt.Errorf("generic remediation error status: %s", s) - } - return fmt.Errorf("generic remediation error status: %s", s) -} - -// ErrorAsAlertStatus returns the alert status for a given error -func ErrorAsAlertStatus(err error) db.AlertStatusTypes { - if err == nil { - return db.AlertStatusTypesOn - } - - switch err != nil { - case errors.Is(err, ErrActionTurnedOff): - return db.AlertStatusTypesOff - case errors.Is(err, ErrActionFailed): - return db.AlertStatusTypesError - case errors.Is(err, ErrActionSkipped): - return db.AlertStatusTypesSkipped - case errors.Is(err, ErrActionNotAvailable): - return db.AlertStatusTypesNotAvailable - } - return db.AlertStatusTypesError -} - -// AlertStatusAsError returns the error for a given alert status -func AlertStatusAsError(prevStatus *db.ListRuleEvaluationsByProfileIdRow) error { - if prevStatus == nil { - return errors.New("no previous alert state") - } - - s := prevStatus.AlertStatus - - switch s { - case db.AlertStatusTypesOn: - return nil - case db.AlertStatusTypesOff: - return ErrActionTurnedOff - case db.AlertStatusTypesError: - return ErrActionFailed - case db.AlertStatusTypesSkipped: - return ErrActionSkipped - case db.AlertStatusTypesNotAvailable: - return ErrActionNotAvailable - } - return fmt.Errorf("unknown alert status: %s", s) -} - var ( // ErrUnauthorized is returned when a request is unauthorized ErrUnauthorized = errors.New("unauthorized") + // ErrForbidden is returned when a request is forbidden ErrForbidden = errors.New("forbidden") + // ErrNotFound is returned when a resource is not found ErrNotFound = errors.New("not found") + // ErrValidateOrSpammed is returned when a request is a validation or spammed error ErrValidateOrSpammed = errors.New("validation or spammed error") + // ErrClientError is returned when a request is a client error ErrClientError = errors.New("client error") + // ErrServerError is returned when a request is a server error ErrServerError = errors.New("server error") + // ErrOther is returned when a request is another error ErrOther = errors.New("other error") ) -// HTTPErrorCodeToErr converts an HTTP error code to an error +// HTTPErrorCodeToErr returns an engine error corresponding to the given HTTP status code. func HTTPErrorCodeToErr(httpCode int) error { var err = ErrOther @@ -330,21 +223,3 @@ func HTTPErrorCodeToErr(httpCode int) error { return err } - -// EvalErrorAsString returns the evaluation error as a string -func EvalErrorAsString(err error) string { - dbEvalStatus := ErrorAsEvalStatus(err) - return string(dbEvalStatus) -} - -// RemediationErrorAsString returns the remediation error as a string -func RemediationErrorAsString(err error) string { - dbRemediationStatus := ErrorAsRemediationStatus(err) - return string(dbRemediationStatus) -} - -// AlertErrorAsString returns the alert error as a string -func AlertErrorAsString(err error) string { - dbAlertStatus := ErrorAsAlertStatus(err) - return string(dbAlertStatus) -} From 1d989bd11d1e96e1ac466a248a20845cc705bae7 Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Sun, 5 Apr 2026 17:26:16 +0530 Subject: [PATCH 16/30] feat: expose executor timeout configuration and add validation, logging, and tests --- internal/engine/handler.go | 14 +++++++++++++- internal/engine/handler_test.go | 33 +++++++++++++++++++++++++++++++++ internal/service/service.go | 1 + 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/internal/engine/handler.go b/internal/engine/handler.go index a6d5354e83..f86e21b932 100644 --- a/internal/engine/handler.go +++ b/internal/engine/handler.go @@ -51,14 +51,21 @@ func NewExecutorEventHandler( evt interfaces.Publisher, handlerMiddleware []message.HandlerMiddleware, executor Executor, + executionTimeout time.Duration, ) *ExecutorEventHandler { + if executionTimeout <= 0 { + executionTimeout = DefaultExecutionTimeout + } eh := &ExecutorEventHandler{ evt: evt, wgEntityEventExecution: &sync.WaitGroup{}, handlerMiddleware: handlerMiddleware, executor: executor, - executionTimeout: DefaultExecutionTimeout, + executionTimeout: executionTimeout, } + zerolog.Ctx(ctx).Info(). + Dur("execution_timeout", executionTimeout). + Msg("executor event handler initialized") go func() { <-ctx.Done() eh.lock.Lock() @@ -82,6 +89,11 @@ func (e *ExecutorEventHandler) Wait() { e.wgEntityEventExecution.Wait() } +// ExecutionTimeout returns the configured execution timeout for the handler. +func (e *ExecutorEventHandler) ExecutionTimeout() time.Duration { + return e.executionTimeout +} + // HandleEntityEvent handles events coming from webhooks/signals // as well as the init event. func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { diff --git a/internal/engine/handler_test.go b/internal/engine/handler_test.go index c5aa3cc4cc..447b65fa3b 100644 --- a/internal/engine/handler_test.go +++ b/internal/engine/handler_test.go @@ -83,6 +83,7 @@ func TestExecutorEventHandler_handleEntityEvent(t *testing.T) { evt, []message.HandlerMiddleware{}, executor, + engine.DefaultExecutionTimeout, ) t.Log("waiting for eventer to start") @@ -114,3 +115,35 @@ func TestExecutorEventHandler_handleEntityEvent(t *testing.T) { t.Log("waiting for executor to finish") handler.Wait() } + +func TestExecutorEventHandler_CustomTimeout(t *testing.T) { + t.Parallel() + + handler := engine.NewExecutorEventHandler( + context.Background(), + nil, + nil, + nil, + 10*time.Second, + ) + + if handler.ExecutionTimeout() != 10*time.Second { + t.Fatalf("expected 10s, got %v", handler.ExecutionTimeout()) + } +} + +func TestExecutorEventHandler_DefaultTimeoutFallback(t *testing.T) { + t.Parallel() + + handler := engine.NewExecutorEventHandler( + context.Background(), + nil, + nil, + nil, + 0, + ) + + if handler.ExecutionTimeout() != engine.DefaultExecutionTimeout { + t.Fatalf("expected default timeout, got %v", handler.ExecutionTimeout()) + } +} diff --git a/internal/service/service.go b/internal/service/service.go index 87856e9d82..7232d25c82 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -265,6 +265,7 @@ func AllInOneServerService( evt, executorMiddleware, exec, + engine.DefaultExecutionTimeout, ) evt.ConsumeEvents(handler) From 817bbd36755b378d1ee32b514efe50c36139780d Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Sun, 5 Apr 2026 17:48:18 +0530 Subject: [PATCH 17/30] test: disable parallel execution for profile DB test to avoid unique constraint conflicts --- internal/db/profiles_test.go | 4 ++-- internal/engine/handler.go | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/internal/db/profiles_test.go b/internal/db/profiles_test.go index 5f3aabaad4..6e67b2ca18 100644 --- a/internal/db/profiles_test.go +++ b/internal/db/profiles_test.go @@ -498,7 +498,7 @@ func TestProfileLabels(t *testing.T) { } func TestCreateProfileStatusSingleRuleTransitions(t *testing.T) { - t.Parallel() + // t.Parallel() tests := []struct { name string @@ -633,7 +633,7 @@ func TestCreateProfileStatusSingleRuleTransitions(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - t.Parallel() + // t.Parallel() profile := createRandomProfile(t, randomEntities.proj.ID, []string{}) ruleID := createRuleInstance(t, profile.ID, randomEntities.ruleType1.ID, profile.ProjectID) diff --git a/internal/engine/handler.go b/internal/engine/handler.go index f86e21b932..fec2ddfe4f 100644 --- a/internal/engine/handler.go +++ b/internal/engine/handler.go @@ -129,7 +129,12 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { time.Sleep(ArtifactSignatureWaitPeriod) } - ctx, cancel := context.WithTimeout(msgCtx, e.executionTimeout) + ctx := msgCtx + var cancel context.CancelFunc = func() {} + + if _, ok := msgCtx.Deadline(); !ok { + ctx, cancel = context.WithTimeout(msgCtx, e.executionTimeout) + } defer cancel() defer func() { e.lock.Lock() From 38b63a1fc6ab484511aa97c89324dbdc746d8e8d Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Sun, 5 Apr 2026 18:01:38 +0530 Subject: [PATCH 18/30] lint-skipped-for-parallel-tests --- internal/db/profiles_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/db/profiles_test.go b/internal/db/profiles_test.go index 6e67b2ca18..b0786fc33d 100644 --- a/internal/db/profiles_test.go +++ b/internal/db/profiles_test.go @@ -497,8 +497,8 @@ func TestProfileLabels(t *testing.T) { } } +//nolint:paralleltest // DB test uses shared state, cannot run in parallel func TestCreateProfileStatusSingleRuleTransitions(t *testing.T) { - // t.Parallel() tests := []struct { name string @@ -631,9 +631,10 @@ func TestCreateProfileStatusSingleRuleTransitions(t *testing.T) { randomEntities := createTestRandomEntities(t) for _, tt := range tests { + tt := tt // capture range variable t.Run(tt.name, func(t *testing.T) { - // t.Parallel() + //nolint:paralleltest // DB test, must not run in parallel profile := createRandomProfile(t, randomEntities.proj.ID, []string{}) ruleID := createRuleInstance(t, profile.ID, randomEntities.ruleType1.ID, profile.ProjectID) From 4773bbaef940fa203d351bae310def239f1c17a8 Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Sun, 5 Apr 2026 18:14:09 +0530 Subject: [PATCH 19/30] avoid enforced timeout at handler level --- internal/engine/handler.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/internal/engine/handler.go b/internal/engine/handler.go index fec2ddfe4f..1df1f2022c 100644 --- a/internal/engine/handler.go +++ b/internal/engine/handler.go @@ -130,11 +130,7 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { } ctx := msgCtx - var cancel context.CancelFunc = func() {} - - if _, ok := msgCtx.Deadline(); !ok { - ctx, cancel = context.WithTimeout(msgCtx, e.executionTimeout) - } + cancel := func() {} defer cancel() defer func() { e.lock.Lock() From d662ebbc84c6b22d6f58ad25d424af7826c17519 Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Mon, 6 Apr 2026 12:37:59 +0530 Subject: [PATCH 20/30] Make execution timeout configurable and improve test parallelization --- internal/db/profiles_test.go | 5 +- internal/engine/handler.go | 57 +++++++++----------- internal/engine/handler_test.go | 93 ++++++++++++++++++++------------- 3 files changed, 84 insertions(+), 71 deletions(-) diff --git a/internal/db/profiles_test.go b/internal/db/profiles_test.go index b0786fc33d..9c74b48deb 100644 --- a/internal/db/profiles_test.go +++ b/internal/db/profiles_test.go @@ -497,7 +497,7 @@ func TestProfileLabels(t *testing.T) { } } -//nolint:paralleltest // DB test uses shared state, cannot run in parallel +//nolint:paralleltest,tparallel // top-level parallel causes interference with other tests (gomock/shared state) func TestCreateProfileStatusSingleRuleTransitions(t *testing.T) { tests := []struct { @@ -631,10 +631,9 @@ func TestCreateProfileStatusSingleRuleTransitions(t *testing.T) { randomEntities := createTestRandomEntities(t) for _, tt := range tests { - tt := tt // capture range variable t.Run(tt.name, func(t *testing.T) { - //nolint:paralleltest // DB test, must not run in parallel + t.Parallel() profile := createRandomProfile(t, randomEntities.proj.ID, []string{}) ruleID := createRuleInstance(t, profile.ID, randomEntities.ruleType1.ID, profile.ProjectID) diff --git a/internal/engine/handler.go b/internal/engine/handler.go index 1df1f2022c..68407c8c61 100644 --- a/internal/engine/handler.go +++ b/internal/engine/handler.go @@ -25,6 +25,7 @@ const ( // DefaultExecutionTimeout is the timeout for execution of a set // of profiles on an entity. DefaultExecutionTimeout = 5 * time.Minute + // ArtifactSignatureWaitPeriod is the waiting period for potential artifact signature to be available // before proceeding with evaluation. ArtifactSignatureWaitPeriod = 10 * time.Second @@ -37,10 +38,10 @@ type ExecutorEventHandler struct { handlerMiddleware []message.HandlerMiddleware wgEntityEventExecution *sync.WaitGroup executor Executor - executionTimeout time.Duration + + executionTimeout time.Duration + // cancels are a set of cancel functions for current entity events in flight. - // This allows us to cancel rule evaluation directly when terminationContext - // is cancelled. cancels []*context.CancelFunc lock sync.Mutex } @@ -53,9 +54,11 @@ func NewExecutorEventHandler( executor Executor, executionTimeout time.Duration, ) *ExecutorEventHandler { + if executionTimeout <= 0 { executionTimeout = DefaultExecutionTimeout } + eh := &ExecutorEventHandler{ evt: evt, wgEntityEventExecution: &sync.WaitGroup{}, @@ -63,9 +66,12 @@ func NewExecutorEventHandler( executor: executor, executionTimeout: executionTimeout, } - zerolog.Ctx(ctx).Info(). + + // Debug-level log (not noisy in production) + zerolog.Ctx(ctx).Debug(). Dur("execution_timeout", executionTimeout). Msg("executor event handler initialized") + go func() { <-ctx.Done() eh.lock.Lock() @@ -89,32 +95,21 @@ func (e *ExecutorEventHandler) Wait() { e.wgEntityEventExecution.Wait() } -// ExecutionTimeout returns the configured execution timeout for the handler. -func (e *ExecutorEventHandler) ExecutionTimeout() time.Duration { - return e.executionTimeout -} - // HandleEntityEvent handles events coming from webhooks/signals // as well as the init event. func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { - // NOTE: we're _deliberately_ "escaping" from the parent context's Cancel/Done - // completion, because the default watermill behavior for both Go channels and - // SQL is to process messages sequentially, but we need additional parallelism - // beyond that. When we switch to a different message processing system, we - // should aim to remove this goroutine altogether and have the messaging system - // provide the parallelism. - // We _do_ still want to cancel on shutdown, however. - // TODO: Make this timeout configurable + // Escape parent cancellation but still support shutdown cancellation msgCtx := context.WithoutCancel(msg.Context()) - //nolint:gosec // this is called when we iterate over e.cancels + + //nolint:gosec msgCtx, shutdownCancel := context.WithCancel(msgCtx) e.lock.Lock() e.cancels = append(e.cancels, &shutdownCancel) e.lock.Unlock() - // Let's not share memory with the caller. Note that this does not copy Context + // Copy message to avoid shared memory issues msg = msg.Copy() inf, err := entities.ParseEntityEvent(msg) @@ -123,15 +118,18 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { } e.wgEntityEventExecution.Add(1) + go func() { defer e.wgEntityEventExecution.Done() + if inf.Type == pb.Entity_ENTITY_ARTIFACTS { time.Sleep(ArtifactSignatureWaitPeriod) } - ctx := msgCtx - cancel := func() {} + // ✅ FIX: Proper configurable timeout + ctx, cancel := context.WithTimeout(msgCtx, e.executionTimeout) defer cancel() + defer func() { e.lock.Lock() e.cancels = slices.DeleteFunc(e.cancels, func(cf *context.CancelFunc) bool { @@ -142,15 +140,18 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { ctx = engcontext.WithEntityContext(ctx, &engcontext.EntityContext{ Project: engcontext.Project{ID: inf.ProjectID}, - // TODO: extract Provider name from ProviderID? + Provider: engcontext.Provider{ + Name: inf.ProviderID.String(), + }, }) ts := minderlogger.BusinessRecord(ctx) ctx = ts.WithTelemetry(ctx) logger := zerolog.Ctx(ctx) + if err := inf.WithExecutionIDFromMessage(msg); err != nil { - logger.Info(). + logger.Debug(). Str("message_id", msg.UUID). Msg("message does not contain execution ID, skipping") return @@ -158,10 +159,6 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { err := e.executor.EvalEntityEvent(ctx, inf) - // record telemetry regardless of error. We explicitly record telemetry - // here even though we also record it in the middleware because the evaluation - // is done in a separate goroutine which usually still runs after the middleware - // had already recorded the telemetry. logMsg := logger.Info() if err != nil { logMsg = logger.Error() @@ -174,18 +171,16 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { Str("provider_id", inf.ProviderID.String()). Str("entity", inf.Type.String()). Str("entity_id", inf.EntityID.String()). - Err(err).Msg("got error while evaluating entity event") + Err(err). + Msg("got error while evaluating entity event") } - // We don't need to unset the execution ID because the event is going to be - // deleted from the database anyway. The aggregator will take care of that. msg, err := inf.BuildMessage() if err != nil { logger.Err(err).Msg("error building message") return } - // Publish the result of the entity evaluation if err := e.evt.Publish(constants.TopicQueueEntityFlush, msg); err != nil { logger.Err(err).Msg("error publishing flush event") } diff --git a/internal/engine/handler_test.go b/internal/engine/handler_test.go index 447b65fa3b..3c0d516505 100644 --- a/internal/engine/handler_test.go +++ b/internal/engine/handler_test.go @@ -29,7 +29,6 @@ func TestExecutorEventHandler_handleEntityEvent(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - // declarations projectID := uuid.New() providerID := uuid.New() repositoryID := uuid.New() @@ -37,24 +36,21 @@ func TestExecutorEventHandler_handleEntityEvent(t *testing.T) { parallelOps := 2 - // -- end expectations - evt, err := eventer.New(context.Background(), nil, &serverconfig.EventConfig{ Driver: "go-channel", GoChannel: serverconfig.GoChannelEventConfig{ BlockPublishUntilSubscriberAck: true, }, }) - require.NoError(t, err, "failed to setup eventer") + require.NoError(t, err) pq := testqueue.NewPassthroughQueue(t) queued := pq.GetQueue() go func() { - t.Log("Running eventer") evt.Register(constants.TopicQueueEntityFlush, pq.Pass) err := evt.Run(context.Background()) - require.NoError(t, err, "failed to run eventer") + require.NoError(t, err) }() testTimeout := 5 * time.Second @@ -68,7 +64,8 @@ func TestExecutorEventHandler_handleEntityEvent(t *testing.T) { Name: "test", RepoId: 123, CloneUrl: "github.com/foo/bar.git", - }).WithID(repositoryID). + }). + WithID(repositoryID). WithExecutionID(executionID) executor := mockengine.NewMockExecutor(ctrl) @@ -86,23 +83,18 @@ func TestExecutorEventHandler_handleEntityEvent(t *testing.T) { engine.DefaultExecutionTimeout, ) - t.Log("waiting for eventer to start") <-evt.Running() msg, err := eiw.BuildMessage() - require.NoError(t, err, "expected no error") + require.NoError(t, err) - // Run in the background, twice for i := 0; i < parallelOps; i++ { go func() { - t.Log("Running entity event handler") - require.NoError(t, handler.HandleEntityEvent(msg), "expected no error") + require.NoError(t, handler.HandleEntityEvent(msg)) }() } - // expect flush for i := 0; i < parallelOps; i++ { - t.Log("waiting for flush") result := <-queued require.NotNil(t, result) require.Equal(t, providerID.String(), msg.Metadata.Get(entities.ProviderIDEventKey)) @@ -110,40 +102,67 @@ func TestExecutorEventHandler_handleEntityEvent(t *testing.T) { require.Equal(t, projectID.String(), msg.Metadata.Get(entities.ProjectIDEventKey)) } - require.NoError(t, evt.Close(), "expected no error") - - t.Log("waiting for executor to finish") + require.NoError(t, evt.Close()) handler.Wait() } -func TestExecutorEventHandler_CustomTimeout(t *testing.T) { +// Behavior-based timeout test +func TestExecutorEventHandler_RespectsTimeout(t *testing.T) { t.Parallel() - handler := engine.NewExecutorEventHandler( - context.Background(), - nil, - nil, - nil, - 10*time.Second, - ) + ctrl := gomock.NewController(t) + defer ctrl.Finish() - if handler.ExecutionTimeout() != 10*time.Second { - t.Fatalf("expected 10s, got %v", handler.ExecutionTimeout()) - } -} + projectID := uuid.New() + providerID := uuid.New() + repositoryID := uuid.New() + executionID := uuid.New() -func TestExecutorEventHandler_DefaultTimeoutFallback(t *testing.T) { - t.Parallel() + // Mock executor that simulates long-running work + executor := mockengine.NewMockExecutor(ctrl) + executor.EXPECT(). + EvalEntityEvent(gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, _ *entities.EntityInfoWrapper) error { + select { + case <-time.After(5 * time.Second): + return nil + case <-ctx.Done(): + return ctx.Err() + } + }) + + evt, err := eventer.New(context.Background(), nil, &serverconfig.EventConfig{ + Driver: "go-channel", + }) + require.NoError(t, err) handler := engine.NewExecutorEventHandler( context.Background(), + evt, nil, - nil, - nil, - 0, + executor, + 1*time.Second, ) - if handler.ExecutionTimeout() != engine.DefaultExecutionTimeout { - t.Fatalf("expected default timeout, got %v", handler.ExecutionTimeout()) - } + eiw := entities.NewEntityInfoWrapper(). + WithProviderID(providerID). + WithProjectID(projectID). + WithRepository(&minderv1.Repository{ + Name: "test", + }). + WithID(repositoryID). + WithExecutionID(executionID) + + msg, err := eiw.BuildMessage() + require.NoError(t, err) + + start := time.Now() + + require.NoError(t, handler.HandleEntityEvent(msg)) + handler.Wait() + + elapsed := time.Since(start) + + //Ensure execution timed out early + require.Less(t, elapsed, 3*time.Second, "execution did not timeout as expected") } From 14e4130853dc1582b653d5fe18903f659fb56ea4 Mon Sep 17 00:00:00 2001 From: Sachin Kumar <69066918+sachin9058@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:46:52 +0530 Subject: [PATCH 21/30] Move internal/engine/errors to pkg/engine/errors to reduce coupling (#6252) * Move internal/engine/errors to pkg/engine/errors to reduce coupling Signed-off-by: Sachin Kumar * fix: resolve lint issues --------- Signed-off-by: Sachin Kumar --- internal/engine/eval/rego/rego_test.go | 3 +++ internal/providers/github/webhook/fuzz_test.go | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/engine/eval/rego/rego_test.go b/internal/engine/eval/rego/rego_test.go index e8b39af954..6e0606a00e 100644 --- a/internal/engine/eval/rego/rego_test.go +++ b/internal/engine/eval/rego/rego_test.go @@ -12,7 +12,10 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" +<<<<<<< HEAD dbadapter "github.com/mindersec/minder/internal/adapters/db" +======= +>>>>>>> 0cbed8ad3 (Move internal/engine/errors to pkg/engine/errors to reduce coupling (#6252)) "github.com/mindersec/minder/internal/engine/eval/rego" "github.com/mindersec/minder/internal/engine/options" "github.com/mindersec/minder/internal/util/ptr" diff --git a/internal/providers/github/webhook/fuzz_test.go b/internal/providers/github/webhook/fuzz_test.go index ad9b9c1a1d..d0043c5f38 100644 --- a/internal/providers/github/webhook/fuzz_test.go +++ b/internal/providers/github/webhook/fuzz_test.go @@ -81,9 +81,7 @@ func FuzzGitHubEventParsers(f *testing.F) { req.Header.Add("X-Hub-Signature-256", fmt.Sprintf("sha256=%s", expectedMAC)) wes := &metrics.WebhookEventState{ - Typ: "unknown", - Accepted: false, - Error: true, + Typ: "unknown", } wes.Typ = github.WebHookType(req) From 74c52bf6b1b0d2eb82f3ef7c0976c7441d223423 Mon Sep 17 00:00:00 2001 From: Dharun Date: Sat, 4 Apr 2026 01:22:06 +0530 Subject: [PATCH 22/30] Remove git_pr_diffs flag (#6258) * removed git_pr_diffs feature flag Signed-off-by: DharunMR * removed the flag from testcase Signed-off-by: DharunMR --------- Signed-off-by: DharunMR --- internal/engine/eval/rego/lib.go | 15 +++++++++++++++ pkg/flags/constants.go | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/internal/engine/eval/rego/lib.go b/internal/engine/eval/rego/lib.go index a0ebe110ef..82862176ea 100644 --- a/internal/engine/eval/rego/lib.go +++ b/internal/engine/eval/rego/lib.go @@ -56,11 +56,26 @@ var MinderRegoLib = []func(res *interfaces.Ingested) func(*rego.Rego){ BaseFileRead, BaseFileWalk, BaseListGithubActions, +<<<<<<< HEAD DependencyExtract, BaseDependencyExtract, } func instantiateRegoLib(res *interfaces.Ingested) []func(*rego.Rego) { +======= +} + +// MinderRegoLibExperiments contains Minder-specific functions which +// should only be exposed when the given experiment is enabled. +var MinderRegoLibExperiments = map[flags.Experiment][]func(res *interfaces.Ingested) func(*rego.Rego){ + flags.DependencyExtract: { + DependencyExtract, + BaseDependencyExtract, + }, +} + +func instantiateRegoLib(ctx context.Context, featureFlags flags.Interface, res *interfaces.Ingested) []func(*rego.Rego) { +>>>>>>> 10868b7ac (Remove git_pr_diffs flag (#6258)) var lib []func(*rego.Rego) for _, f := range MinderRegoLib { lib = append(lib, f(res)) diff --git a/pkg/flags/constants.go b/pkg/flags/constants.go index 8730be78f5..4f10b5e764 100644 --- a/pkg/flags/constants.go +++ b/pkg/flags/constants.go @@ -10,6 +10,11 @@ const ( GitLabProvider Experiment = "gitlab_provider" // AlternateMessageDriver enables an an alternate message driver. AlternateMessageDriver Experiment = "alternate_message_driver" +<<<<<<< HEAD +======= + // DependencyExtract enables functions to perform dependency extraction. + DependencyExtract Experiment = "dependency_extract" +>>>>>>> 10868b7ac (Remove git_pr_diffs flag (#6258)) // ProjectCreateDelete enables creating top-level projects and deleting them. ProjectCreateDelete Experiment = "project_create_delete" // AuthenticatedDataSources enables provider authentication for data sources. From 9572bdd2bfa471f28423f72a231f3279ea72fbcd Mon Sep 17 00:00:00 2001 From: Dharun Date: Sat, 4 Apr 2026 09:53:02 +0530 Subject: [PATCH 23/30] removed dependency_extract feature flag (#6272) * removed dependency_extract feature flag Signed-off-by: DharunMR * solved lint issues Signed-off-by: DharunMR --------- Signed-off-by: DharunMR --- pkg/flags/constants.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/flags/constants.go b/pkg/flags/constants.go index 4f10b5e764..52be847619 100644 --- a/pkg/flags/constants.go +++ b/pkg/flags/constants.go @@ -11,10 +11,13 @@ const ( // AlternateMessageDriver enables an an alternate message driver. AlternateMessageDriver Experiment = "alternate_message_driver" <<<<<<< HEAD +<<<<<<< HEAD ======= // DependencyExtract enables functions to perform dependency extraction. DependencyExtract Experiment = "dependency_extract" >>>>>>> 10868b7ac (Remove git_pr_diffs flag (#6258)) +======= +>>>>>>> 47d52cf1c (removed dependency_extract feature flag (#6272)) // ProjectCreateDelete enables creating top-level projects and deleting them. ProjectCreateDelete Experiment = "project_create_delete" // AuthenticatedDataSources enables provider authentication for data sources. From 33510660e519e5eb321c72f465d18266d6da6709 Mon Sep 17 00:00:00 2001 From: Sachin Kumar <69066918+sachin9058@users.noreply.github.com> Date: Sat, 4 Apr 2026 09:53:15 +0530 Subject: [PATCH 24/30] Decouple pkg/engine/errors from internal/db using adapter layer (#6266) * Move internal/engine/errors to pkg/engine/errors to reduce coupling Signed-off-by: Sachin Kumar * fix: resolve lint issues * refactor: decouple engine errors from internal/db via adapter layer * fix: add package comment and correct license header * fix: cleanup imports and resolve lint issues * fix: update generated protobuf files --------- Signed-off-by: Sachin Kumar --- internal/engine/eval/rego/rego_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/engine/eval/rego/rego_test.go b/internal/engine/eval/rego/rego_test.go index 6e0606a00e..54b323f7b2 100644 --- a/internal/engine/eval/rego/rego_test.go +++ b/internal/engine/eval/rego/rego_test.go @@ -12,10 +12,14 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" +<<<<<<< HEAD <<<<<<< HEAD dbadapter "github.com/mindersec/minder/internal/adapters/db" ======= >>>>>>> 0cbed8ad3 (Move internal/engine/errors to pkg/engine/errors to reduce coupling (#6252)) +======= + dbadapter "github.com/mindersec/minder/internal/adapters/db" +>>>>>>> 63a6a8e5f (Decouple pkg/engine/errors from internal/db using adapter layer (#6266)) "github.com/mindersec/minder/internal/engine/eval/rego" "github.com/mindersec/minder/internal/engine/options" "github.com/mindersec/minder/internal/util/ptr" From b8d4449698261da3598f8173ea5538b09aeee1cc Mon Sep 17 00:00:00 2001 From: Daksh Pathak Date: Mon, 6 Apr 2026 11:00:54 +0530 Subject: [PATCH 25/30] Test(actions): add unit tests for rule actions (#6208) test: add unit tests for shouldRemediate and shouldAlert --- internal/engine/actions/actions_test.go | 220 ++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 internal/engine/actions/actions_test.go diff --git a/internal/engine/actions/actions_test.go b/internal/engine/actions/actions_test.go new file mode 100644 index 0000000000..7d9dc8c90d --- /dev/null +++ b/internal/engine/actions/actions_test.go @@ -0,0 +1,220 @@ +// SPDX-FileCopyrightText: Copyright 2026 The Minder Authors +// SPDX-License-Identifier: Apache-2.0 + +package actions + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/mindersec/minder/internal/db" + "github.com/mindersec/minder/internal/engine/actions/remediate/pull_request" + enginerr "github.com/mindersec/minder/internal/engine/errors" + engif "github.com/mindersec/minder/internal/engine/interfaces" +) + +func TestShouldRemediate(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + prevEval db.RemediationStatusTypes + nilRow bool + evalErr error + expected engif.ActionCmd + }{ + // Happy path: eval success + { + name: "eval success, prev success -> off", + prevEval: db.RemediationStatusTypesSuccess, + evalErr: nil, + expected: engif.ActionCmdOff, + }, + { + name: "eval success, prev skipped -> do nothing", + prevEval: db.RemediationStatusTypesSkipped, + evalErr: nil, + expected: engif.ActionCmdDoNothing, + }, + // Happy path: eval failure triggers remediation + { + name: "eval failure, prev skipped -> on", + prevEval: db.RemediationStatusTypesSkipped, + evalErr: enginerr.NewErrEvaluationFailed("failed"), + expected: engif.ActionCmdOn, + }, + { + name: "eval failure, prev success -> do nothing", + prevEval: db.RemediationStatusTypesSuccess, + evalErr: enginerr.NewErrEvaluationFailed("failed"), + expected: engif.ActionCmdDoNothing, + }, + // Expected errors: eval error cases + { + name: "eval error, prev skipped -> do nothing", + prevEval: db.RemediationStatusTypesSkipped, + evalErr: errors.New("random error"), + expected: engif.ActionCmdDoNothing, + }, + { + // NOTE: EvalStatusTypesError has an empty case body in shouldRemediate, + // so eval errors fall through to the default DoNothing. This may be a bug + // (see the comment on cases Error/Success in shouldRemediate). + name: "eval error, prev success -> do nothing", + prevEval: db.RemediationStatusTypesSuccess, + evalErr: errors.New("random error"), + expected: engif.ActionCmdDoNothing, + }, + { + name: "eval failure, prev error -> do nothing", + prevEval: db.RemediationStatusTypesError, + evalErr: enginerr.NewErrEvaluationFailed("failed"), + expected: engif.ActionCmdDoNothing, + }, + { + name: "eval error, prev error -> do nothing", + prevEval: db.RemediationStatusTypesError, + evalErr: errors.New("random error"), + expected: engif.ActionCmdDoNothing, + }, + // Edge cases + { + name: "eval skipped -> do nothing", + prevEval: db.RemediationStatusTypesSkipped, + evalErr: enginerr.ErrEvaluationSkipSilently, + expected: engif.ActionCmdDoNothing, + }, + { + name: "nil DB row, eval failure -> on", + nilRow: true, + evalErr: enginerr.NewErrEvaluationFailed("failed"), + expected: engif.ActionCmdOn, + }, + { + name: "nil DB row, eval success -> do nothing", + nilRow: true, + evalErr: nil, + expected: engif.ActionCmdDoNothing, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + var prevRow *db.ListRuleEvaluationsByProfileIdRow + if !tt.nilRow { + prevRow = &db.ListRuleEvaluationsByProfileIdRow{RemStatus: tt.prevEval} + } + got := shouldRemediate(prevRow, tt.evalErr) + assert.Equal(t, tt.expected, got) + }) + } +} + +func TestShouldAlert(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + prevAlert db.AlertStatusTypes + nilRow bool + evalErr error + remErr error + remType string + expected engif.ActionCmd + }{ + // Happy path: eval success + { + name: "eval success, alert on -> off", + prevAlert: db.AlertStatusTypesOn, + evalErr: nil, + remErr: nil, + // Using pull_request.RemediateType so we reach the switch instead of + // hitting the early-return in Case 1 (non-PR successful remediation). + remType: pull_request.RemediateType, + expected: engif.ActionCmdOff, + }, + { + name: "eval success, alert already off -> do nothing", + prevAlert: db.AlertStatusTypesOff, + evalErr: nil, + remErr: nil, + remType: pull_request.RemediateType, + expected: engif.ActionCmdDoNothing, + }, + // Happy path: eval failure triggers alert + { + name: "pr remediation eval failure, alert skipped -> on", + prevAlert: db.AlertStatusTypesSkipped, + evalErr: enginerr.NewErrEvaluationFailed("failed"), + remErr: nil, + remType: pull_request.RemediateType, + expected: engif.ActionCmdOn, + }, + { + name: "pr remediation eval failure, alert already on -> do nothing", + prevAlert: db.AlertStatusTypesOn, + evalErr: enginerr.NewErrEvaluationFailed("failed"), + remErr: nil, + remType: pull_request.RemediateType, + expected: engif.ActionCmdDoNothing, + }, + // Non-PR successful remediation (Case 1 early return) + { + name: "successful non-pr remediation, alert on -> off", + prevAlert: db.AlertStatusTypesOn, + evalErr: enginerr.NewErrEvaluationFailed("failed"), + remErr: nil, + remType: "some-other-type", + expected: engif.ActionCmdOff, + }, + { + name: "successful non-pr remediation, alert already off -> do nothing", + prevAlert: db.AlertStatusTypesOff, + evalErr: enginerr.NewErrEvaluationFailed("failed"), + remErr: nil, + remType: "some-other-type", + expected: engif.ActionCmdDoNothing, + }, + // Expected errors + { + name: "eval error -> do nothing", + prevAlert: db.AlertStatusTypesOff, + evalErr: errors.New("generic error"), + remErr: nil, + remType: pull_request.RemediateType, + expected: engif.ActionCmdDoNothing, + }, + // Edge cases + { + name: "nil DB row, eval failure -> on", + nilRow: true, + evalErr: enginerr.NewErrEvaluationFailed("failed"), + remErr: nil, + remType: pull_request.RemediateType, + expected: engif.ActionCmdOn, + }, + { + name: "nil DB row, eval success -> off", + nilRow: true, + evalErr: nil, + remErr: nil, + remType: pull_request.RemediateType, + expected: engif.ActionCmdOff, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + var prevRow *db.ListRuleEvaluationsByProfileIdRow + if !tt.nilRow { + prevRow = &db.ListRuleEvaluationsByProfileIdRow{AlertStatus: tt.prevAlert} + } + got := shouldAlert(prevRow, tt.evalErr, tt.remErr, tt.remType) + assert.Equal(t, tt.expected, got) + }) + } +} From 96b7e640268f81002652032bd74842960d917000 Mon Sep 17 00:00:00 2001 From: Dharun Date: Mon, 6 Apr 2026 11:21:58 +0530 Subject: [PATCH 26/30] Additional info delete ruletype (#6273) * added additional info for deleting ruletype Signed-off-by: DharunMR * solved linting Signed-off-by: DharunMR * added struct approach Signed-off-by: DharunMR --------- Signed-off-by: DharunMR --- cmd/cli/app/ruletype/ruletype_delete.go | 92 ++++++++++++++++++++----- 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/cmd/cli/app/ruletype/ruletype_delete.go b/cmd/cli/app/ruletype/ruletype_delete.go index a8417ae491..303d3cc411 100644 --- a/cmd/cli/app/ruletype/ruletype_delete.go +++ b/cmd/cli/app/ruletype/ruletype_delete.go @@ -5,6 +5,8 @@ package ruletype import ( "context" + "regexp" + "strings" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -14,6 +16,11 @@ import ( minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1" ) +type ruleTypeBlock struct { + Name string + Profiles []string +} + var deleteCmd = &cobra.Command{ Use: "delete", Short: "Delete a rule type", @@ -74,22 +81,7 @@ func deleteCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn *gr deletedRuleTypes, remainingRuleTypes := deleteRuleTypes(ctx, client, rulesToDelete, project) // Print the results - if len(deletedRuleTypes) == 0 && len(remainingRuleTypes) == 0 { - cmd.Println("There are no rule types to delete") - return nil - } - if len(deletedRuleTypes) > 0 { - cmd.Println("\nThe following rule type(s) were successfully deleted:") - for _, ruleType := range deletedRuleTypes { - cmd.Println(ruleType) - } - } - if len(remainingRuleTypes) > 0 { - cmd.Println("\nThe following rule type(s) are referenced by existing profiles and were not deleted:") - for _, ruleType := range remainingRuleTypes { - cmd.Println(ruleType) - } - } + printDeleteResults(cmd, deletedRuleTypes, remainingRuleTypes) return nil } @@ -99,16 +91,23 @@ func deleteRuleTypes( client minderv1.RuleTypeServiceClient, rulesToDelete []*minderv1.RuleType, project string, -) ([]string, []string) { +) ([]string, []ruleTypeBlock) { + var deletedRuleTypes []string - var remainingRuleTypes []string + var remainingRuleTypes []ruleTypeBlock + for _, ruleType := range rulesToDelete { _, err := client.DeleteRuleType(ctx, &minderv1.DeleteRuleTypeRequest{ Context: &minderv1.Context{Project: &project}, Id: ruleType.GetId(), }) if err != nil { - remainingRuleTypes = append(remainingRuleTypes, ruleType.GetName()) + profiles := extractProfiles(err.Error()) + + remainingRuleTypes = append(remainingRuleTypes, ruleTypeBlock{ + Name: ruleType.GetName(), + Profiles: profiles, + }) continue } deletedRuleTypes = append(deletedRuleTypes, ruleType.GetName()) @@ -116,6 +115,61 @@ func deleteRuleTypes( return deletedRuleTypes, remainingRuleTypes } +func printDeleteResults( + cmd *cobra.Command, + deletedRuleTypes []string, + remainingRuleTypes []ruleTypeBlock, +) { + if len(deletedRuleTypes) == 0 && len(remainingRuleTypes) == 0 { + cmd.Println("There are no rule types to delete") + return + } + + if len(deletedRuleTypes) > 0 { + cmd.Println("\nThe following rule type(s) were successfully deleted:") + for _, ruleType := range deletedRuleTypes { + cmd.Println(ruleType) + } + } + + if len(remainingRuleTypes) > 0 { + cmd.Println("\nThe following rule type(s) are referenced by existing profiles and were not deleted:") + for _, ruleType := range remainingRuleTypes { + cmd.Println(ruleType.Name) + } + + cmd.Println("\nThey are referenced by profiles:") + + seen := map[string]bool{} + for _, b := range remainingRuleTypes { + for _, p := range b.Profiles { + if !seen[p] { + cmd.Println(p) + seen[p] = true + } + } + } + + } +} + +func extractProfiles(errMsg string) []string { + var profilesRegex = regexp.MustCompile(`used by profiles (.+)`) + match := profilesRegex.FindStringSubmatch(strings.ToLower(errMsg)) + if len(match) < 2 { + return []string{} + } + + profilesPart := strings.TrimSpace(match[1]) + + parts := strings.Split(profilesPart, ",") + for i := range parts { + parts[i] = strings.TrimSpace(parts[i]) + } + + return parts +} + func init() { ruleTypeCmd.AddCommand(deleteCmd) // Flags From 9ecafed9945c1221a2d196ebb11e3f9fd6536d06 Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Mon, 6 Apr 2026 14:04:51 +0530 Subject: [PATCH 27/30] Fix rebase issues, resolve conflicts, and sync validator with upstream --- internal/engine/actions/actions_test.go | 2 +- internal/engine/eval/rego/lib.go | 15 --------------- internal/engine/eval/rego/rego_test.go | 7 ------- pkg/flags/constants.go | 8 -------- 4 files changed, 1 insertion(+), 31 deletions(-) diff --git a/internal/engine/actions/actions_test.go b/internal/engine/actions/actions_test.go index 7d9dc8c90d..17ed1d7283 100644 --- a/internal/engine/actions/actions_test.go +++ b/internal/engine/actions/actions_test.go @@ -11,8 +11,8 @@ import ( "github.com/mindersec/minder/internal/db" "github.com/mindersec/minder/internal/engine/actions/remediate/pull_request" - enginerr "github.com/mindersec/minder/internal/engine/errors" engif "github.com/mindersec/minder/internal/engine/interfaces" + enginerr "github.com/mindersec/minder/pkg/engine/errors" ) func TestShouldRemediate(t *testing.T) { diff --git a/internal/engine/eval/rego/lib.go b/internal/engine/eval/rego/lib.go index 82862176ea..a0ebe110ef 100644 --- a/internal/engine/eval/rego/lib.go +++ b/internal/engine/eval/rego/lib.go @@ -56,26 +56,11 @@ var MinderRegoLib = []func(res *interfaces.Ingested) func(*rego.Rego){ BaseFileRead, BaseFileWalk, BaseListGithubActions, -<<<<<<< HEAD DependencyExtract, BaseDependencyExtract, } func instantiateRegoLib(res *interfaces.Ingested) []func(*rego.Rego) { -======= -} - -// MinderRegoLibExperiments contains Minder-specific functions which -// should only be exposed when the given experiment is enabled. -var MinderRegoLibExperiments = map[flags.Experiment][]func(res *interfaces.Ingested) func(*rego.Rego){ - flags.DependencyExtract: { - DependencyExtract, - BaseDependencyExtract, - }, -} - -func instantiateRegoLib(ctx context.Context, featureFlags flags.Interface, res *interfaces.Ingested) []func(*rego.Rego) { ->>>>>>> 10868b7ac (Remove git_pr_diffs flag (#6258)) var lib []func(*rego.Rego) for _, f := range MinderRegoLib { lib = append(lib, f(res)) diff --git a/internal/engine/eval/rego/rego_test.go b/internal/engine/eval/rego/rego_test.go index 54b323f7b2..e8b39af954 100644 --- a/internal/engine/eval/rego/rego_test.go +++ b/internal/engine/eval/rego/rego_test.go @@ -12,14 +12,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" -<<<<<<< HEAD -<<<<<<< HEAD dbadapter "github.com/mindersec/minder/internal/adapters/db" -======= ->>>>>>> 0cbed8ad3 (Move internal/engine/errors to pkg/engine/errors to reduce coupling (#6252)) -======= - dbadapter "github.com/mindersec/minder/internal/adapters/db" ->>>>>>> 63a6a8e5f (Decouple pkg/engine/errors from internal/db using adapter layer (#6266)) "github.com/mindersec/minder/internal/engine/eval/rego" "github.com/mindersec/minder/internal/engine/options" "github.com/mindersec/minder/internal/util/ptr" diff --git a/pkg/flags/constants.go b/pkg/flags/constants.go index 52be847619..8730be78f5 100644 --- a/pkg/flags/constants.go +++ b/pkg/flags/constants.go @@ -10,14 +10,6 @@ const ( GitLabProvider Experiment = "gitlab_provider" // AlternateMessageDriver enables an an alternate message driver. AlternateMessageDriver Experiment = "alternate_message_driver" -<<<<<<< HEAD -<<<<<<< HEAD -======= - // DependencyExtract enables functions to perform dependency extraction. - DependencyExtract Experiment = "dependency_extract" ->>>>>>> 10868b7ac (Remove git_pr_diffs flag (#6258)) -======= ->>>>>>> 47d52cf1c (removed dependency_extract feature flag (#6272)) // ProjectCreateDelete enables creating top-level projects and deleting them. ProjectCreateDelete Experiment = "project_create_delete" // AuthenticatedDataSources enables provider authentication for data sources. From 49b3bb817fcbc90bf161cbfa9a454f1f0c54092f Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Tue, 7 Apr 2026 03:00:02 +0530 Subject: [PATCH 28/30] fix: add missing comments for exported handler methods --- internal/engine/handler.go | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/internal/engine/handler.go b/internal/engine/handler.go index 68407c8c61..f5c7e56ce6 100644 --- a/internal/engine/handler.go +++ b/internal/engine/handler.go @@ -31,8 +31,8 @@ const ( ArtifactSignatureWaitPeriod = 10 * time.Second ) -// ExecutorEventHandler is responsible for consuming entity events, passing -// entities to the executor, and then publishing the results. +// ExecutorEventHandler handles entity events, executes evaluations, +// and publishes the results. type ExecutorEventHandler struct { evt interfaces.Publisher handlerMiddleware []message.HandlerMiddleware @@ -41,12 +41,12 @@ type ExecutorEventHandler struct { executionTimeout time.Duration - // cancels are a set of cancel functions for current entity events in flight. cancels []*context.CancelFunc lock sync.Mutex } -// NewExecutorEventHandler creates the event handler for the executor +// NewExecutorEventHandler creates a new ExecutorEventHandler with +// configurable execution timeout. func NewExecutorEventHandler( ctx context.Context, evt interfaces.Publisher, @@ -67,7 +67,6 @@ func NewExecutorEventHandler( executionTimeout: executionTimeout, } - // Debug-level log (not noisy in production) zerolog.Ctx(ctx).Debug(). Dur("execution_timeout", executionTimeout). Msg("executor event handler initialized") @@ -85,23 +84,30 @@ func NewExecutorEventHandler( return eh } -// Register implements the Consumer interface. +// Register registers the handler for entity evaluation events. func (e *ExecutorEventHandler) Register(r interfaces.Registrar) { r.Register(constants.TopicQueueEntityEvaluate, e.HandleEntityEvent, e.handlerMiddleware...) } -// Wait waits for all the entity executions to finish. +// Wait blocks until all entity event executions are complete. func (e *ExecutorEventHandler) Wait() { e.wgEntityEventExecution.Wait() } -// HandleEntityEvent handles events coming from webhooks/signals -// as well as the init event. +// HandleEntityEvent processes incoming entity events and triggers evaluation. func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { - // Escape parent cancellation but still support shutdown cancellation + // NOTE: we're _deliberately_ "escaping" from the parent context's Cancel/Done + // completion, because the default watermill behavior for both Go channels and + // SQL is to process messages sequentially, but we need additional parallelism + // beyond that. When we switch to a different message processing system, we + // should aim to remove this goroutine altogether and have the messaging system + // provide the parallelism. + // We _do_ still want to cancel on shutdown, however. msgCtx := context.WithoutCancel(msg.Context()) + // This allows us to cancel rule evaluation directly when terminationContext + // is cancelled. //nolint:gosec msgCtx, shutdownCancel := context.WithCancel(msgCtx) @@ -109,7 +115,6 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { e.cancels = append(e.cancels, &shutdownCancel) e.lock.Unlock() - // Copy message to avoid shared memory issues msg = msg.Copy() inf, err := entities.ParseEntityEvent(msg) @@ -126,7 +131,7 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { time.Sleep(ArtifactSignatureWaitPeriod) } - // ✅ FIX: Proper configurable timeout + // use configurable timeout ctx, cancel := context.WithTimeout(msgCtx, e.executionTimeout) defer cancel() @@ -141,7 +146,7 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { ctx = engcontext.WithEntityContext(ctx, &engcontext.EntityContext{ Project: engcontext.Project{ID: inf.ProjectID}, Provider: engcontext.Provider{ - Name: inf.ProviderID.String(), + Name: inf.ProviderID.String(), // unchanged }, }) @@ -165,6 +170,11 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { } ts.Record(logMsg).Send() + // record telemetry regardless of error. We explicitly record telemetry + // here even though we also record it in the middleware because the evaluation + // is done in a separate goroutine which usually still runs after the middleware + // had already recorded the telemetry. + if err != nil { logger.Info(). Str("project", inf.ProjectID.String()). From 68098a45e479d41018172fef8d777a38ec2eee02 Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Mon, 20 Apr 2026 15:04:10 +0530 Subject: [PATCH 29/30] Make executor timeout configurable Wire executor timeout from server event config into the handler and keep the default fallback behavior for non-positive values. Add behavior-focused tests to validate timeout cancellation and configured timeout propagation, and preserve subtle handler comments for maintainability. --- internal/engine/handler.go | 7 ++-- internal/engine/handler_test.go | 66 +++++++++++++++++++++++++------- internal/service/service.go | 2 +- pkg/config/server/config_test.go | 2 + pkg/config/server/events.go | 2 + 5 files changed, 62 insertions(+), 17 deletions(-) diff --git a/internal/engine/handler.go b/internal/engine/handler.go index 0ff5b5a190..bee9b4617e 100644 --- a/internal/engine/handler.go +++ b/internal/engine/handler.go @@ -123,6 +123,8 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { e.cancels = append(e.cancels, &shutdownCancel) e.lock.Unlock() + // Copy the message so the async goroutine does not share mutable state with + // the original Watermill message. msg = msg.Copy() inf, err := entities.ParseEntityEvent(msg) @@ -144,7 +146,6 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { } } - // use configurable timeout ctx, cancel := context.WithTimeout(msgCtx, e.executionTimeout) defer cancel() @@ -159,7 +160,7 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { ctx = engcontext.WithEntityContext(ctx, &engcontext.EntityContext{ Project: engcontext.Project{ID: inf.ProjectID}, Provider: engcontext.Provider{ - Name: inf.ProviderID.String(), // unchanged + Name: inf.ProviderID.String(), }, }) @@ -181,12 +182,12 @@ func (e *ExecutorEventHandler) HandleEntityEvent(msg *message.Message) error { if err != nil { logMsg = logger.Error() } - ts.Record(logMsg).Send() // record telemetry regardless of error. We explicitly record telemetry // here even though we also record it in the middleware because the evaluation // is done in a separate goroutine which usually still runs after the middleware // had already recorded the telemetry. + ts.Record(logMsg).Send() if err != nil { logger.Info(). diff --git a/internal/engine/handler_test.go b/internal/engine/handler_test.go index 30570afcc3..06ad2c9be2 100644 --- a/internal/engine/handler_test.go +++ b/internal/engine/handler_test.go @@ -118,8 +118,8 @@ func TestExecutorEventHandler_RespectsTimeout(t *testing.T) { repositoryID := uuid.New() executionID := uuid.New() - // Mock executor that simulates long-running work executor := mockengine.NewMockExecutor(ctrl) + var timedOut bool executor.EXPECT(). EvalEntityEvent(gomock.Any(), gomock.Any()). DoAndReturn(func(ctx context.Context, _ *entities.EntityInfoWrapper) error { @@ -127,6 +127,7 @@ func TestExecutorEventHandler_RespectsTimeout(t *testing.T) { case <-time.After(5 * time.Second): return nil case <-ctx.Done(): + timedOut = true return ctx.Err() } }) @@ -147,9 +148,7 @@ func TestExecutorEventHandler_RespectsTimeout(t *testing.T) { eiw := entities.NewEntityInfoWrapper(). WithProviderID(providerID). WithProjectID(projectID). - WithRepository(&minderv1.Repository{ - Name: "test", - }). + WithRepository(&minderv1.Repository{Name: "test"}). WithID(repositoryID). WithExecutionID(executionID) @@ -157,13 +156,11 @@ func TestExecutorEventHandler_RespectsTimeout(t *testing.T) { require.NoError(t, err) start := time.Now() - require.NoError(t, handler.HandleEntityEvent(msg)) handler.Wait() - elapsed := time.Since(start) - //Ensure execution timed out early + require.True(t, timedOut, "execution did not hit the timeout path") require.Less(t, elapsed, 3*time.Second, "execution did not timeout as expected") } @@ -176,7 +173,6 @@ func TestExecutorEventHandler_ShutdownCancelsNewEvents(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) executor := mockengine.NewMockExecutor(ctrl) - executor.EXPECT(). EvalEntityEvent(gomock.Any(), gomock.Any()). Times(0) @@ -186,20 +182,64 @@ func TestExecutorEventHandler_ShutdownCancelsNewEvents(t *testing.T) { nil, []message.HandlerMiddleware{}, executor, + engine.DefaultExecutionTimeout, ) - // Trigger shutdown cancel() - time.Sleep(10 * time.Millisecond) - msg := message.NewMessage("1", []byte("{}")) - // Call handler AFTER shutdown + msg := message.NewMessage("1", []byte("{}")) err := handler.HandleEntityEvent(msg) require.NoError(t, err) - // Give time in case something incorrectly executes time.Sleep(50 * time.Millisecond) + handler.Wait() +} + +func TestExecutorEventHandler_UsesConfiguredTimeout(t *testing.T) { + t.Parallel() + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + projectID := uuid.New() + providerID := uuid.New() + repositoryID := uuid.New() + executionID := uuid.New() + + executor := mockengine.NewMockExecutor(ctrl) + executor.EXPECT(). + EvalEntityEvent(gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, _ *entities.EntityInfoWrapper) error { + deadline, ok := ctx.Deadline() + require.True(t, ok, "expected execution context deadline") + remaining := time.Until(deadline) + require.Greater(t, remaining, 40*time.Second) + require.Less(t, remaining, 80*time.Second) + return nil + }) + + evt, err := eventer.New(context.Background(), nil, &serverconfig.EventConfig{Driver: "go-channel"}) + require.NoError(t, err) + handler := engine.NewExecutorEventHandler( + context.Background(), + evt, + nil, + executor, + 1*time.Minute, + ) + + eiw := entities.NewEntityInfoWrapper(). + WithProviderID(providerID). + WithProjectID(projectID). + WithRepository(&minderv1.Repository{Name: "test"}). + WithID(repositoryID). + WithExecutionID(executionID) + + msg, err := eiw.BuildMessage() + require.NoError(t, err) + + require.NoError(t, handler.HandleEntityEvent(msg)) handler.Wait() } diff --git a/internal/service/service.go b/internal/service/service.go index 7232d25c82..590c4cfc7a 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -265,7 +265,7 @@ func AllInOneServerService( evt, executorMiddleware, exec, - engine.DefaultExecutionTimeout, + cfg.Events.ExecutionTimeout, ) evt.ConsumeEvents(handler) diff --git a/pkg/config/server/config_test.go b/pkg/config/server/config_test.go index b52117d861..5b3f195cc1 100644 --- a/pkg/config/server/config_test.go +++ b/pkg/config/server/config_test.go @@ -6,6 +6,7 @@ package server_test import ( "bytes" "testing" + "time" "github.com/spf13/pflag" "github.com/spf13/viper" @@ -164,6 +165,7 @@ func TestReadDefaultConfig(t *testing.T) { require.Equal(t, "debug", cfg.LoggingConfig.Level) require.Equal(t, "minder", cfg.Database.Name) require.Equal(t, "./.ssh/token_key_passphrase", cfg.Auth.TokenKey) + require.Equal(t, 5*time.Minute, cfg.Events.ExecutionTimeout) } const ( diff --git a/pkg/config/server/events.go b/pkg/config/server/events.go index 182c155250..0f707ddda1 100644 --- a/pkg/config/server/events.go +++ b/pkg/config/server/events.go @@ -18,6 +18,8 @@ type EventConfig struct { Flags FlagDriverConfig `mapstructure:"flags"` // RouterCloseTimeout is the timeout for closing the router in seconds RouterCloseTimeout int64 `mapstructure:"router_close_timeout" default:"10"` + // ExecutionTimeout is the timeout for executor event handling. + ExecutionTimeout time.Duration `mapstructure:"execution_timeout" default:"5m"` // GoChannel is the configuration for the go channel event driver GoChannel GoChannelEventConfig `mapstructure:"go-channel"` // SQLPubSub is the configuration for the database event driver From 7277590bc21ff71f1368fee5c12c64fa3af49114 Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Wed, 29 Apr 2026 02:14:07 +0530 Subject: [PATCH 30/30] Cover default timeout fallback --- internal/engine/handler_test.go | 97 +++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 41 deletions(-) diff --git a/internal/engine/handler_test.go b/internal/engine/handler_test.go index 06ad2c9be2..35f728b223 100644 --- a/internal/engine/handler_test.go +++ b/internal/engine/handler_test.go @@ -196,50 +196,65 @@ func TestExecutorEventHandler_ShutdownCancelsNewEvents(t *testing.T) { handler.Wait() } -func TestExecutorEventHandler_UsesConfiguredTimeout(t *testing.T) { +func TestExecutorEventHandler_FallsBackToDefaultTimeout(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) - defer ctrl.Finish() + tests := []struct { + name string + timeout time.Duration + }{ + {name: "zero", timeout: 0}, + {name: "negative", timeout: -1 * time.Second}, + } - projectID := uuid.New() - providerID := uuid.New() - repositoryID := uuid.New() - executionID := uuid.New() + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + projectID := uuid.New() + providerID := uuid.New() + repositoryID := uuid.New() + executionID := uuid.New() + + executor := mockengine.NewMockExecutor(ctrl) + executor.EXPECT(). + EvalEntityEvent(gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, _ *entities.EntityInfoWrapper) error { + deadline, ok := ctx.Deadline() + require.True(t, ok, "expected execution context deadline") + remaining := time.Until(deadline) + require.Greater(t, remaining, 4*time.Minute) + require.Less(t, remaining, 6*time.Minute) + return nil + }) + + evt, err := eventer.New(context.Background(), nil, &serverconfig.EventConfig{Driver: "go-channel"}) + require.NoError(t, err) + + handler := engine.NewExecutorEventHandler( + context.Background(), + evt, + nil, + executor, + tt.timeout, + ) + + eiw := entities.NewEntityInfoWrapper(). + WithProviderID(providerID). + WithProjectID(projectID). + WithRepository(&minderv1.Repository{Name: "test"}). + WithID(repositoryID). + WithExecutionID(executionID) + + msg, err := eiw.BuildMessage() + require.NoError(t, err) - executor := mockengine.NewMockExecutor(ctrl) - executor.EXPECT(). - EvalEntityEvent(gomock.Any(), gomock.Any()). - DoAndReturn(func(ctx context.Context, _ *entities.EntityInfoWrapper) error { - deadline, ok := ctx.Deadline() - require.True(t, ok, "expected execution context deadline") - remaining := time.Until(deadline) - require.Greater(t, remaining, 40*time.Second) - require.Less(t, remaining, 80*time.Second) - return nil + require.NoError(t, handler.HandleEntityEvent(msg)) + handler.Wait() }) - - evt, err := eventer.New(context.Background(), nil, &serverconfig.EventConfig{Driver: "go-channel"}) - require.NoError(t, err) - - handler := engine.NewExecutorEventHandler( - context.Background(), - evt, - nil, - executor, - 1*time.Minute, - ) - - eiw := entities.NewEntityInfoWrapper(). - WithProviderID(providerID). - WithProjectID(projectID). - WithRepository(&minderv1.Repository{Name: "test"}). - WithID(repositoryID). - WithExecutionID(executionID) - - msg, err := eiw.BuildMessage() - require.NoError(t, err) - - require.NoError(t, handler.HandleEntityEvent(msg)) - handler.Wait() + } }