func (v *SnapshotJob) do(ffmpegPath, inputUrl string) (err error) {
	outputPicDir := path.Join(StaticDir, v.App)
	if err = os.MkdirAll(outputPicDir, 0777); err != nil {
		log.Println(fmt.Sprintf("create snapshot image dir:%v failed, err is %v", outputPicDir, err))
		return
	}

	normalPicPath := path.Join(outputPicDir, fmt.Sprintf("%v", v.Stream)+"-%03d.png")
	bestPng := path.Join(outputPicDir, fmt.Sprintf("%v-best.png", v.Stream))

	param := fmt.Sprintf("%v -i %v -vf fps=1 -vcodec png -f image2 -an -y -vframes %v -y %v", ffmpegPath, inputUrl, v.vframes, normalPicPath)
	log.Println(fmt.Sprintf("start snapshot, cmd param=%v", param))
	timeoutCtx, _ := context.WithTimeout(v.cancelCtx, v.timeout)
	cmd := exec.CommandContext(timeoutCtx, "/bin/bash", "-c", param)
	if err = cmd.Run(); err != nil {
		log.Println(fmt.Sprintf("run snapshot %v cmd failed, err is %v", v.Tag(), err))
		return
	}

	bestFileSize := int64(0)
	for i := 1; i <= v.vframes; i++ {
		pic := path.Join(outputPicDir, fmt.Sprintf("%v-%03d.png", v.Stream, i))
		fi, err := os.Stat(pic)
		if err != nil {
			log.Println(fmt.Sprintf("stat pic:%v failed, err is %v", pic, err))
			continue
		}
		if bestFileSize == 0 {
			bestFileSize = fi.Size()
		} else if fi.Size() > bestFileSize {
			os.Remove(bestPng)
			os.Symlink(pic, bestPng)
			bestFileSize = fi.Size()
		}
	}
	log.Println(fmt.Sprintf("%v the best thumbnail is %v", v.Tag(), bestPng))
	return
}

Improper Neutralization of Special Elements used in a Command ('Command Injection')

The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.


func (r *TerraformRunnerServer) NewTerraform(ctx context.Context, req *NewTerraformRequest) (*NewTerraformReply, error) {
	r.InstanceID = req.GetInstanceID()
	log := ctrl.LoggerFrom(ctx, "instance-id", r.InstanceID).WithName(loggerName)
	log.Info("creating new terraform", "workingDir", req.WorkingDir, "execPath", req.ExecPath)
	tf, err := tfexec.NewTerraform(req.WorkingDir, req.ExecPath)
	if err != nil {
		log.Error(err, "unable to create new terraform", "workingDir", req.WorkingDir, "execPath", req.ExecPath)
		return nil, err
	}

	// hold only 1 instance
	r.tf = tf

	var terraform infrav1.Terraform
	if err := terraform.FromBytes(req.Terraform, r.Scheme); err != nil {
		log.Error(err, "there was a problem getting the terraform resource")
		return nil, err
	}
	// cache the Terraform resource when initializing
	r.terraform = &terraform

	disableTestLogging := os.Getenv("DISABLE_TF_LOGS") == "1"
	if !disableTestLogging {
		r.tf.SetStdout(os.Stdout)
		r.tf.SetStderr(os.Stderr)
		if os.Getenv("ENABLE_SENSITIVE_TF_LOGS") == "1" {
			r.tf.SetLogger(&LocalPrintfer{logger: log})
		}
	}

	return &NewTerraformReply{Id: r.InstanceID}, nil
}

Exposure of Sensitive Information to an Unauthorized Actor

The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.


func (r *TerraformRunnerServer) Plan(ctx context.Context, req *PlanRequest) (*PlanReply, error) {
	log := controllerruntime.LoggerFrom(ctx, "instance-id", r.InstanceID).WithName(loggerName)
	log.Info("creating a plan")
	ctx, cancel := context.WithCancel(ctx)
	go func() {
		select {
		case <-r.Done:
			cancel()
		case <-ctx.Done():
		}
	}()

	if req.TfInstance != r.InstanceID {
		err := fmt.Errorf("no TF instance found")
		log.Error(err, "no terraform")
		return nil, err
	}

	var planOpt []tfexec.PlanOption
	if req.Out != "" {
		planOpt = append(planOpt, tfexec.Out(req.Out))
	} else {
		// if backend is disabled completely, there will be no plan output file (req.Out = "")
		log.Info("backend seems to be disabled completely, so there will be no plan output file")
	}

	if req.Refresh == false {
		planOpt = append(planOpt, tfexec.Refresh(req.Refresh))
	}

	if req.Destroy {
		planOpt = append(planOpt, tfexec.Destroy(req.Destroy))
	}

	for _, target := range req.Targets {
		planOpt = append(planOpt, tfexec.Target(target))
	}

	drifted, err := r.tf.Plan(ctx, planOpt...)
	if err != nil {
		st := status.New(codes.Internal, err.Error())
		var stateErr *tfexec.ErrStateLocked

		if errors.As(err, &stateErr) {
			st, err = st.WithDetails(&PlanReply{Message: "not ok", StateLockIdentifier: stateErr.ID})

			if err != nil {
				return nil, err
			}
		}

		log.Error(err, "error creating the plan")
		return nil, st.Err()
	}

	planCreated := false
	if req.Out != "" {
		planCreated = true
		plan, err := r.tf.ShowPlanFile(ctx, req.Out)
		if err != nil {
			return nil, err
		}

		// This is the case when the plan is empty.
		if plan.PlannedValues.Outputs == nil &&
			plan.PlannedValues.RootModule.Resources == nil &&
			plan.ResourceChanges == nil &&
			plan.PriorState == nil &&
			plan.OutputChanges == nil {
			planCreated = false
		}
	}

	return &PlanReply{Message: "ok", Drifted: drifted, PlanCreated: planCreated}, nil
}


func (r *TerraformRunnerServer) SaveTFPlan(ctx context.Context, req *SaveTFPlanRequest) (*SaveTFPlanReply, error) {
	log := controllerruntime.LoggerFrom(ctx, "instance-id", r.InstanceID).WithName(loggerName)
	log.Info("save the plan")
	if req.TfInstance != r.InstanceID {
		err := fmt.Errorf("no TF instance found")
		log.Error(err, "no terraform")
		return nil, err
	}

	var tfplan []byte
	if req.BackendCompletelyDisable {
		tfplan = []byte("dummy plan")
	} else {
		var err error
		tfplan, err = ioutil.ReadFile(filepath.Join(r.tf.WorkingDir(), TFPlanName))
		if err != nil {
			err = fmt.Errorf("error reading plan file: %s", err)
			log.Error(err, "unable to complete SaveTFPlan function")
			return nil, err
		}
	}

	planRev := strings.Replace(req.Revision, "/", "-", 1)
	planName := "plan-" + planRev
	if err := r.writePlanAsSecret(ctx, req.Name, req.Namespace, log, planName, tfplan, "", req.Uuid); err != nil {
		return nil, err
	}

	if r.terraform.Spec.StoreReadablePlan == "json" {
		planObj, err := r.tf.ShowPlanFile(ctx, TFPlanName)
		if err != nil {
			log.Error(err, "unable to get the plan output for json")
			return nil, err
		}
		jsonBytes, err := json.Marshal(planObj)
		if err != nil {
			log.Error(err, "unable to marshal the plan to json")
			return nil, err
		}

		if err := r.writePlanAsSecret(ctx, req.Name, req.Namespace, log, planName, jsonBytes, ".json", req.Uuid); err != nil {
			return nil, err
		}

	} else if r.terraform.Spec.StoreReadablePlan == "human" {
		rawOutput, err := r.tf.ShowPlanFileRaw(ctx, TFPlanName)
		if err != nil {
			log.Error(err, "unable to get the plan output for human")
			return nil, err
		}

		if err := r.writePlanAsConfigMap(ctx, req.Name, req.Namespace, log, planName, rawOutput, "", req.Uuid); err != nil {
			return nil, err
		}
	}

	return &SaveTFPlanReply{Message: "ok"}, nil
}


func (r *TerraformRunnerServer) ShowPlanFileRaw(ctx context.Context, req *ShowPlanFileRawRequest) (*ShowPlanFileRawReply, error) {
	log := controllerruntime.LoggerFrom(ctx, "instance-id", r.InstanceID).WithName(loggerName)
	log.Info("show the raw plan file")
	if req.TfInstance != r.InstanceID {
		err := fmt.Errorf("no TF instance found")
		log.Error(err, "no terraform")
		return nil, err
	}

	rawOutput, err := r.tf.ShowPlanFileRaw(ctx, req.Filename)
	if err != nil {
		log.Error(err, "unable to get the raw plan output")
		return nil, err
	}

	return &ShowPlanFileRawReply{RawOutput: rawOutput}, nil
}


func (r *TerraformRunnerServer) ShowPlanFile(ctx context.Context, req *ShowPlanFileRequest) (*ShowPlanFileReply, error) {
	log := controllerruntime.LoggerFrom(ctx, "instance-id", r.InstanceID).WithName(loggerName)
	log.Info("show the raw plan file")
	if req.TfInstance != r.InstanceID {
		err := fmt.Errorf("no TF instance found")
		log.Error(err, "no terraform")
		return nil, err
	}

	plan, err := r.tf.ShowPlanFile(ctx, req.Filename)
	if err != nil {
		log.Error(err, "unable to get the json plan output")
		return nil, err
	}

	jsonBytes, err := json.Marshal(plan)
	if err != nil {
		log.Error(err, "unable to marshal the plan to json")
		return nil, err
	}

	return &ShowPlanFileReply{JsonOutput: jsonBytes}, nil
}


func (r *TerraformRunnerServer) Output(ctx context.Context, req *OutputRequest) (*OutputReply, error) {
	log := ctrl.LoggerFrom(ctx, "instance-id", r.InstanceID).WithName(loggerName)
	log.Info("creating outputs")
	if req.TfInstance != r.InstanceID {
		err := fmt.Errorf("no TF instance found")
		log.Error(err, "no terraform")
		return nil, err
	}

	outputs, err := r.tf.Output(ctx)
	if err != nil {
		log.Error(err, "unable to get outputs")
		return nil, err
	}

	outputReply := &OutputReply{Outputs: map[string]*OutputMeta{}}
	for k, v := range outputs {
		outputReply.Outputs[k] = &OutputMeta{
			Sensitive: v.Sensitive,
			Type:      v.Type,
			Value:     v.Value,
		}
	}
	return outputReply, nil
}


func (ctx *Context) RedirectToFirst(location ...string) {
	for _, loc := range location {
		if len(loc) == 0 {
			continue
		}

		// Unfortunately browsers consider a redirect Location with preceding "//" and "/\" as meaning redirect to "http(s)://REST_OF_PATH"
		// Therefore we should ignore these redirect locations to prevent open redirects
		if len(loc) > 1 && loc[0] == '/' && (loc[1] == '/' || loc[1] == '\\') {
			continue
		}

		u, err := url.Parse(loc)
		if err != nil || ((u.Scheme != "" || u.Host != "") && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) {
			continue
		}

		ctx.Redirect(loc)
		return
	}

	ctx.Redirect(setting.AppSubURL + "/")
}

URL Redirection to Untrusted Site ('Open Redirect')

A web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a Redirect. This simplifies phishing attacks.


func (t *assetAction) checkERC20Deposit() error {
	asset, _ := t.asset.ERC20()
	return t.bridgeView.FindDeposit(
		t.erc20D, t.blockHeight, t.logIndex, asset.Address(),
	)
}

The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.


func (t *assetAction) checkERC20BridgeResumed() error {
	return t.bridgeView.FindBridgeResumed(
		t.erc20BridgeResumed, t.blockHeight, t.logIndex)
}


func (t *assetAction) checkERC20AssetList() error {
	return t.bridgeView.FindAssetList(t.erc20AL, t.blockHeight, t.logIndex)
}


func (t *assetAction) checkERC20BridgeStopped() error {
	return t.bridgeView.FindBridgeStopped(
		t.erc20BridgeStopped, t.blockHeight, t.logIndex)
}


func (t *assetAction) checkERC20AssetLimitsUpdated() error {
	asset, _ := t.asset.ERC20()
	return t.bridgeView.FindAssetLimitsUpdated(
		t.erc20AssetLimitsUpdated, t.blockHeight, t.logIndex, asset.Address(),
	)
}


func (m *MockERC20BridgeView) FindBridgeResumed(arg0 *types.ERC20EventBridgeResumed, arg1, arg2 uint64) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "FindBridgeResumed", arg0, arg1, arg2)
	ret0, _ := ret[0].(error)
	return ret0
}


func (m *MockERC20BridgeView) FindDeposit(arg0 *types.ERC20Deposit, arg1, arg2 uint64, arg3 string) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "FindDeposit", arg0, arg1, arg2, arg3)
	ret0, _ := ret[0].(error)
	return ret0
}


func (mr *MockERC20BridgeViewMockRecorder) FindAssetList(arg0, arg1, arg2 interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindAssetList", reflect.TypeOf((*MockERC20BridgeView)(nil).FindAssetList), arg0, arg1, arg2)
}


func (m *MockERC20BridgeView) FindBridgeStopped(arg0 *types.ERC20EventBridgeStopped, arg1, arg2 uint64) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "FindBridgeStopped", arg0, arg1, arg2)
	ret0, _ := ret[0].(error)
	return ret0
}


func (mr *MockERC20BridgeViewMockRecorder) FindDeposit(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindDeposit", reflect.TypeOf((*MockERC20BridgeView)(nil).FindDeposit), arg0, arg1, arg2, arg3)
}


func (m *MockERC20BridgeView) FindAssetList(arg0 *types.ERC20AssetList, arg1, arg2 uint64) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "FindAssetList", arg0, arg1, arg2)
	ret0, _ := ret[0].(error)
	return ret0
}


