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
123 lines
4.2 KiB
Go
123 lines
4.2 KiB
Go
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
|
|
}
|