First Commit
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
detections / detections (push) Canceled after 0s
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
detections / detections (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// TaskInterceptRuleInput is one task-level rule supplied at task creation.
|
||||
// Action: 'block'=拦截 'allow'=允许(白名单);空视为 'block'。
|
||||
type TaskInterceptRuleInput struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Action string `json:"action"`
|
||||
Kind string `json:"kind"`
|
||||
Pattern string `json:"pattern"`
|
||||
Note string `json:"note"`
|
||||
}
|
||||
|
||||
const taskInterceptRuleCols = `id, enabled, action, kind, pattern, note, created_at, updated_at`
|
||||
|
||||
func scanTaskInterceptRule(row interface{ Scan(...any) error }) (AssetInterceptRule, error) {
|
||||
var r AssetInterceptRule
|
||||
err := row.Scan(&r.ID, &r.Enabled, &r.Action, &r.Kind, &r.Pattern, &r.Note, &r.CreatedAt, &r.UpdatedAt)
|
||||
return r, err
|
||||
}
|
||||
|
||||
// ListTaskInterceptRules returns a task's rules (both block and allow) as
|
||||
// AssetInterceptRule (Builtin always false; Action carries block/allow). taskID
|
||||
// <= 0 returns nothing.
|
||||
func (s *AssetStore) ListTaskInterceptRules(taskID int64) ([]AssetInterceptRule, error) {
|
||||
if taskID <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
rows, err := s.db.Query(`SELECT `+taskInterceptRuleCols+` FROM task_intercept_rules WHERE task_id=$1 ORDER BY action, id`, taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []AssetInterceptRule
|
||||
for rows.Next() {
|
||||
r, err := scanTaskInterceptRule(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, r)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// TaskInterceptRulesSplit loads a task's rules and splits them into block and
|
||||
// allow sets, for the enforcement gate.
|
||||
func (s *AssetStore) TaskInterceptRulesSplit(taskID int64) (block, allow []AssetInterceptRule, err error) {
|
||||
rules, err := s.ListTaskInterceptRules(taskID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, r := range rules {
|
||||
if r.Action == "allow" {
|
||||
allow = append(allow, r)
|
||||
} else {
|
||||
block = append(block, r)
|
||||
}
|
||||
}
|
||||
return block, allow, nil
|
||||
}
|
||||
|
||||
func normalizeRuleAction(action string) string {
|
||||
if action == "allow" {
|
||||
return "allow"
|
||||
}
|
||||
return "block"
|
||||
}
|
||||
|
||||
// CreateTaskInterceptRule inserts a rule under a task.
|
||||
func (s *AssetStore) CreateTaskInterceptRule(taskID int64, action, kind, pattern, note string, enabled bool) (AssetInterceptRule, error) {
|
||||
row := s.db.QueryRow(`
|
||||
INSERT INTO task_intercept_rules(task_id, enabled, action, kind, pattern, note)
|
||||
VALUES ($1,$2,$3,$4,$5,$6)
|
||||
RETURNING `+taskInterceptRuleCols,
|
||||
taskID, enabled, normalizeRuleAction(action), kind, pattern, note)
|
||||
return scanTaskInterceptRule(row)
|
||||
}
|
||||
|
||||
// UpdateTaskInterceptRule replaces the editable fields of a task's rule (scoped
|
||||
// by task_id so a rule can only be edited through its owning task).
|
||||
func (s *AssetStore) UpdateTaskInterceptRule(taskID, ruleID int64, action, kind, pattern, note string, enabled bool) (AssetInterceptRule, error) {
|
||||
row := s.db.QueryRow(`
|
||||
UPDATE task_intercept_rules
|
||||
SET enabled=$3, action=$4, kind=$5, pattern=$6, note=$7
|
||||
WHERE id=$1 AND task_id=$2
|
||||
RETURNING `+taskInterceptRuleCols,
|
||||
ruleID, taskID, enabled, normalizeRuleAction(action), kind, pattern, note)
|
||||
return scanTaskInterceptRule(row)
|
||||
}
|
||||
|
||||
// DeleteTaskInterceptRule removes a task's rule. Returns false if not found.
|
||||
func (s *AssetStore) DeleteTaskInterceptRule(taskID, ruleID int64) (bool, error) {
|
||||
res, err := s.db.Exec(`DELETE FROM task_intercept_rules WHERE id=$1 AND task_id=$2`, ruleID, taskID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
n, _ := res.RowsAffected()
|
||||
return n > 0, nil
|
||||
}
|
||||
|
||||
// ToggleTaskInterceptRule flips the enabled state of a task's rule.
|
||||
func (s *AssetStore) ToggleTaskInterceptRule(taskID, ruleID int64, enabled bool) error {
|
||||
_, err := s.db.Exec(`UPDATE task_intercept_rules SET enabled=$3 WHERE id=$1 AND task_id=$2`, ruleID, taskID, enabled)
|
||||
return err
|
||||
}
|
||||
|
||||
// insertTaskInterceptRules inserts task-level rules within the task-creation
|
||||
// transaction (mirrors insertTaskCompanies).
|
||||
func insertTaskInterceptRules(tx *sql.Tx, taskID int64, rules []TaskInterceptRuleInput) error {
|
||||
for _, r := range rules {
|
||||
if _, err := tx.Exec(`
|
||||
INSERT INTO task_intercept_rules(task_id, enabled, action, kind, pattern, note)
|
||||
VALUES ($1,$2,$3,$4,$5,$6)`, taskID, r.Enabled, normalizeRuleAction(r.Action), r.Kind, r.Pattern, r.Note); err != nil {
|
||||
return fmt.Errorf("insert task intercept rule %q: %w", r.Pattern, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user