func (mr *MockERC20BridgeViewMockRecorder) FindBridgeResumed(arg0, arg1, arg2 interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindBridgeResumed", reflect.TypeOf((*MockERC20BridgeView)(nil).FindBridgeResumed), arg0, arg1, arg2)
}


func (mr *MockERC20BridgeViewMockRecorder) FindAssetLimitsUpdated(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindAssetLimitsUpdated", reflect.TypeOf((*MockERC20BridgeView)(nil).FindAssetLimitsUpdated), arg0, arg1, arg2, arg3)
}


func (m *MockERC20BridgeView) FindAssetLimitsUpdated(arg0 *types.ERC20AssetLimitsUpdated, arg1, arg2 uint64, arg3 string) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "FindAssetLimitsUpdated", arg0, arg1, arg2, arg3)
	ret0, _ := ret[0].(error)
	return ret0
}


func (mr *MockERC20BridgeViewMockRecorder) FindBridgeStopped(arg0, arg1, arg2 interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindBridgeStopped", reflect.TypeOf((*MockERC20BridgeView)(nil).FindBridgeStopped), arg0, arg1, arg2)
}


func (e *ERC20LogicView) FindBridgeStopped(
	al *types.ERC20EventBridgeStopped,
	blockNumber,
	logIndex uint64,
) error {
	bf, err := bridgecontract.NewErc20BridgeLogicRestrictedFilterer(
		e.clt.CollateralBridgeAddress(), e.clt)
	if err != nil {
		return err
	}

	resp := "ok"
	defer func() {
		metrics.EthCallInc("find_bridge_stopped", resp)
	}()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	iter, err := bf.FilterBridgeStopped(
		&bind.FilterOpts{
			Start:   blockNumber - 1,
			Context: ctx,
		},
	)
	if err != nil {
		resp = getMaybeHTTPStatus(err)
		return err
	}
	defer iter.Close()

	var event *bridgecontract.Erc20BridgeLogicRestrictedBridgeStopped

	for iter.Next() {
		if iter.Event.Raw.BlockNumber == blockNumber &&
			uint64(iter.Event.Raw.Index) == logIndex {
			event = iter.Event

			break
		}
	}

	if event == nil {
		return ErrUnableToFindERC20BridgeStopped
	}

	// now ensure we have enough confirmations
	if err := e.ethConfs.Check(event.Raw.BlockNumber); err != nil {
		return err
	}

	return nil
}


func (e *ERC20LogicView) FindAssetList(
	al *types.ERC20AssetList,
	blockNumber,
	logIndex uint64,
) error {
	bf, err := bridgecontract.NewErc20BridgeLogicRestrictedFilterer(
		e.clt.CollateralBridgeAddress(), e.clt)
	if err != nil {
		return err
	}

	resp := "ok"
	defer func() {
		metrics.EthCallInc("find_asset_list", al.VegaAssetID, resp)
	}()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	iter, err := bf.FilterAssetListed(
		&bind.FilterOpts{
			Start:   blockNumber - 1,
			Context: ctx,
		},
		[]ethcommon.Address{ethcommon.HexToAddress(al.AssetSource)},
		[][32]byte{},
	)
	if err != nil {
		resp = getMaybeHTTPStatus(err)
		return err
	}
	defer iter.Close()

	var event *bridgecontract.Erc20BridgeLogicRestrictedAssetListed
	assetID := strings.TrimPrefix(al.VegaAssetID, "0x")

	for iter.Next() {
		if hex.EncodeToString(iter.Event.VegaAssetId[:]) == assetID &&
			iter.Event.Raw.BlockNumber == blockNumber &&
			uint64(iter.Event.Raw.Index) == logIndex {
			event = iter.Event

			break
		}
	}

	if event == nil {
		return ErrUnableToFindERC20AssetList
	}

	// now ensure we have enough confirmations
	if err := e.ethConfs.Check(event.Raw.BlockNumber); err != nil {
		return err
	}

	return nil
}


func (e *ERC20LogicView) FindAssetLimitsUpdated(
	update *types.ERC20AssetLimitsUpdated,
	blockNumber uint64, logIndex uint64,
	ethAssetAddress string,
) error {
	bf, err := bridgecontract.NewErc20BridgeLogicRestrictedFilterer(
		e.clt.CollateralBridgeAddress(), e.clt)
	if err != nil {
		return err
	}

	resp := "ok"
	defer func() {
		metrics.EthCallInc("find_asset_limits_updated", update.VegaAssetID, resp)
	}()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	iter, err := bf.FilterAssetLimitsUpdated(
		&bind.FilterOpts{
			Start:   blockNumber - 1,
			Context: ctx,
		},
		[]ethcommon.Address{ethcommon.HexToAddress(ethAssetAddress)},
	)
	if err != nil {
		resp = getMaybeHTTPStatus(err)
		return err
	}
	defer iter.Close()

	var event *bridgecontract.Erc20BridgeLogicRestrictedAssetLimitsUpdated

	for iter.Next() {
		eventLifetimeLimit, _ := num.UintFromBig(iter.Event.LifetimeLimit)
		eventWithdrawThreshold, _ := num.UintFromBig(iter.Event.WithdrawThreshold)
		if update.LifetimeLimits.EQ(eventLifetimeLimit) &&
			update.WithdrawThreshold.EQ(eventWithdrawThreshold) &&
			iter.Event.Raw.BlockNumber == blockNumber &&
			uint64(iter.Event.Raw.Index) == logIndex {
			event = iter.Event
			break
		}
	}

	if event == nil {
		return ErrUnableToFindERC20AssetLimitsUpdated
	}

	// now ensure we have enough confirmations
	if err := e.ethConfs.Check(event.Raw.BlockNumber); err != nil {
		return err
	}

	return nil
}


func (e *ERC20LogicView) FindWithdrawal(
	w *types.ERC20Withdrawal,
	blockNumber, logIndex uint64,
	ethAssetAddress string,
) (*big.Int, string, uint, error) {
	bf, err := bridgecontract.NewErc20BridgeLogicRestrictedFilterer(
		e.clt.CollateralBridgeAddress(), e.clt)
	if err != nil {
		return nil, "", 0, err
	}

	resp := "ok"
	defer func() {
		metrics.EthCallInc("find_withdrawal", w.VegaAssetID, resp)
	}()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	iter, err := bf.FilterAssetWithdrawn(
		&bind.FilterOpts{
			Start:   blockNumber - 1,
			Context: ctx,
		},
		// user_address
		[]ethcommon.Address{ethcommon.HexToAddress(w.TargetEthereumAddress)},
		// asset_source
		[]ethcommon.Address{ethcommon.HexToAddress(ethAssetAddress)})
	if err != nil {
		resp = getMaybeHTTPStatus(err)
		return nil, "", 0, err
	}
	defer iter.Close()

	var event *bridgecontract.Erc20BridgeLogicRestrictedAssetWithdrawn
	nonce := &big.Int{}
	_, ok := nonce.SetString(w.ReferenceNonce, 10)
	if !ok {
		return nil, "", 0, fmt.Errorf("could not use reference nonce, expected base 10 integer: %v", w.ReferenceNonce)
	}

	for iter.Next() {
		if nonce.Cmp(iter.Event.Nonce) == 0 &&
			iter.Event.Raw.BlockNumber == blockNumber &&
			uint64(iter.Event.Raw.Index) == logIndex {
			event = iter.Event

			break
		}
	}

	if event == nil {
		return nil, "", 0, ErrUnableToFindERC20Withdrawal
	}

	// now ensure we have enough confirmations
	if err := e.ethConfs.Check(event.Raw.BlockNumber); err != nil {
		return nil, "", 0, err
	}

	return nonce, event.Raw.TxHash.Hex(), event.Raw.Index, nil
}


func (e *ERC20LogicView) FindBridgeResumed(
	al *types.ERC20EventBridgeResumed,
	blockNumber,
	logIndex uint64,
) error {
	bf, err := bridgecontract.NewErc20BridgeLogicRestrictedFilterer(
		e.clt.CollateralBridgeAddress(), e.clt)
	if err != nil {
		return err
	}

	resp := "ok"
	defer func() {
		metrics.EthCallInc("find_bridge_stopped", resp)
	}()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	iter, err := bf.FilterBridgeResumed(
		&bind.FilterOpts{
			Start:   blockNumber - 1,
			Context: ctx,
		},
	)
	if err != nil {
		resp = getMaybeHTTPStatus(err)
		return err
	}
	defer iter.Close()

	var event *bridgecontract.Erc20BridgeLogicRestrictedBridgeResumed

	for iter.Next() {
		if iter.Event.Raw.BlockNumber == blockNumber &&
			uint64(iter.Event.Raw.Index) == logIndex {
			event = iter.Event

			break
		}
	}

	if event == nil {
		return ErrUnableToFindERC20BridgeStopped
	}

	// now ensure we have enough confirmations
	if err := e.ethConfs.Check(event.Raw.BlockNumber); err != nil {
		return err
	}

	return nil
}


func (e *ERC20LogicView) FindDeposit(
	d *types.ERC20Deposit,
	blockNumber, logIndex uint64,
	ethAssetAddress string,
) error {
	bf, err := bridgecontract.NewErc20BridgeLogicRestrictedFilterer(
		e.clt.CollateralBridgeAddress(), e.clt)
	if err != nil {
		return err
	}

	resp := "ok"
	defer func() {
		metrics.EthCallInc("find_deposit", d.VegaAssetID, resp)
	}()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	iter, err := bf.FilterAssetDeposited(
		&bind.FilterOpts{
			Start:   blockNumber - 1,
			Context: ctx,
		},
		// user_address
		[]ethcommon.Address{ethcommon.HexToAddress(d.SourceEthereumAddress)},
		// asset_source
		[]ethcommon.Address{ethcommon.HexToAddress(ethAssetAddress)})
	if err != nil {
		resp = getMaybeHTTPStatus(err)
		return err
	}
	defer iter.Close()

	depamount := d.Amount.BigInt()
	var event *bridgecontract.Erc20BridgeLogicRestrictedAssetDeposited
	targetPartyID := strings.TrimPrefix(d.TargetPartyID, "0x")

	for iter.Next() {
		if hex.EncodeToString(iter.Event.VegaPublicKey[:]) == targetPartyID &&
			iter.Event.Amount.Cmp(depamount) == 0 &&
			iter.Event.Raw.BlockNumber == blockNumber &&
			uint64(iter.Event.Raw.Index) == logIndex {
			event = iter.Event
			break
		}
	}

	if event == nil {
		return ErrUnableToFindERC20Deposit
	}

	// now ensure we have enough confirmations
	if err := e.ethConfs.Check(event.Raw.BlockNumber); err != nil {
		return err
	}

	return nil
}


func (*BridgeViewStub) FindDeposit(d *types.ERC20Deposit, blockNumber, logIndex uint64, ethAssetAddress string) error {
	return nil
}


func (*BridgeViewStub) FindBridgeResumed(al *types.ERC20EventBridgeResumed, blockNumber, logIndex uint64) error {
	return nil
}


func (*BridgeViewStub) FindBridgeStopped(al *types.ERC20EventBridgeStopped, blockNumber, logIndex uint64) error {
	return nil
}


func (*BridgeViewStub) FindAssetLimitsUpdated(w *types.ERC20AssetLimitsUpdated, blockNumber, logIndex uint64, ethAssetAddress string) error {
	return nil
}


func (*BridgeViewStub) FindAssetList(al *types.ERC20AssetList, blockNumber, logIndex uint64) error {
	return nil
}


func (o *OnChainVerifier) filterSignerAdded(
	ctx context.Context,
	filterer *multisig.MultisigControlFilterer,
	event *types.SignerEvent,
) error {
	iter, err := filterer.FilterSignerAdded(
		&bind.FilterOpts{
			Start:   event.BlockNumber,
			End:     &event.BlockNumber,
			Context: ctx,
		},
	)
	if err != nil {
		o.log.Error("Couldn't start filtering on signer added event",
			logging.Error(err))
		return err
	}
	defer iter.Close()

	for iter.Next() {
		if o.log.GetLevel() <= logging.DebugLevel {
			o.log.Debug("found signer added event on chain",
				logging.String("new-signer", iter.Event.NewSigner.Hex()),
			)
		}

		nonce, _ := big.NewInt(0).SetString(event.Nonce, 10)
		if iter.Event.Raw.BlockNumber == event.BlockNumber &&
			uint64(iter.Event.Raw.Index) == event.LogIndex &&
			iter.Event.NewSigner.Hex() == event.Address &&
			nonce.Cmp(iter.Event.Nonce) == 0 {
			// now we know the event is OK,
			// just need to check for confirmations
			return o.ethConfirmations.Check(event.BlockNumber)
		}
	}

	return ErrNoSignerEventFound
}


func (o *OnChainVerifier) CheckThresholdSetEvent(
	event *types.SignerThresholdSetEvent,
) error {
	o.mu.RLock()
	defer o.mu.RUnlock()

	if o.log.GetLevel() <= logging.DebugLevel {
		o.log.Debug("checking threshold set event on chain",
			logging.String("contract-address", o.multiSigAddress.Hex()),
			logging.String("event", event.String()),
		)
	}

	filterer, err := multisig.NewMultisigControlFilterer(
		o.multiSigAddress,
		o.ethClient,
	)
	if err != nil {
		o.log.Error("could not instantiate multisig control filterer",
			logging.Error(err))
		return err
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	iter, err := filterer.FilterThresholdSet(
		&bind.FilterOpts{
			Start:   event.BlockNumber,
			End:     &event.BlockNumber,
			Context: ctx,
		},
	)
	if err != nil {
		o.log.Error("Couldn't start filtering on signer added event",
			logging.Error(err))
		return err
	}
	defer iter.Close()

	for iter.Next() {
		if o.log.GetLevel() <= logging.DebugLevel {
			o.log.Debug("found threshold set event on chain",
				logging.Uint16("new-threshold", iter.Event.NewThreshold),
			)
		}

		nonce, _ := big.NewInt(0).SetString(event.Nonce, 10)
		if iter.Event.Raw.BlockNumber == event.BlockNumber &&
			uint64(iter.Event.Raw.Index) == event.LogIndex &&
			iter.Event.NewThreshold == uint16(event.Threshold) &&
			nonce.Cmp(iter.Event.Nonce) == 0 {
			// now we know the event is OK,
			// just need to check for confirmations
			return o.ethConfirmations.Check(event.BlockNumber)
		}
	}

	return ErrNoThresholdSetEventFound
}


func (o *OnChainVerifier) filterSignerRemoved(
	ctx context.Context,
	filterer *multisig.MultisigControlFilterer,
	event *types.SignerEvent,
) error {
	iter, err := filterer.FilterSignerRemoved(
		&bind.FilterOpts{
			Start:   event.BlockNumber,
			End:     &event.BlockNumber,
			Context: ctx,
		},
	)
	if err != nil {
		o.log.Error("Couldn't start filtering on signer removed event",
			logging.Error(err))
		return err
	}
	defer iter.Close()

	for iter.Next() {
		if o.log.GetLevel() <= logging.DebugLevel {
			o.log.Debug("found signer removed event on chain",
				logging.String("old-signer", iter.Event.OldSigner.Hex()),
			)
		}

		nonce, _ := big.NewInt(0).SetString(event.Nonce, 10)
		if iter.Event.Raw.BlockNumber == event.BlockNumber &&
			uint64(iter.Event.Raw.Index) == event.LogIndex &&
			iter.Event.OldSigner.Hex() == event.Address &&
			nonce.Cmp(iter.Event.Nonce) == 0 {
			// now we know the event is OK,
			// just need to check for confirmations
			return o.ethConfirmations.Check(event.BlockNumber)
		}
	}

	return ErrNoSignerEventFound
}


func ValidateAllAuthorizationModels(ctx context.Context, db storage.OpenFGADatastore) ([]validationResult, error) {
	validationResults := make([]validationResult, 0)

	continuationTokenStores := ""

	for {
		// fetch a page of stores
		stores, tokenStores, err := db.ListStores(ctx, storage.PaginationOptions{
			PageSize: 100,
			From:     continuationTokenStores,
		})
		if err != nil {
			return nil, fmt.Errorf("error reading stores: %w", err)
		}

		// validate each store
		for _, store := range stores {

			latestModelID, err := db.FindLatestAuthorizationModelID(ctx, store.Id)
			if err != nil {
				fmt.Printf("no models in store %s \n", store.Id)
			}

			continuationTokenModels := ""

			for {
				// fetch a page of models for that store
				models, tokenModels, err := db.ReadAuthorizationModels(ctx, store.Id, storage.PaginationOptions{
					PageSize: 100,
					From:     continuationTokenModels,
				})
				if err != nil {
					return nil, fmt.Errorf("error reading authorization models: %w", err)
				}

				// validate each model
				for _, model := range models {
					_, err := typesystem.NewAndValidate(model)

					validationResult := validationResult{
						StoreID:       store.Id,
						ModelID:       model.Id,
						IsLatestModel: model.Id == latestModelID,
					}

					if err != nil {
						validationResult.Error = err.Error()
					}
					validationResults = append(validationResults, validationResult)
				}

				continuationTokenModels = string(tokenModels)

				if continuationTokenModels == "" {
					break
				}
			}
		}

		// next page of stores
		continuationTokenStores = string(tokenStores)

		if continuationTokenStores == "" {
			break
		}
	}

	return validationResults, nil
}

Loop with Unreachable Exit Condition ('Infinite Loop')

The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.


func (q *ExpandQuery) Execute(ctx context.Context, req *openfgapb.ExpandRequest) (*openfgapb.ExpandResponse, error) {
	store := req.GetStoreId()
	modelID := req.GetAuthorizationModelId()
	tupleKey := req.GetTupleKey()
	object := tupleKey.GetObject()
	relation := tupleKey.GetRelation()

	if object == "" || relation == "" {
		return nil, serverErrors.InvalidExpandInput
	}

	tk := tupleUtils.NewTupleKey(object, relation, "")

	model, err := q.datastore.ReadAuthorizationModel(ctx, store, modelID)
	if err != nil {
		if errors.Is(err, storage.ErrNotFound) {
			return nil, serverErrors.AuthorizationModelNotFound(modelID)
		}

		return nil, serverErrors.HandleError("", err)
	}

	if !typesystem.IsSchemaVersionSupported(model.GetSchemaVersion()) {
		return nil, serverErrors.ValidationError(typesystem.ErrInvalidSchemaVersion)
	}

	typesys := typesystem.New(model)

	if err = validation.ValidateObject(typesys, tk); err != nil {
		return nil, serverErrors.ValidationError(err)
	}

	err = validation.ValidateRelation(typesys, tk)
	if err != nil {
		return nil, serverErrors.ValidationError(err)
	}

	objectType := tupleUtils.GetType(object)
	rel, err := typesys.GetRelation(objectType, relation)
	if err != nil {
		if errors.Is(err, typesystem.ErrObjectTypeUndefined) {
			return nil, serverErrors.TypeNotFound(objectType)
		}

		if errors.Is(err, typesystem.ErrRelationUndefined) {
			return nil, serverErrors.RelationNotFound(relation, objectType, tk)
		}

		return nil, serverErrors.HandleError("", err)
	}

	userset := rel.GetRewrite()

	root, err := q.resolveUserset(ctx, store, userset, tk, typesys)
	if err != nil {
		return nil, err
	}

	return &openfgapb.ExpandResponse{
		Tree: &openfgapb.UsersetTree{
			Root: root,
		},
	}, nil
}


func (w *WriteAuthorizationModelCommand) Execute(ctx context.Context, req *openfgapb.WriteAuthorizationModelRequest) (*openfgapb.WriteAuthorizationModelResponse, error) {
	// Until this is solved: https://github.com/envoyproxy/protoc-gen-validate/issues/74
	if len(req.GetTypeDefinitions()) > w.backend.MaxTypesPerAuthorizationModel() {
		return nil, serverErrors.ExceededEntityLimit("type definitions in an authorization model", w.backend.MaxTypesPerAuthorizationModel())
	}

	// Fill in the schema version for old requests, which don't contain it, while we migrate to the new schema version.
	if req.SchemaVersion == "" {
		req.SchemaVersion = typesystem.SchemaVersion1_1
	}

	model := &openfgapb.AuthorizationModel{
		Id:              ulid.Make().String(),
		SchemaVersion:   req.GetSchemaVersion(),
		TypeDefinitions: req.GetTypeDefinitions(),
	}

	_, err := typesystem.NewAndValidate(model)
	if err != nil {
		return nil, serverErrors.InvalidAuthorizationModelInput(err)
	}

	err = w.backend.WriteAuthorizationModel(ctx, req.GetStoreId(), model)
	if err != nil {
		return nil, serverErrors.NewInternalError("Error writing authorization model configuration", err)
	}

	return &openfgapb.WriteAuthorizationModelResponse{
		AuthorizationModelId: model.Id,
	}, nil
}


func (s *Server) StreamedListObjects(req *openfgapb.StreamedListObjectsRequest, srv openfgapb.OpenFGAService_StreamedListObjectsServer) error {
	ctx := srv.Context()
	ctx, span := tracer.Start(ctx, "StreamedListObjects", trace.WithAttributes(
		attribute.String("object_type", req.GetType()),
		attribute.String("relation", req.GetRelation()),
		attribute.String("user", req.GetUser()),
	))
	defer span.End()

	storeID := req.GetStoreId()

	modelID, err := s.resolveAuthorizationModelID(ctx, storeID, req.GetAuthorizationModelId())
	if err != nil {
		return err
	}

	model, err := s.datastore.ReadAuthorizationModel(ctx, storeID, modelID)
	if err != nil {
		if errors.Is(err, storage.ErrNotFound) {
			return serverErrors.AuthorizationModelNotFound(req.GetAuthorizationModelId())
		}

		return serverErrors.HandleError("", err)
	}

	typesys := typesystem.New(model)

	ctx = typesystem.ContextWithTypesystem(ctx, typesys)

	q := &commands.ListObjectsQuery{
		Datastore:             s.datastore,
		Logger:                s.logger,
		ListObjectsDeadline:   s.config.ListObjectsDeadline,
		ListObjectsMaxResults: s.config.ListObjectsMaxResults,
		ResolveNodeLimit:      s.config.ResolveNodeLimit,
	}

	req.AuthorizationModelId = modelID
	return q.ExecuteStreamed(ctx, req, srv)
}


func (s *Server) ListObjects(ctx context.Context, req *openfgapb.ListObjectsRequest) (*openfgapb.ListObjectsResponse, error) {
	storeID := req.GetStoreId()
	targetObjectType := req.GetType()

	ctx, span := tracer.Start(ctx, "ListObjects", trace.WithAttributes(
		attribute.String("object_type", targetObjectType),
		attribute.String("relation", req.GetRelation()),
		attribute.String("user", req.GetUser()),
	))
	defer span.End()

	modelID := req.GetAuthorizationModelId()

	modelID, err := s.resolveAuthorizationModelID(ctx, storeID, modelID)
	if err != nil {
		return nil, err
	}

	model, err := s.datastore.ReadAuthorizationModel(ctx, storeID, modelID)
	if err != nil {
		if errors.Is(err, storage.ErrNotFound) {
			return nil, serverErrors.AuthorizationModelNotFound(modelID)
		}

		return nil, err
	}

	typesys := typesystem.New(model)

	ctx = typesystem.ContextWithTypesystem(ctx, typesys)

	q := &commands.ListObjectsQuery{
		Datastore:             s.datastore,
		Logger:                s.logger,
		ListObjectsDeadline:   s.config.ListObjectsDeadline,
		ListObjectsMaxResults: s.config.ListObjectsMaxResults,
		ResolveNodeLimit:      s.config.ResolveNodeLimit,
	}
	return q.Execute(ctx, &openfgapb.ListObjectsRequest{
		StoreId:              storeID,
		ContextualTuples:     req.GetContextualTuples(),
		AuthorizationModelId: modelID,
		Type:                 targetObjectType,
		Relation:             req.Relation,
		User:                 req.User,
	})
}


func TestCheckDoesNotThrowBecauseDirectTupleWasFound(t *testing.T) {
	ctx := context.Background()
	storeID := ulid.Make().String()
	modelID := ulid.Make().String()

	typedefs := parser.MustParse(`
	type user

	type repo
	  relations
	    define reader: [user] as self
	`)

	tk := tuple.NewTupleKey("repo:openfga", "reader", "user:anne")
	tuple := &openfgapb.Tuple{Key: tk}

	mockController := gomock.NewController(t)
	defer mockController.Finish()

	mockDatastore := mockstorage.NewMockOpenFGADatastore(mockController)

	mockDatastore.EXPECT().
		ReadAuthorizationModel(gomock.Any(), storeID, modelID).
		AnyTimes().
		Return(&openfgapb.AuthorizationModel{
			SchemaVersion:   typesystem.SchemaVersion1_1,
			TypeDefinitions: typedefs,
		}, nil)

	// it could happen that one of the following two mocks won't be necessary because the goroutine will be short-circuited
	mockDatastore.EXPECT().
		ReadUserTuple(gomock.Any(), storeID, gomock.Any()).
		AnyTimes().
		Return(tuple, nil)

	mockDatastore.EXPECT().
		ReadUsersetTuples(gomock.Any(), storeID, gomock.Any()).
		AnyTimes().
		DoAndReturn(
			func(_ context.Context, _ string, _ storage.ReadUsersetTuplesFilter) (storage.TupleIterator, error) {
				time.Sleep(50 * time.Millisecond)
				return nil, errors.New("some error")
			})

	s := New(&Dependencies{
		Datastore: mockDatastore,
		Logger:    logger.NewNoopLogger(),
		Transport: gateway.NewNoopTransport(),
	}, &Config{
		ResolveNodeLimit: 25,
	})

	checkResponse, err := s.Check(ctx, &openfgapb.CheckRequest{
		StoreId:              storeID,
		TupleKey:             tk,
		AuthorizationModelId: modelID,
	})
	require.NoError(t, err)
	require.Equal(t, true, checkResponse.Allowed)
}


func BenchmarkListObjectsNoRaceCondition(b *testing.B) {
	ctx := context.Background()
	logger := logger.NewNoopLogger()
	transport := gateway.NewNoopTransport()
	store := ulid.Make().String()
	modelID := ulid.Make().String()

	mockController := gomock.NewController(b)
	defer mockController.Finish()

	typedefs := parser.MustParse(`
	type user

	type repo
	  relations
	    define allowed: [user] as self
	    define viewer: [user] as self and allowed
    `)

	mockDatastore := mockstorage.NewMockOpenFGADatastore(mockController)

	mockDatastore.EXPECT().ReadAuthorizationModel(gomock.Any(), store, modelID).AnyTimes().Return(&openfgapb.AuthorizationModel{
		SchemaVersion:   typesystem.SchemaVersion1_1,
		TypeDefinitions: typedefs,
	}, nil)
	mockDatastore.EXPECT().ListObjectsByType(gomock.Any(), store, "repo").AnyTimes().Return(nil, errors.New("error reading from storage"))

	s := New(&Dependencies{
		Datastore: mockDatastore,
		Transport: transport,
		Logger:    logger,
	}, &Config{
		ResolveNodeLimit:      25,
		ListObjectsDeadline:   5 * time.Second,
		ListObjectsMaxResults: 1000,
	})

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := s.ListObjects(ctx, &openfgapb.ListObjectsRequest{
			StoreId:              store,
			AuthorizationModelId: modelID,
			Type:                 "repo",
			Relation:             "viewer",
			User:                 "user:bob",
		})

		require.ErrorIs(b, err, serverErrors.NewInternalError("", errors.New("error reading from storage")))

		err = s.StreamedListObjects(&openfgapb.StreamedListObjectsRequest{
			StoreId:              store,
			AuthorizationModelId: modelID,
			Type:                 "repo",
			Relation:             "viewer",
			User:                 "user:bob",
		}, NewMockStreamServer())

		require.ErrorIs(b, err, serverErrors.NewInternalError("", errors.New("error reading from storage")))
	}
}


func TestListObjects_Unoptimized_UnhappyPaths(t *testing.T) {
	ctx := context.Background()
	logger := logger.NewNoopLogger()
	transport := gateway.NewNoopTransport()
	store := ulid.Make().String()
	modelID := ulid.Make().String()

	mockController := gomock.NewController(t)
	defer mockController.Finish()

	mockDatastore := mockstorage.NewMockOpenFGADatastore(mockController)

	mockDatastore.EXPECT().ReadAuthorizationModel(gomock.Any(), store, modelID).AnyTimes().Return(&openfgapb.AuthorizationModel{
		SchemaVersion: typesystem.SchemaVersion1_1,
		TypeDefinitions: parser.MustParse(`
		type user

		type repo
		  relations
		    define allowed: [user] as self
		    define viewer: [user] as self and allowed
		`),
	}, nil)
	mockDatastore.EXPECT().ListObjectsByType(gomock.Any(), store, "repo").AnyTimes().Return(nil, errors.New("error reading from storage"))

	s := New(&Dependencies{
		Datastore: mockDatastore,
		Transport: transport,
		Logger:    logger,
	}, &Config{
		ResolveNodeLimit:      25,
		ListObjectsDeadline:   5 * time.Second,
		ListObjectsMaxResults: 1000,
	})

	t.Run("error_listing_objects_from_storage_in_non-streaming_version", func(t *testing.T) {
		res, err := s.ListObjects(ctx, &openfgapb.ListObjectsRequest{
			StoreId:              store,
			AuthorizationModelId: modelID,
			Type:                 "repo",
			Relation:             "viewer",
			User:                 "user:bob",
		})

		require.Nil(t, res)
		require.ErrorIs(t, err, serverErrors.NewInternalError("", errors.New("error reading from storage")))
	})

	t.Run("error_listing_objects_from_storage_in_streaming_version", func(t *testing.T) {
		err := s.StreamedListObjects(&openfgapb.StreamedListObjectsRequest{
			StoreId:              store,
			AuthorizationModelId: modelID,
			Type:                 "repo",
			Relation:             "viewer",
			User:                 "user:bob",
		}, NewMockStreamServer())

		require.ErrorIs(t, err, serverErrors.NewInternalError("", errors.New("error reading from storage")))
	})
}


func BenchmarkListObjectsWithConcurrentChecks(b *testing.B, ds storage.OpenFGADatastore) {
	ctx := context.Background()
	store := ulid.Make().String()

	typedefs := parser.MustParse(`
	type user

	type document
	  relations
	    define allowed: [user] as self
	    define viewer: [user] as self and allowed
	`)

	model := &openfgapb.AuthorizationModel{
		Id:              ulid.Make().String(),
		SchemaVersion:   typesystem.SchemaVersion1_1,
		TypeDefinitions: typedefs,
	}
	err := ds.WriteAuthorizationModel(ctx, store, model)
	require.NoError(b, err)

	n := 0
	for i := 0; i < 100; i++ {
		var tuples []*openfgapb.TupleKey

		for j := 0; j < ds.MaxTuplesPerWrite()/2; j++ {
			obj := fmt.Sprintf("document:%s", strconv.Itoa(n))
			user := fmt.Sprintf("user:%s", strconv.Itoa(n))

			tuples = append(
				tuples,
				tuple.NewTupleKey(obj, "viewer", user),
				tuple.NewTupleKey(obj, "allowed", user),
			)

			n += 1
		}

		err = ds.Write(ctx, store, nil, tuples)
		require.NoError(b, err)
	}

	listObjectsQuery := commands.ListObjectsQuery{
		Datastore:        ds,
		Logger:           logger.NewNoopLogger(),
		ResolveNodeLimit: defaultResolveNodeLimit,
	}

	var r *openfgapb.ListObjectsResponse

	ctx = typesystem.ContextWithTypesystem(ctx, typesystem.New(model))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		r, _ = listObjectsQuery.Execute(ctx, &openfgapb.ListObjectsRequest{
			StoreId:              store,
			AuthorizationModelId: model.Id,
			Type:                 "document",
			Relation:             "viewer",
			User:                 "user:999",
		})
	}

	listObjectsResponse = r
}


func BenchmarkListObjectsWithReverseExpand(b *testing.B, ds storage.OpenFGADatastore) {

	ctx := context.Background()
	store := ulid.Make().String()

	model := &openfgapb.AuthorizationModel{
		Id:            ulid.Make().String(),
		SchemaVersion: typesystem.SchemaVersion1_1,
		TypeDefinitions: []*openfgapb.TypeDefinition{
			{
				Type: "user",
			},
			{
				Type: "document",
				Relations: map[string]*openfgapb.Userset{
					"viewer": typesystem.This(),
				},
				Metadata: &openfgapb.Metadata{
					Relations: map[string]*openfgapb.RelationMetadata{
						"viewer": {
							DirectlyRelatedUserTypes: []*openfgapb.RelationReference{
								typesystem.DirectRelationReference("user", ""),
							},
						},
					},
				},
			},
		},
	}
	err := ds.WriteAuthorizationModel(ctx, store, model)
	require.NoError(b, err)

	n := 0
	for i := 0; i < 100; i++ {
		var tuples []*openfgapb.TupleKey

		for j := 0; j < ds.MaxTuplesPerWrite(); j++ {
			obj := fmt.Sprintf("document:%s", strconv.Itoa(n))
			user := fmt.Sprintf("user:%s", strconv.Itoa(n))

			tuples = append(tuples, tuple.NewTupleKey(obj, "viewer", user))

			n += 1
		}

		err = ds.Write(ctx, store, nil, tuples)
		require.NoError(b, err)
	}

	listObjectsQuery := commands.ListObjectsQuery{
		Datastore:        ds,
		Logger:           logger.NewNoopLogger(),
		ResolveNodeLimit: defaultResolveNodeLimit,
	}

	var r *openfgapb.ListObjectsResponse

	ctx = typesystem.ContextWithTypesystem(ctx, typesystem.New(model))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		r, _ = listObjectsQuery.Execute(ctx, &openfgapb.ListObjectsRequest{
			StoreId:              store,
			AuthorizationModelId: model.Id,
			Type:                 "document",
			Relation:             "viewer",
			User:                 "user:999",
		})
	}

	listObjectsResponse = r
}


func RunQueryTests(t *testing.T, ds storage.OpenFGADatastore) {
	t.Run("TestReadAuthorizationModelQueryErrors", func(t *testing.T) { TestReadAuthorizationModelQueryErrors(t, ds) })
	t.Run("TestSuccessfulReadAuthorizationModelQuery", func(t *testing.T) { TestSuccessfulReadAuthorizationModelQuery(t, ds) })
	t.Run("TestReadAuthorizationModel", func(t *testing.T) { ReadAuthorizationModelTest(t, ds) })

	t.Run("TestExpandQuery", func(t *testing.T) { TestExpandQuery(t, ds) })
	t.Run("TestExpandQueryErrors", func(t *testing.T) { TestExpandQueryErrors(t, ds) })

	t.Run("TestGetStoreQuery", func(t *testing.T) { TestGetStoreQuery(t, ds) })
	t.Run("TestGetStoreSucceeds", func(t *testing.T) { TestGetStoreSucceeds(t, ds) })
	t.Run("TestListStores", func(t *testing.T) { TestListStores(t, ds) })

	t.Run("TestReadAssertionQuery", func(t *testing.T) { TestReadAssertionQuery(t, ds) })

	t.Run("TestReadQuerySuccess", func(t *testing.T) { ReadQuerySuccessTest(t, ds) })
	t.Run("TestReadQueryError", func(t *testing.T) { ReadQueryErrorTest(t, ds) })
	t.Run("TestReadAllTuples", func(t *testing.T) { ReadAllTuplesTest(t, ds) })
	t.Run("TestReadAllTuplesInvalidContinuationToken", func(t *testing.T) { ReadAllTuplesInvalidContinuationTokenTest(t, ds) })

	t.Run("TestReadAuthorizationModelsWithoutPaging",
		func(t *testing.T) { TestReadAuthorizationModelsWithoutPaging(t, ds) },
	)

	t.Run("TestReadAuthorizationModelsWithPaging",
		func(t *testing.T) { TestReadAuthorizationModelsWithPaging(t, ds) },
	)

	t.Run("TestReadAuthorizationModelsInvalidContinuationToken",
		func(t *testing.T) { TestReadAuthorizationModelsInvalidContinuationToken(t, ds) },
	)

	t.Run("TestReadChanges", func(t *testing.T) { TestReadChanges(t, ds) })
	t.Run("TestReadChangesReturnsSameContTokenWhenNoChanges",
		func(t *testing.T) { TestReadChangesReturnsSameContTokenWhenNoChanges(t, ds) },
	)

	t.Run("TestListObjectsRespectsMaxResults", func(t *testing.T) { TestListObjectsRespectsMaxResults(t, ds) })
}


func New(model *openfgapb.AuthorizationModel) *TypeSystem {
	tds := make(map[string]*openfgapb.TypeDefinition, len(model.GetTypeDefinitions()))
	relations := make(map[string]map[string]*openfgapb.Relation, len(model.GetTypeDefinitions()))

	for _, td := range model.GetTypeDefinitions() {
		tds[td.GetType()] = td
		tdRelations := make(map[string]*openfgapb.Relation, len(td.GetRelations()))

		for relation, rewrite := range td.GetRelations() {
			r := &openfgapb.Relation{
				Name:     relation,
				Rewrite:  rewrite,
				TypeInfo: &openfgapb.RelationTypeInfo{},
			}

			if metadata, ok := td.GetMetadata().GetRelations()[relation]; ok {
				r.TypeInfo.DirectlyRelatedUserTypes = metadata.GetDirectlyRelatedUserTypes()
			}

			tdRelations[relation] = r
		}
		relations[td.GetType()] = tdRelations
	}

	return &TypeSystem{
		modelID:         model.GetId(),
		schemaVersion:   model.GetSchemaVersion(),
		typeDefinitions: tds,
		relations:       relations,
	}
}


func TestSuccessfulRewriteValidations(t *testing.T) {
	var tests = []struct {
		name  string
		model *openfgapb.AuthorizationModel
	}{
		{
			name: "empty_relations",
			model: &openfgapb.AuthorizationModel{
				SchemaVersion: SchemaVersion1_1,
				TypeDefinitions: []*openfgapb.TypeDefinition{
					{
						Type: "repo",
					},
				},
			},
		},
		{
			name: "zero_length_relations_is_valid",
			model: &openfgapb.AuthorizationModel{
				SchemaVersion: SchemaVersion1_1,
				TypeDefinitions: []*openfgapb.TypeDefinition{
					{
						Type:      "repo",
						Relations: map[string]*openfgapb.Userset{},
					},
				},
			},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			_, err := NewAndValidate(test.model)
			require.NoError(t, err)
		})
	}
}


func (c *LocalChecker) checkComputedUserset(parentctx context.Context, req *ResolveCheckRequest, rewrite *openfgav1.Userset_ComputedUserset) CheckHandlerFunc {
	return func(ctx context.Context) (*ResolveCheckResponse, error) {
		ctx, span := tracer.Start(ctx, "checkComputedUserset")
		defer span.End()

		return c.dispatch(
			ctx,
			&ResolveCheckRequest{
				StoreID:              req.GetStoreID(),
				AuthorizationModelID: req.GetAuthorizationModelID(),
				TupleKey: tuple.NewTupleKey(
					req.TupleKey.GetObject(),
					rewrite.ComputedUserset.GetRelation(),
					req.TupleKey.GetUser(),
				),
				ResolutionMetadata: &ResolutionMetadata{
					Depth:               req.GetResolutionMetadata().Depth - 1,
					DatastoreQueryCount: req.GetResolutionMetadata().DatastoreQueryCount,
				},
			})(ctx)
	}
}


func TestListObjects_Unoptimized_UnhappyPaths_Known_Error(t *testing.T) {
	ctx := context.Background()
	store := ulid.Make().String()
	modelID := ulid.Make().String()

	mockController := gomock.NewController(t)
	defer mockController.Finish()

	mockDatastore := mockstorage.NewMockOpenFGADatastore(mockController)

	mockDatastore.EXPECT().ReadAuthorizationModel(gomock.Any(), store, modelID).AnyTimes().Return(&openfgav1.AuthorizationModel{
		SchemaVersion: typesystem.SchemaVersion1_1,
		TypeDefinitions: parser.MustParse(`
		type user

		type repo
		  relations
		    define allowed: [user] as self
		    define viewer: [user] as self and allowed
		`),
	}, nil)
	mockDatastore.EXPECT().ReadStartingWithUser(gomock.Any(), store, gomock.Any()).AnyTimes().Return(nil, serverErrors.AuthorizationModelResolutionTooComplex)

	s := MustNewServerWithOpts(
		WithDatastore(mockDatastore),
	)

	t.Run("error_listing_objects_from_storage_in_non-streaming_version", func(t *testing.T) {
		res, err := s.ListObjects(ctx, &openfgav1.ListObjectsRequest{
			StoreId:              store,
			AuthorizationModelId: modelID,
			Type:                 "repo",
			Relation:             "viewer",
			User:                 "user:bob",
		})

		require.Nil(t, res)
		require.ErrorIs(t, err, serverErrors.AuthorizationModelResolutionTooComplex)
	})

	t.Run("error_listing_objects_from_storage_in_streaming_version", func(t *testing.T) {
		err := s.StreamedListObjects(&openfgav1.StreamedListObjectsRequest{
			StoreId:              store,
			AuthorizationModelId: modelID,
			Type:                 "repo",
			Relation:             "viewer",
			User:                 "user:bob",
		}, NewMockStreamServer())

		require.ErrorIs(t, err, serverErrors.AuthorizationModelResolutionTooComplex)
	})
}


func TestListObjects_Unoptimized_UnhappyPaths(t *testing.T) {
	ctx := context.Background()
	store := ulid.Make().String()
	modelID := ulid.Make().String()

	mockController := gomock.NewController(t)
	defer mockController.Finish()

	mockDatastore := mockstorage.NewMockOpenFGADatastore(mockController)

	mockDatastore.EXPECT().ReadAuthorizationModel(gomock.Any(), store, modelID).AnyTimes().Return(&openfgav1.AuthorizationModel{
		SchemaVersion: typesystem.SchemaVersion1_1,
		TypeDefinitions: parser.MustParse(`
		type user

		type repo
		  relations
		    define allowed: [user] as self
		    define viewer: [user] as self and allowed
		`),
	}, nil)
	mockDatastore.EXPECT().ReadStartingWithUser(gomock.Any(), store, gomock.Any()).AnyTimes().Return(nil, errors.New("error reading from storage"))

	s := MustNewServerWithOpts(
		WithDatastore(mockDatastore),
	)

	t.Run("error_listing_objects_from_storage_in_non-streaming_version", func(t *testing.T) {
		res, err := s.ListObjects(ctx, &openfgav1.ListObjectsRequest{
			StoreId:              store,
			AuthorizationModelId: modelID,
			Type:                 "repo",
			Relation:             "viewer",
			User:                 "user:bob",
		})

		require.Nil(t, res)
		require.ErrorIs(t, err, serverErrors.NewInternalError("", errors.New("error reading from storage")))
	})

	t.Run("error_listing_objects_from_storage_in_streaming_version", func(t *testing.T) {
		err := s.StreamedListObjects(&openfgav1.StreamedListObjectsRequest{
			StoreId:              store,
			AuthorizationModelId: modelID,
			Type:                 "repo",
			Relation:             "viewer",
			User:                 "user:bob",
		}, NewMockStreamServer())

		require.ErrorIs(t, err, serverErrors.NewInternalError("", errors.New("error reading from storage")))
	})
}


func PostSambaConnectionsCreate(c *gin.Context) {
	connection := model.Connections{}
	c.ShouldBindJSON(&connection)
	if connection.Port == "" {
		connection.Port = "445"
	}
	if connection.Username == "" || connection.Host == "" {
		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CHARACTER_LIMIT, Message: common_err.GetMsg(common_err.CHARACTER_LIMIT)})
		return
	}

	if ok, _ := regexp.MatchString(`^[\w@#*.]{4,30}$`, connection.Password); !ok {
		c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CHARACTER_LIMIT, Message: common_err.GetMsg(common_err.CHARACTER_LIMIT)})
		return
	}


func (s *connectionsStruct) MountSmaba(username, host, directory, port, mountPoint, password string) string {
	str := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;MountCIFS " + username + " " + host + " " + directory + " " + port + " " + mountPoint + " " + password)
	return str
}


		Skipper: func(c echo.Context) bool {
			return c.RealIP() == "::1" || c.RealIP() == "127.0.0.1"
			// return true
		},
		ParseTokenFunc: func(token string, c echo.Context) (interface{}, error) {
			claims, code := jwt.Validate(token) // TODO - needs JWT validation
			if code != common_err.SUCCESS {
				return nil, echo.ErrUnauthorized
			}

			c.Request().Header.Set("user_id", strconv.Itoa(claims.ID))

			return claims, nil
		},
		TokenLookupFuncs: []echo_middleware.ValuesExtractor{
			func(c echo.Context) ([]string, error) {
				return []string{c.Request().Header.Get(echo.HeaderAuthorization)}, nil
			},
		},
	}))

When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.


func (r *Reader) readBytes(op string) []byte {
	size := int(r.ReadLong())
	if size < 0 {
		r.ReportError("ReadString", "invalid "+op+" length")
		return nil
	}
	if size == 0 {
		return []byte{}
	}

	// The bytes are entirely in the buffer and of a reasonable size.
	// Use the byte slab.
	if r.head+size <= r.tail && size <= 1024 {
		if cap(r.slab) < size {
			r.slab = make([]byte, 1024)
		}
		dst := r.slab[:size]
		r.slab = r.slab[size:]
		copy(dst, r.buf[r.head:r.head+size])
		r.head += size
		return dst
	}

	buf := make([]byte, size)
	r.Read(buf)
	return buf
}

The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.


func OperateFirewallPort(oldPorts, newPorts []int) error {
	client, err := firewall.NewFirewallClient()
	if err != nil {
		return err
	}
	for _, port := range newPorts {

		if err := client.Port(fireClient.FireInfo{Port: strconv.Itoa(port), Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
			return err
		}
	}
	for _, port := range oldPorts {
		if err := client.Port(fireClient.FireInfo{Port: strconv.Itoa(port), Protocol: "tcp", Strategy: "accept"}, "remove"); err != nil {
			return err
		}
	}
	return client.Reload()
}

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.


func useAPIAuthentication(next fasthttp.RequestHandler) fasthttp.RequestHandler {
	token := auth.GetAPIToken()
	if token == "" {
		return next
	}
	log.Info("enabled token authentication on http server")

	return func(ctx *fasthttp.RequestCtx) {
		v := ctx.Request.Header.Peek(authConsts.APITokenHeader)
		if auth.ExcludedRoute(string(ctx.Request.URI().FullURI())) || string(v) == token {
			ctx.Request.Header.Del(authConsts.APITokenHeader)
			next(ctx)
		} else {
			ctx.Error("invalid api token", http.StatusUnauthorized)
		}
	}
}


func ExcludedRoute(route string) bool {
	for _, r := range excludedRoutes {
		if strings.Contains(route, r) {
			return true
		}
	}
	return false
}


func TestExcludedRoute(t *testing.T) {
	t.Run("healthz route is excluded", func(t *testing.T) {
		route := "v1.0/healthz"
		excluded := ExcludedRoute(route)
		assert.True(t, excluded)
	})

	t.Run("custom route is not excluded", func(t *testing.T) {
		route := "v1.0/state"
		excluded := ExcludedRoute(route)
		assert.False(t, excluded)
	})
}


func rawFileHandler(w http.ResponseWriter, r *http.Request, file *files.FileInfo) (int, error) {
	fd, err := file.Fs.Open(file.Path)
	if err != nil {
		return http.StatusInternalServerError, err
	}
	defer fd.Close()

	setContentDisposition(w, r, file)

	w.Header().Set("Cache-Control", "private")
	http.ServeContent(w, r, file.Name, file.ModTime, fd)
	return 0, nil
}

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.


func (mbp *multipartBodyProcessor) ProcessRequest(reader io.Reader, v plugintypes.TransactionVariables, options plugintypes.BodyProcessorOptions) error {
	mimeType := options.Mime
	storagePath := options.StoragePath
	mediaType, params, err := mime.ParseMediaType(mimeType)
	if err != nil {
		log.Fatalf("failed to parse media type: %s", err.Error())
	}
	if !strings.HasPrefix(mediaType, "multipart/") {
		return errors.New("not a multipart body")
	}
	mr := multipart.NewReader(reader, params["boundary"])
	totalSize := int64(0)
	filesCol := v.Files()
	filesTmpNamesCol := v.FilesTmpNames()
	fileSizesCol := v.FilesSizes()
	postCol := v.ArgsPost()
	filesCombinedSizeCol := v.FilesCombinedSize()
	filesNamesCol := v.FilesNames()
	headersNames := v.MultipartPartHeaders()
	for {
		p, err := mr.NextPart()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		partName := p.FormName()
		for key, values := range p.Header {
			for _, value := range values {
				headersNames.Add(partName, fmt.Sprintf("%s: %s", key, value))
			}
		}
		// if is a file
		filename := originFileName(p)
		if filename != "" {
			var size int64
			if environment.HasAccessToFS {
				// Only copy file to temp when not running in TinyGo
				temp, err := os.CreateTemp(storagePath, "crzmp*")
				if err != nil {
					return err
				}
				sz, err := io.Copy(temp, p)
				if err != nil {
					return err
				}
				size = sz
				filesTmpNamesCol.Add("", temp.Name())
			} else {
				sz, err := io.Copy(io.Discard, p)
				if err != nil {
					return err
				}
				size = sz
			}
			totalSize += size
			filesCol.Add("", filename)
			fileSizesCol.SetIndex(filename, 0, fmt.Sprintf("%d", size))
			filesNamesCol.Add("", p.FormName())
		} else {
			// if is a field
			data, err := io.ReadAll(p)
			if err != nil {
				return err
			}
			totalSize += int64(len(data))
			postCol.Add(p.FormName(), string(data))
		}
		filesCombinedSizeCol.(*collections.Single).Set(fmt.Sprintf("%d", totalSize))
	}
	return nil
}


func getTokenFromStorage(c *fiber.Ctx, token string, cfg Config, sessionManager *sessionManager, storageManager *storageManager) []byte {
	if cfg.Session != nil {
		return sessionManager.getRaw(c, token, dummyValue)
	}
	return storageManager.getRaw(token)
}


The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.


Reliance on Cookies without Validation and Integrity Checking

The product relies on the existence or values of cookies when performing security-critical operations, but it does not properly ensure that the setting is valid for the associated user.


Reliance on Untrusted Inputs in a Security Decision

The product uses a protection mechanism that relies on the existence or values of an input, but the input can be modified by an untrusted actor in a way that bypasses the protection mechanism.


func CsrfFromCookie(param string) func(c *fiber.Ctx) (string, error) {
	return func(c *fiber.Ctx) (string, error) {
		token := c.Cookies(param)
		if token == "" {
			return "", errMissingCookie
		}
		return token, nil
	}
}


func CsrfFromHeader(param string) func(c *fiber.Ctx) (string, error) {
	return func(c *fiber.Ctx) (string, error) {
		token := c.Get(param)
		if token == "" {
			return "", errMissingHeader
		}
		return token, nil
	}
}


func CsrfFromParam(param string) func(c *fiber.Ctx) (string, error) {
	return func(c *fiber.Ctx) (string, error) {
		token := c.Params(param)
		if token == "" {
			return "", errMissingParam
		}
		return token, nil
	}
}


func CsrfFromQuery(param string) func(c *fiber.Ctx) (string, error) {
	return func(c *fiber.Ctx) (string, error) {
		token := c.Query(param)
		if token == "" {
			return "", errMissingQuery
		}
		return token, nil
	}
}


func CsrfFromForm(param string) func(c *fiber.Ctx) (string, error) {
	return func(c *fiber.Ctx) (string, error) {
		token := c.FormValue(param)
		if token == "" {
			return "", errMissingForm
		}
		return token, nil
	}
}


func NewSortParameter(sort admin.Sort) (SortParameter, error) {
	var gormOrderExpression string
	switch sort.Direction {
	case admin.Sort_DESCENDING:
		gormOrderExpression = fmt.Sprintf(gormDescending, sort.Key)
	case admin.Sort_ASCENDING:
		gormOrderExpression = fmt.Sprintf(gormAscending, sort.Key)
	default:
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument, "invalid sort order specified: %v", sort)
	}
	return &sortParamImpl{
		gormOrderExpression: gormOrderExpression,
	}, nil
}

Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component.


func TestSortParameter_Descending(t *testing.T) {
	sortParameter, err := NewSortParameter(admin.Sort{
		Direction: admin.Sort_DESCENDING,
		Key:       "project",
	})
	assert.Nil(t, err)
	assert.Equal(t, "project desc", sortParameter.GetGormOrderExpr())
}


func TestSortParameter_Ascending(t *testing.T) {
	sortParameter, err := NewSortParameter(admin.Sort{
		Direction: admin.Sort_ASCENDING,
		Key:       "name",
	})
	assert.Nil(t, err)
	assert.Equal(t, "name asc", sortParameter.GetGormOrderExpr())
}


func (m *LaunchPlanManager) ListLaunchPlans(ctx context.Context, request admin.ResourceListRequest) (
	*admin.LaunchPlanList, error) {

	// Check required fields
	if err := validation.ValidateResourceListRequest(request); err != nil {
		logger.Debugf(ctx, "")
		return nil, err
	}
	ctx = m.getNamedEntityContext(ctx, request.Id)

	filters, err := util.GetDbFilters(util.FilterSpec{
		Project:        request.Id.Project,
		Domain:         request.Id.Domain,
		Name:           request.Id.Name,
		RequestFilters: request.Filters,
	}, common.LaunchPlan)
	if err != nil {
		return nil, err
	}

	var sortParameter common.SortParameter
	if request.SortBy != nil {
		sortParameter, err = common.NewSortParameter(*request.SortBy)
		if err != nil {
			return nil, err
		}
	}
	offset, err := validation.ValidateToken(request.Token)
	if err != nil {
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument,
			"invalid pagination token %s for ListLaunchPlans", request.Token)
	}
	listLaunchPlansInput := repoInterfaces.ListResourceInput{
		Limit:         int(request.Limit),
		Offset:        offset,
		InlineFilters: filters,
		SortParameter: sortParameter,
	}

	output, err := m.db.LaunchPlanRepo().List(ctx, listLaunchPlansInput)
	if err != nil {
		logger.Debugf(ctx, "Failed to list launch plans for request [%+v] with err %v", request, err)
		return nil, err
	}
	launchPlanList, err := transformers.FromLaunchPlanModels(output.LaunchPlans)
	if err != nil {
		logger.Errorf(ctx,
			"Failed to transform launch plan models [%+v] with err: %v", output.LaunchPlans, err)
		return nil, err
	}
	var token string
	if len(output.LaunchPlans) == int(request.Limit) {
		token = strconv.Itoa(offset + len(output.LaunchPlans))
	}
	return &admin.LaunchPlanList{
		LaunchPlans: launchPlanList,
		Token:       token,
	}, nil
}


func (m *LaunchPlanManager) ListLaunchPlanIds(ctx context.Context, request admin.NamedEntityIdentifierListRequest) (
	*admin.NamedEntityIdentifierList, error) {
	ctx = contextutils.WithProjectDomain(ctx, request.Project, request.Domain)
	filters, err := util.GetDbFilters(util.FilterSpec{
		Project: request.Project,
		Domain:  request.Domain,
	}, common.LaunchPlan)
	if err != nil {
		return nil, err
	}
	var sortParameter common.SortParameter
	if request.SortBy != nil {
		sortParameter, err = common.NewSortParameter(*request.SortBy)
		if err != nil {
			return nil, err
		}
	}
	offset, err := validation.ValidateToken(request.Token)
	if err != nil {
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument, "invalid pagination token %s", request.Token)
	}
	listLaunchPlansInput := repoInterfaces.ListResourceInput{
		Limit:         int(request.Limit),
		Offset:        offset,
		InlineFilters: filters,
		SortParameter: sortParameter,
	}

	output, err := m.db.LaunchPlanRepo().ListLaunchPlanIdentifiers(ctx, listLaunchPlansInput)

	if err != nil {
		logger.Debugf(ctx, "Failed to list launch plan ids for request [%+v] with err %v", request, err)
		return nil, err
	}
	var token string
	if len(output.LaunchPlans) == int(request.Limit) {
		token = strconv.Itoa(offset + len(output.LaunchPlans))
	}
	return &admin.NamedEntityIdentifierList{
		Entities: transformers.FromLaunchPlanModelsToIdentifiers(output.LaunchPlans),
		Token:    token,
	}, nil
}


func (m *LaunchPlanManager) ListActiveLaunchPlans(ctx context.Context, request admin.ActiveLaunchPlanListRequest) (
	*admin.LaunchPlanList, error) {

	// Check required fields
	if err := validation.ValidateActiveLaunchPlanListRequest(request); err != nil {
		logger.Debugf(ctx, "")
		return nil, err
	}
	ctx = contextutils.WithProjectDomain(ctx, request.Project, request.Domain)

	filters, err := util.ListActiveLaunchPlanVersionsFilters(request.Project, request.Domain)
	if err != nil {
		return nil, err
	}

	var sortParameter common.SortParameter
	if request.SortBy != nil {
		sortParameter, err = common.NewSortParameter(*request.SortBy)
		if err != nil {
			return nil, err
		}
	}
	offset, err := validation.ValidateToken(request.Token)
	if err != nil {
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument,
			"invalid pagination token %s for ListActiveLaunchPlans", request.Token)
	}
	listLaunchPlansInput := repoInterfaces.ListResourceInput{
		Limit:         int(request.Limit),
		Offset:        offset,
		InlineFilters: filters,
		SortParameter: sortParameter,
	}

	output, err := m.db.LaunchPlanRepo().List(ctx, listLaunchPlansInput)
	if err != nil {
		logger.Debugf(ctx, "Failed to list active launch plans for request [%+v] with err %v", request, err)
		return nil, err
	}
	launchPlanList, err := transformers.FromLaunchPlanModels(output.LaunchPlans)
	if err != nil {
		logger.Errorf(ctx,
			"Failed to transform active launch plan models [%+v] with err: %v", output.LaunchPlans, err)
		return nil, err
	}
	var token string
	if len(output.LaunchPlans) == int(request.Limit) {
		token = strconv.Itoa(offset + len(output.LaunchPlans))
	}
	return &admin.LaunchPlanList{
		LaunchPlans: launchPlanList,
		Token:       token,
	}, nil
}


func (m *NodeExecutionManager) listNodeExecutions(
	ctx context.Context, identifierFilters []common.InlineFilter,
	requestFilters string, limit uint32, requestToken string, sortBy *admin.Sort, mapFilters []common.MapFilter) (
	*admin.NodeExecutionList, error) {

	filters, err := util.AddRequestFilters(requestFilters, common.NodeExecution, identifierFilters)
	if err != nil {
		return nil, err
	}
	var sortParameter common.SortParameter
	if sortBy != nil {
		sortParameter, err = common.NewSortParameter(*sortBy)
		if err != nil {
			return nil, err
		}
	}
	offset, err := validation.ValidateToken(requestToken)
	if err != nil {
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument,
			"invalid pagination token %s for ListNodeExecutions", requestToken)
	}
	listInput := repoInterfaces.ListResourceInput{
		Limit:         int(limit),
		Offset:        offset,
		InlineFilters: filters,
		SortParameter: sortParameter,
	}

	listInput.MapFilters = mapFilters
	output, err := m.db.NodeExecutionRepo().List(ctx, listInput)
	if err != nil {
		logger.Debugf(ctx, "Failed to list node executions for request with err %v", err)
		return nil, err
	}

	var token string
	if len(output.NodeExecutions) == int(limit) {
		token = strconv.Itoa(offset + len(output.NodeExecutions))
	}
	nodeExecutionList, err := m.transformNodeExecutionModelList(ctx, output.NodeExecutions)
	if err != nil {
		logger.Debugf(ctx, "failed to transform node execution models for request with err: %v", err)
		return nil, err
	}

	return &admin.NodeExecutionList{
		NodeExecutions: nodeExecutionList,
		Token:          token,
	}, nil
}


func TestListNodeExecutions_NothingToReturn(t *testing.T) {
	repository := repositoryMocks.NewMockRepository()
	repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetListCallback(
		func(ctx context.Context, input interfaces.ListResourceInput) (
			interfaces.NodeExecutionCollectionOutput, error) {
			return interfaces.NodeExecutionCollectionOutput{}, nil
		})
	var listExecutionsCalled bool
	repository.ExecutionRepo().(*repositoryMocks.MockExecutionRepo).SetListCallback(
		func(ctx context.Context, input interfaces.ListResourceInput) (
			interfaces.ExecutionCollectionOutput, error) {
			listExecutionsCalled = true
			return interfaces.ExecutionCollectionOutput{}, nil
		})
	nodeExecManager := NewNodeExecutionManager(repository, getMockExecutionsConfigProvider(), make([]string, 0), getMockStorageForExecTest(context.Background()), mockScope.NewTestScope(), mockNodeExecutionRemoteURL, nil, nil, &eventWriterMocks.NodeExecutionEventWriter{})
	_, err := nodeExecManager.ListNodeExecutions(context.Background(), admin.NodeExecutionListRequest{
		WorkflowExecutionId: &core.WorkflowExecutionIdentifier{
			Project: "project",
			Domain:  "domain",
			Name:    "name",
		},
		Limit: 1,
		Token: "2",
		SortBy: &admin.Sort{
			Direction: admin.Sort_ASCENDING,
			Key:       "domain",
		},
	})
	assert.Nil(t, err)
	assert.False(t, listExecutionsCalled)
}


func (m *ProjectManager) ListProjects(ctx context.Context, request admin.ProjectListRequest) (*admin.Projects, error) {
	spec := util.FilterSpec{
		RequestFilters: request.Filters,
	}
	filters, err := util.GetDbFilters(spec, common.Project)
	if err != nil {
		return nil, err
	}

	var sortParameter common.SortParameter
	if request.SortBy != nil {
		sortParameter, err = common.NewSortParameter(*request.SortBy)
		if err != nil {
			return nil, err
		}
	} else {
		sortParameter = alphabeticalSortParam
	}

	offset, err := validation.ValidateToken(request.Token)
	if err != nil {
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument,
			"invalid pagination token %s for ListProjects", request.Token)
	}

	// And finally, query the database
	listProjectsInput := repoInterfaces.ListResourceInput{
		Limit:         int(request.Limit),
		Offset:        offset,
		InlineFilters: filters,
		SortParameter: sortParameter,
	}
	projectModels, err := m.db.ProjectRepo().List(ctx, listProjectsInput)
	if err != nil {
		return nil, err
	}
	projects := transformers.FromProjectModels(projectModels, m.getDomains())

	var token string
	if len(projects) == int(request.Limit) {
		token = strconv.Itoa(offset + len(projects))
	}

	return &admin.Projects{
		Projects: projects,
		Token:    token,
	}, nil
}


func (s *SignalManager) ListSignals(ctx context.Context, request admin.SignalListRequest) (*admin.SignalList, error) {
	if err := validation.ValidateSignalListRequest(ctx, request); err != nil {
		logger.Debugf(ctx, "ListSignals request [%+v] is invalid: %v", request, err)
		return nil, err
	}
	ctx = getExecutionContext(ctx, request.WorkflowExecutionId)

	identifierFilters, err := util.GetWorkflowExecutionIdentifierFilters(ctx, *request.WorkflowExecutionId)
	if err != nil {
		return nil, err
	}

	filters, err := util.AddRequestFilters(request.Filters, common.Signal, identifierFilters)
	if err != nil {
		return nil, err
	}
	var sortParameter common.SortParameter
	if request.SortBy != nil {
		sortParameter, err = common.NewSortParameter(*request.SortBy)
		if err != nil {
			return nil, err
		}
	}

	offset, err := validation.ValidateToken(request.Token)
	if err != nil {
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument,
			"invalid pagination token %s for ListSignals", request.Token)
	}

	signalModelList, err := s.db.SignalRepo().List(ctx, repoInterfaces.ListResourceInput{
		InlineFilters: filters,
		Offset:        offset,
		Limit:         int(request.Limit),
		SortParameter: sortParameter,
	})
	if err != nil {
		logger.Debugf(ctx, "Failed to list signals with request [%+v] with err %v",
			request, err)
		return nil, err
	}

	signalList, err := transformers.FromSignalModels(signalModelList)
	if err != nil {
		logger.Debugf(ctx, "failed to transform signal models for request [%+v] with err: %v", request, err)
		return nil, err
	}
	var token string
	if len(signalList) == int(request.Limit) {
		token = strconv.Itoa(offset + len(signalList))
	}
	return &admin.SignalList{
		Signals: signalList,
		Token:   token,
	}, nil
}


func (t *TaskManager) ListTasks(ctx context.Context, request admin.ResourceListRequest) (*admin.TaskList, error) {
	// Check required fields
	if err := validation.ValidateResourceListRequest(request); err != nil {
		logger.Debugf(ctx, "Invalid request [%+v]: %v", request, err)
		return nil, err
	}
	ctx = contextutils.WithProjectDomain(ctx, request.Id.Project, request.Id.Domain)
	ctx = contextutils.WithTaskID(ctx, request.Id.Name)
	spec := util.FilterSpec{
		Project:        request.Id.Project,
		Domain:         request.Id.Domain,
		Name:           request.Id.Name,
		RequestFilters: request.Filters,
	}

	filters, err := util.GetDbFilters(spec, common.Task)
	if err != nil {
		return nil, err
	}
	var sortParameter common.SortParameter
	if request.SortBy != nil {
		sortParameter, err = common.NewSortParameter(*request.SortBy)
		if err != nil {
			return nil, err
		}
	}
	offset, err := validation.ValidateToken(request.Token)
	if err != nil {
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument,
			"invalid pagination token %s for ListTasks", request.Token)
	}
	// And finally, query the database
	listTasksInput := repoInterfaces.ListResourceInput{
		Limit:         int(request.Limit),
		Offset:        offset,
		InlineFilters: filters,
		SortParameter: sortParameter,
	}
	output, err := t.db.TaskRepo().List(ctx, listTasksInput)
	if err != nil {
		logger.Debugf(ctx, "Failed to list tasks with id [%+v] with err %v", request.Id, err)
		return nil, err
	}
	taskList, err := transformers.FromTaskModels(output.Tasks)
	if err != nil {
		logger.Errorf(ctx,
			"Failed to transform task models [%+v] with err: %v", output.Tasks, err)
		return nil, err
	}

	var token string
	if len(taskList) == int(request.Limit) {
		token = strconv.Itoa(offset + len(taskList))
	}
	return &admin.TaskList{
		Tasks: taskList,
		Token: token,
	}, nil
}


func (t *TaskManager) ListUniqueTaskIdentifiers(ctx context.Context, request admin.NamedEntityIdentifierListRequest) (
	*admin.NamedEntityIdentifierList, error) {
	if err := validation.ValidateNamedEntityIdentifierListRequest(request); err != nil {
		logger.Debugf(ctx, "invalid request [%+v]: %v", request, err)
		return nil, err
	}
	ctx = contextutils.WithProjectDomain(ctx, request.Project, request.Domain)
	filters, err := util.GetDbFilters(util.FilterSpec{
		Project: request.Project,
		Domain:  request.Domain,
	}, common.Task)
	if err != nil {
		return nil, err
	}
	var sortParameter common.SortParameter
	if request.SortBy != nil {
		sortParameter, err = common.NewSortParameter(*request.SortBy)
		if err != nil {
			return nil, err
		}
	}
	offset, err := validation.ValidateToken(request.Token)
	if err != nil {
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument,
			"invalid pagination token %s for ListUniqueTaskIdentifiers", request.Token)
	}
	listTasksInput := repoInterfaces.ListResourceInput{
		Limit:         int(request.Limit),
		Offset:        offset,
		InlineFilters: filters,
		SortParameter: sortParameter,
	}

	output, err := t.db.TaskRepo().ListTaskIdentifiers(ctx, listTasksInput)
	if err != nil {
		logger.Debugf(ctx, "Failed to list tasks ids with project: %s and domain: %s with err %v",
			request.Project, request.Domain, err)
		return nil, err
	}

	idList := transformers.FromTaskModelsToIdentifiers(output.Tasks)
	var token string
	if len(idList) == int(request.Limit) {
		token = strconv.Itoa(offset + len(idList))
	}
	return &admin.NamedEntityIdentifierList{
		Entities: idList,
		Token:    token,
	}, nil
}


func TestParseFilters(t *testing.T) {
	filterExpression := "eq(foo, 123)+ne(version, TheWorst)+value_in(bar, 4;5;6)"
	taskFilters, err := ParseFilters(filterExpression, common.Task)
	assert.NoError(t, err)

	assert.Len(t, taskFilters, 3)
	actualFilterExpression, _ := taskFilters[0].GetGormQueryExpr()
	assert.Equal(t, "foo = ?", actualFilterExpression.Query)
	assert.Equal(t, "123", actualFilterExpression.Args)

	actualFilterExpression, _ = taskFilters[1].GetGormQueryExpr()
	assert.Equal(t, "version <> ?", actualFilterExpression.Query)
	assert.Equal(t, "TheWorst", actualFilterExpression.Args)

	actualFilterExpression, _ = taskFilters[2].GetGormQueryExpr()
	assert.Equal(t, "bar in (?)", actualFilterExpression.Query)
	assert.Equal(t, []interface{}{"4", "5", "6"}, actualFilterExpression.Args)

	filterExpression = "invalid_function(foo,bar)"
	_, err = ParseFilters(filterExpression, common.Task)
	assert.Error(t, err)
	assert.EqualError(t, err, "unrecognized filter function: invalid_function")
}


func TestAddRequestFilters(t *testing.T) {
	filters, err := AddRequestFilters(
		"ne(version, TheWorst)+eq(workflow.name, workflow)", common.Execution, make([]common.InlineFilter, 0))
	assert.Nil(t, err)
	assert.Len(t, filters, 2)
	expression, err := filters[0].GetGormQueryExpr()
	assert.Nil(t, err)
	assert.Equal(t, "version <> ?", expression.Query)
	assert.Equal(t, "TheWorst", expression.Args)

	expression, err = filters[1].GetGormQueryExpr()
	assert.Nil(t, err)
	assert.Equal(t, testutils.NameQueryPattern, expression.Query)
	assert.Equal(t, "workflow", expression.Args)
}


func (w *WorkflowManager) ListWorkflows(
	ctx context.Context, request admin.ResourceListRequest) (*admin.WorkflowList, error) {
	// Check required fields
	if err := validation.ValidateResourceListRequest(request); err != nil {
		return nil, err
	}
	ctx = contextutils.WithProjectDomain(ctx, request.Id.Project, request.Id.Domain)
	ctx = contextutils.WithWorkflowID(ctx, request.Id.Name)
	filters, err := util.GetDbFilters(util.FilterSpec{
		Project:        request.Id.Project,
		Domain:         request.Id.Domain,
		Name:           request.Id.Name,
		RequestFilters: request.Filters,
	}, common.Workflow)
	if err != nil {
		return nil, err
	}
	var sortParameter common.SortParameter
	if request.SortBy != nil {
		sortParameter, err = common.NewSortParameter(*request.SortBy)
		if err != nil {
			return nil, err
		}
	}
	offset, err := validation.ValidateToken(request.Token)
	if err != nil {
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument,
			"invalid pagination token %s for ListWorkflows", request.Token)
	}
	listWorkflowsInput := repoInterfaces.ListResourceInput{
		Limit:         int(request.Limit),
		Offset:        offset,
		InlineFilters: filters,
		SortParameter: sortParameter,
	}
	output, err := w.db.WorkflowRepo().List(ctx, listWorkflowsInput)
	if err != nil {
		logger.Debugf(ctx, "Failed to list workflows with [%+v] with err %v", request.Id, err)
		return nil, err
	}
	workflowList, err := transformers.FromWorkflowModels(output.Workflows)
	if err != nil {
		logger.Errorf(ctx,
			"Failed to transform workflow models [%+v] with err: %v", output.Workflows, err)
		return nil, err
	}
	var token string
	if len(output.Workflows) == int(request.Limit) {
		token = strconv.Itoa(offset + len(output.Workflows))
	}
	return &admin.WorkflowList{
		Workflows: workflowList,
		Token:     token,
	}, nil
}


func (w *WorkflowManager) ListWorkflowIdentifiers(ctx context.Context, request admin.NamedEntityIdentifierListRequest) (
	*admin.NamedEntityIdentifierList, error) {
	if err := validation.ValidateNamedEntityIdentifierListRequest(request); err != nil {
		logger.Debugf(ctx, "invalid request [%+v]: %v", request, err)
		return nil, err
	}
	ctx = contextutils.WithProjectDomain(ctx, request.Project, request.Domain)

	filters, err := util.GetDbFilters(util.FilterSpec{
		Project: request.Project,
		Domain:  request.Domain,
	}, common.Workflow)
	if err != nil {
		return nil, err
	}
	var sortParameter common.SortParameter
	if request.SortBy != nil {
		sortParameter, err = common.NewSortParameter(*request.SortBy)
		if err != nil {
			return nil, err
		}
	}
	offset, err := validation.ValidateToken(request.Token)
	if err != nil {
		return nil, errors.NewFlyteAdminErrorf(codes.InvalidArgument,
			"invalid pagination token %s for ListWorkflowIdentifiers", request.Token)
	}
	listWorkflowsInput := repoInterfaces.ListResourceInput{
		Limit:         int(request.Limit),
		Offset:        offset,
		InlineFilters: filters,
		SortParameter: sortParameter,
	}

	output, err := w.db.WorkflowRepo().ListIdentifiers(ctx, listWorkflowsInput)
	if err != nil {
		logger.Debugf(ctx, "Failed to list workflow ids with project: %s and domain: %s with err %v",
			request.Project, request.Domain, err)
		return nil, err
	}

	var token string
	if len(output.Workflows) == int(request.Limit) {
		token = strconv.Itoa(offset + len(output.Workflows))
	}
	entities := transformers.FromWorkflowModelsToIdentifiers(output.Workflows)
	return &admin.NamedEntityIdentifierList{
		Entities: entities,
		Token:    token,
	}, nil

}


func TestListExecutions_Order(t *testing.T) {
	executionRepo := NewExecutionRepo(GetDbForTest(t), errors.NewTestErrorTransformer(), mockScope.NewTestScope())

	executions := make([]map[string]interface{}, 0)
	GlobalMock := mocket.Catcher.Reset()
	// Only match on queries that include ordering by name
	mockQuery := GlobalMock.NewMock().WithQuery(`name asc`)
	mockQuery.WithReply(executions)

	sortParameter, _ := common.NewSortParameter(admin.Sort{
		Direction: admin.Sort_ASCENDING,
		Key:       "name",
	})
	_, err := executionRepo.List(context.Background(), interfaces.ListResourceInput{
		SortParameter: sortParameter,
		InlineFilters: []common.InlineFilter{
			getEqualityFilter(common.Task, "project", project),
			getEqualityFilter(common.Task, "domain", domain),
			getEqualityFilter(common.Task, "name", name),
		},
		Limit: 20,
	})
	assert.NoError(t, err)
	assert.True(t, mockQuery.Triggered)
}


func TestListExecutions_WithTags(t *testing.T) {
	executionRepo := NewExecutionRepo(GetDbForTest(t), errors.NewTestErrorTransformer(), mockScope.NewTestScope())

	executions := make([]map[string]interface{}, 0)
	GlobalMock := mocket.Catcher.Reset()
	// Only match on queries that include ordering by name
	mockQuery := GlobalMock.NewMock().WithQuery(`name asc`)
	mockQuery.WithReply(executions)

	sortParameter, _ := common.NewSortParameter(admin.Sort{
		Direction: admin.Sort_ASCENDING,
		Key:       "name",
	})
	vals := []string{"tag1", "tag2"}
	tagFilter, err := common.NewRepeatedValueFilter(common.ExecutionAdminTag, common.ValueIn, "admin_tag_name", vals)
	assert.NoError(t, err)
	_, err = executionRepo.List(context.Background(), interfaces.ListResourceInput{
		SortParameter: sortParameter,
		InlineFilters: []common.InlineFilter{
			getEqualityFilter(common.Task, "project", project),
			getEqualityFilter(common.Task, "domain", domain),
			getEqualityFilter(common.Task, "name", name),
			tagFilter,
		},
		Limit: 20,
	})
	assert.NoError(t, err)
	assert.True(t, mockQuery.Triggered)
}


func TestListLaunchPlans_Order(t *testing.T) {
	launchPlanRepo := NewLaunchPlanRepo(GetDbForTest(t), errors.NewTestErrorTransformer(), mockScope.NewTestScope())
	launchPlans := make([]map[string]interface{}, 0)

	GlobalMock := mocket.Catcher.Reset()
	// Only match on queries that include ordering by project
	mockQuery := GlobalMock.NewMock()
	mockQuery.WithQuery(`project desc`)
	mockQuery.WithReply(launchPlans)

	sortParameter, _ := common.NewSortParameter(admin.Sort{
		Direction: admin.Sort_DESCENDING,
		Key:       "project",
	})
	_, err := launchPlanRepo.List(context.Background(), interfaces.ListResourceInput{
		SortParameter: sortParameter,
		InlineFilters: []common.InlineFilter{
			getEqualityFilter(common.LaunchPlan, "project", project),
			getEqualityFilter(common.LaunchPlan, "domain", domain),
			getEqualityFilter(common.LaunchPlan, "name", name),
			getEqualityFilter(common.LaunchPlan, "version", version),
		},
		Limit: 20,
	})
	assert.NoError(t, err)
	assert.True(t, mockQuery.Triggered)
}


func TestListNamedEntity(t *testing.T) {
	metadataRepo := NewNamedEntityRepo(GetDbForTest(t), errors.NewTestErrorTransformer(), mockScope.NewTestScope())

	results := make([]map[string]interface{}, 0)
	metadata := getMockNamedEntityResponseFromDb(models.NamedEntity{
		NamedEntityKey: models.NamedEntityKey{
			ResourceType: resourceType,
			Project:      project,
			Domain:       domain,
			Name:         name,
		},
		NamedEntityMetadataFields: models.NamedEntityMetadataFields{
			Description: description,
		},
	})
	results = append(results, metadata)

	GlobalMock := mocket.Catcher.Reset()
	GlobalMock.Logging = true
	mockQuery := GlobalMock.NewMock()

	mockQuery.WithQuery(
		`SELECT entities.project,entities.domain,entities.name,'2' AS resource_type,named_entity_metadata.description,named_entity_metadata.state FROM "named_entity_metadata" RIGHT JOIN (SELECT project,domain,name FROM "workflows" WHERE "domain" = $1 AND "project" = $2 GROUP BY project, domain, name ORDER BY name desc LIMIT 20) AS entities ON named_entity_metadata.resource_type = 2 AND named_entity_metadata.project = entities.project AND named_entity_metadata.domain = entities.domain AND named_entity_metadata.name = entities.name GROUP BY entities.project, entities.domain, entities.name, named_entity_metadata.description, named_entity_metadata.state ORDER BY name desc`).WithReply(results)

	sortParameter, _ := common.NewSortParameter(admin.Sort{
		Direction: admin.Sort_DESCENDING,
		Key:       "name",
	})
	output, err := metadataRepo.List(context.Background(), interfaces.ListNamedEntityInput{
		ResourceType: resourceType,
		Project:      "admintests",
		Domain:       "development",
		ListResourceInput: interfaces.ListResourceInput{
			Limit:         20,
			SortParameter: sortParameter,
		},
	})
	assert.NoError(t, err)
	assert.Len(t, output.Entities, 1)
}


func TestListNodeExecutions_Order(t *testing.T) {
	nodeExecutionRepo := NewNodeExecutionRepo(GetDbForTest(t), errors.NewTestErrorTransformer(), mockScope.NewTestScope())
	nodeExecutions := make([]map[string]interface{}, 0)

	GlobalMock := mocket.Catcher.Reset()
	// Only match on queries that include ordering by project
	mockQuery := GlobalMock.NewMock()
	mockQuery.WithQuery(`project desc`)
	mockQuery.WithReply(nodeExecutions)

	sortParameter, _ := common.NewSortParameter(admin.Sort{
		Direction: admin.Sort_DESCENDING,
		Key:       "project",
	})
	_, err := nodeExecutionRepo.List(context.Background(), interfaces.ListResourceInput{
		SortParameter: sortParameter,
		InlineFilters: []common.InlineFilter{
			getEqualityFilter(common.NodeExecution, "phase", nodePhase),
		},
		Limit: 20,
	})
	assert.NoError(t, err)
	assert.True(t, mockQuery.Triggered)
}


func TestListProjects(t *testing.T) {
	filter, err := common.NewSingleValueFilter(common.Project, common.Equal, "name", "foo")
	assert.Nil(t, err)
	testListProjects(interfaces.ListResourceInput{
		Offset:        0,
		Limit:         1,
		InlineFilters: []common.InlineFilter{filter},
		SortParameter: alphabeticalSortParam,
	}, `SELECT * FROM "projects" WHERE name = $1 ORDER BY identifier asc LIMIT 1`, t)
}


func TestListTasks_Order(t *testing.T) {
	taskRepo := NewTaskRepo(GetDbForTest(t), errors.NewTestErrorTransformer(), mockScope.NewTestScope())
	tasks := make([]map[string]interface{}, 0)

	GlobalMock := mocket.Catcher.Reset()
	GlobalMock.Logging = true
	// Only match on queries that include ordering by project
	mockQuery := GlobalMock.NewMock()
	mockQuery.WithQuery(`project desc`)
	mockQuery.WithReply(tasks)

	sortParameter, _ := common.NewSortParameter(admin.Sort{
		Direction: admin.Sort_DESCENDING,
		Key:       "project",
	})
	_, err := taskRepo.List(context.Background(), interfaces.ListResourceInput{
		SortParameter: sortParameter,
		InlineFilters: []common.InlineFilter{
			getEqualityFilter(common.Task, "project", project),
			getEqualityFilter(common.Task, "domain", domain),
			getEqualityFilter(common.Task, "name", name),
			getEqualityFilter(common.Task, "version", "ABC"),
		},
		Limit: 20,
	})
	assert.Empty(t, err)
	assert.True(t, mockQuery.Triggered)
}


func TestListWorkflows_Order(t *testing.T) {
	workflowRepo := NewWorkflowRepo(GetDbForTest(t), errors.NewTestErrorTransformer(), mockScope.NewTestScope())
	workflows := make([]map[string]interface{}, 0)

	GlobalMock := mocket.Catcher.Reset()
	// Only match on queries that include ordering by project
	mockQuery := GlobalMock.NewMock()
	mockQuery.WithQuery(`project desc`)
	mockQuery.WithReply(workflows)

	sortParameter, _ := common.NewSortParameter(admin.Sort{
		Direction: admin.Sort_DESCENDING,
		Key:       "project",
	})
	_, err := workflowRepo.List(context.Background(), interfaces.ListResourceInput{
		SortParameter: sortParameter,
		InlineFilters: []common.InlineFilter{
			getEqualityFilter(common.Workflow, "project", project),
			getEqualityFilter(common.Workflow, "domain", domain),
			getEqualityFilter(common.Workflow, "name", name),
			getEqualityFilter(common.Workflow, "version", "ABC"),
		},
		Limit: 20,
	})
	assert.Empty(t, err)
	assert.True(t, mockQuery.Triggered)
}


func (v *cosignVerifier) VerifySignature(ctx context.Context, opts images.Options) (*images.Response, error) {
	ref, err := name.ParseReference(opts.ImageRef)
	if err != nil {
		return nil, fmt.Errorf("failed to parse image %s", opts.ImageRef)
	}

	signatures, bundleVerified, err := tracing.ChildSpan3(
		ctx,
		"",
		"VERIFY IMG SIGS",
		func(ctx context.Context, span trace.Span) ([]oci.Signature, bool, error) {
			cosignOpts, err := buildCosignOptions(ctx, opts)
			if err != nil {
				return nil, false, err
			}
			return client.VerifyImageSignatures(ctx, ref, cosignOpts)
		},
	)
	if err != nil {
		logger.Info("image verification failed", "error", err.Error())
		return nil, err
	}

	logger.V(3).Info("verified image", "count", len(signatures), "bundleVerified", bundleVerified)
	payload, err := extractPayload(signatures)
	if err != nil {
		return nil, err
	}

	if err := matchSignatures(signatures, opts.Subject, opts.Issuer, opts.AdditionalExtensions); err != nil {
		return nil, err
	}

	err = checkAnnotations(payload, opts.Annotations)
	if err != nil {
		return nil, err
	}

	var digest string
	if opts.PredicateType == "" {
		digest, err = extractDigest(opts.ImageRef, payload)
		if err != nil {
			return nil, err
		}
	}

	return &images.Response{Digest: digest}, nil
}


func matchPredicateType(sig oci.Signature, expectedPredicateType string) (bool, string, error) {
	if expectedPredicateType != "" {
		statement, _, err := decodeStatement(sig)
		if err != nil {
			return false, "", fmt.Errorf("failed to decode predicateType: %w", err)
		}

		if pType, ok := statement["predicateType"]; ok {
			if pType.(string) == expectedPredicateType {
				return true, pType.(string), nil
			}
		}
	}
	return false, "", nil
}


func (v *cosignVerifier) FetchAttestations(ctx context.Context, opts images.Options) (*images.Response, error) {
	cosignOpts, err := buildCosignOptions(ctx, opts)
	if err != nil {
		return nil, err
	}

	signatures, bundleVerified, err := tracing.ChildSpan3(
		ctx,
		"",
		"VERIFY IMG ATTESTATIONS",
		func(ctx context.Context, span trace.Span) (checkedAttestations []oci.Signature, bundleVerified bool, err error) {
			ref, err := name.ParseReference(opts.ImageRef)
			if err != nil {
				return nil, false, fmt.Errorf("failed to parse image: %w", err)
			}
			return client.VerifyImageAttestations(ctx, ref, cosignOpts)
		},
	)
	if err != nil {
		msg := err.Error()
		logger.Info("failed to fetch attestations", "error", msg)
		if strings.Contains(msg, "MANIFEST_UNKNOWN: manifest unknown") {
			return nil, fmt.Errorf("not found")
		}

		return nil, err
	}

	payload, err := extractPayload(signatures)
	if err != nil {
		return nil, err
	}

	for _, signature := range signatures {
		match, predicateType, err := matchPredicateType(signature, opts.PredicateType)
		if err != nil {
			return nil, err
		}

		if !match {
			logger.V(4).Info("predicateType doesn't match, continue", "expected", opts.PredicateType, "received", predicateType)
			continue
		}

		if err := matchSignatures([]oci.Signature{signature}, opts.Subject, opts.Issuer, opts.AdditionalExtensions); err != nil {
			return nil, err
		}
	}

	err = checkAnnotations(payload, opts.Annotations)
	if err != nil {
		return nil, err
	}

	logger.V(3).Info("verified images", "signatures", len(signatures), "bundleVerified", bundleVerified)
	inTotoStatements, digest, err := decodeStatements(signatures)
	if err != nil {
		return nil, err
	}

	return &images.Response{Digest: digest, Statements: inTotoStatements}, nil
}


func substituteVariables(rule kyvernov1.Rule, ctx enginecontext.EvalInterface, logger logr.Logger) (*kyvernov1.Rule, error) {
	// remove attestations as variables are not substituted in them
	ruleCopy := *rule.DeepCopy()
	for i := range ruleCopy.VerifyImages {
		ruleCopy.VerifyImages[i].Attestations = nil
	}
	var err error
	ruleCopy, err = variables.SubstituteAllInRule(logger, ctx, ruleCopy)
	if err != nil {
		return nil, err
	}
	// replace attestations
	for i := range rule.VerifyImages {
		ruleCopy.VerifyImages[i].Attestations = rule.VerifyImages[i].Attestations
	}
	return &ruleCopy, nil
}


func (iv *ImageVerifier) buildVerifier(
	attestor kyvernov1.Attestor,
	imageVerify kyvernov1.ImageVerification,
	image string,
	attestation *kyvernov1.Attestation,
) (images.ImageVerifier, *images.Options, string) {
	switch imageVerify.Type {
	case kyvernov1.NotaryV2:
		return iv.buildNotaryV2Verifier(attestor, imageVerify, image)
	default:
		return iv.buildCosignVerifier(attestor, imageVerify, image, attestation)
	}
}


func (iv *ImageVerifier) verifyAttestation(statements []map[string]interface{}, attestation kyvernov1.Attestation, imageInfo apiutils.ImageInfo) error {
	if attestation.PredicateType == "" {
		return fmt.Errorf("a predicateType is required")
	}
	image := imageInfo.String()
	statementsByPredicate, types := buildStatementMap(statements)
	iv.logger.V(4).Info("checking attestations", "predicates", types, "image", image)
	statements = statementsByPredicate[attestation.PredicateType]
	if statements == nil {
		iv.logger.Info("no attestations found for predicate", "type", attestation.PredicateType, "predicates", types, "image", imageInfo.String())
		return fmt.Errorf("attestions not found for predicate type %s", attestation.PredicateType)
	}
	for _, s := range statements {
		iv.logger.Info("checking attestation", "predicates", types, "image", imageInfo.String())
		val, msg, err := iv.checkAttestations(attestation, s)
		if err != nil {
			return fmt.Errorf("failed to check attestations: %w", err)
		}
		if !val {
			return fmt.Errorf("attestation checks failed for %s and predicate %s: %s", imageInfo.String(), attestation.PredicateType, msg)
		}
	}
	return nil
}


func (iv *ImageVerifier) buildNotaryV2Verifier(
	attestor kyvernov1.Attestor,
	imageVerify kyvernov1.ImageVerification,
	image string,
) (images.ImageVerifier, *images.Options, string) {
	path := ""
	opts := &images.Options{
		ImageRef:       image,
		Cert:           attestor.Certificates.Certificate,
		CertChain:      attestor.Certificates.CertificateChain,
		RegistryClient: iv.rclient,
	}

	return notaryv2.NewVerifier(), opts, path
}


func (p *Parser) isPrefixHeading(data []byte) bool {
	if data[0] != '#' {
		return false
	}

	if p.extensions&SpaceHeadings != 0 {
		level := skipCharN(data, 0, '#', 6)
		if level == len(data) || data[level] != ' ' {
			return false
		}
	}
	return true
}

The product reads data past the end, or before the beginning, of the intended buffer.


func (builder *builder) Cmp(i1, i2 frontend.Variable) frontend.Variable {

	vars, _ := builder.toVariables(i1, i2)
	bi1 := builder.ToBinary(vars[0], builder.cs.FieldBitLen())
	bi2 := builder.ToBinary(vars[1], builder.cs.FieldBitLen())

	res := builder.cstZero()

	for i := builder.cs.FieldBitLen() - 1; i >= 0; i-- {

		iszeroi1 := builder.IsZero(bi1[i])
		iszeroi2 := builder.IsZero(bi2[i])

		i1i2 := builder.And(bi1[i], iszeroi2)
		i2i1 := builder.And(bi2[i], iszeroi1)

		n := builder.Select(i2i1, -1, 0)
		m := builder.Select(i1i2, 1, n)

		res = builder.Select(builder.IsZero(res), m, res).(expr.LinearExpression)

	}
	return res
}

The product subtracts one value from another, such that the result is less than the minimum allowable integer value, which produces a value that is not equal to the correct result.


The product compares two entities in a security-relevant context, but the comparison is incorrect, which may lead to resultant weaknesses.


func (builder *builder) mustBeLessOrEqVar(a, bound frontend.Variable) {
	// here bound is NOT a constant,
	// but a can be either constant or a wire.

	_, aConst := builder.constantValue(a)

	debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound)

	nbBits := builder.cs.FieldBitLen()

	aBits := bits.ToBinary(builder, a, bits.WithNbDigits(nbBits), bits.WithUnconstrainedOutputs())
	boundBits := builder.ToBinary(bound, nbBits)

	// constraint added
	added := make([]int, 0, nbBits)

	p := make([]frontend.Variable, nbBits+1)
	p[nbBits] = builder.cstOne()

	zero := builder.cstZero()

	for i := nbBits - 1; i >= 0; i-- {

		// if bound[i] == 0
		// 		p[i] = p[i+1]
		//		t = p[i+1]
		// else
		// 		p[i] = p[i+1] * a[i]
		//		t = 0
		v := builder.Mul(p[i+1], aBits[i])
		p[i] = builder.Select(boundBits[i], v, p[i+1])

		t := builder.Select(boundBits[i], zero, p[i+1])

		// (1 - t - ai) * ai == 0
		var l frontend.Variable
		l = builder.cstOne()
		l = builder.Sub(l, t, aBits[i])

		// note if bound[i] == 1, this constraint is (1 - ai) * ai == 0
		// → this is a boolean constraint
		// if bound[i] == 0, t must be 0 or 1, thus ai must be 0 or 1 too

		if aConst {
			// aBits[i] is a constant;
			l = builder.Mul(l, aBits[i])
			// TODO @gbotrel this constraint seems useless.
			added = append(added, builder.cs.AddR1C(builder.newR1C(l, zero, zero), builder.genericGate))
		} else {
			added = append(added, builder.cs.AddR1C(builder.newR1C(l, aBits[i], zero), builder.genericGate))
		}
	}

	builder.cs.AttachDebugInfo(debug, added)

}


func (builder *builder) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) {
	cv, vConst := builder.constantValue(v)
	cb, bConst := builder.constantValue(bound)

	// both inputs are constants
	if vConst && bConst {
		bv, bb := builder.cs.ToBigInt(cv), builder.cs.ToBigInt(cb)
		if bv.Cmp(bb) == 1 {
			panic(fmt.Sprintf("AssertIsLessOrEqual: %s > %s", bv.String(), bb.String()))
		}
	}

	// bound is constant
	if bConst {
		vv := builder.toVariable(v)
		builder.mustBeLessOrEqCst(vv, builder.cs.ToBigInt(cb))
		return
	}

	builder.mustBeLessOrEqVar(v, bound)
}


func (builder *builder) mustBeLessOrEqCst(a expr.LinearExpression, bound *big.Int) {

	nbBits := builder.cs.FieldBitLen()

	// ensure the bound is positive, it's bit-len doesn't matter
	if bound.Sign() == -1 {
		panic("AssertIsLessOrEqual: bound must be positive")
	}
	if bound.BitLen() > nbBits {
		panic("AssertIsLessOrEqual: bound is too large, constraint will never be satisfied")
	}

	// debug info
	debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", builder.toVariable(bound))

	// note that at this stage, we didn't boolean-constraint these new variables yet
	// (as opposed to ToBinary)
	aBits := bits.ToBinary(builder, a, bits.WithNbDigits(nbBits), bits.WithUnconstrainedOutputs())

	// t trailing bits in the bound
	t := 0
	for i := 0; i < nbBits; i++ {
		if bound.Bit(i) == 0 {
			break
		}
		t++
	}

	// constraint added
	added := make([]int, 0, nbBits)

	p := make([]frontend.Variable, nbBits+1)
	// p[i] == 1 → a[j] == c[j] for all j ⩾ i
	p[nbBits] = builder.cstOne()

	for i := nbBits - 1; i >= t; i-- {
		if bound.Bit(i) == 0 {
			p[i] = p[i+1]
		} else {
			p[i] = builder.Mul(p[i+1], aBits[i])
		}
	}

	for i := nbBits - 1; i >= 0; i-- {
		if bound.Bit(i) == 0 {
			// (1 - p(i+1) - ai) * ai == 0
			l := builder.Sub(1, p[i+1])
			l = builder.Sub(l, aBits[i])

			added = append(added, builder.cs.AddR1C(builder.newR1C(l, aBits[i], builder.cstZero()), builder.genericGate))
		} else {
			builder.AssertIsBoolean(aBits[i])
		}
	}

	if len(added) != 0 {
		builder.cs.AttachDebugInfo(debug, added)
	}
}