x
This commit is contained in:
@@ -1,163 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Ban Stdlib Logger
|
|
||||||
# description: Blocks use of stdlib logging in Python code
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.ban_stdlib_logger
|
|
||||||
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
is_python_patch(patch_text) if {
|
|
||||||
contains(patch_text, ".py")
|
|
||||||
}
|
|
||||||
|
|
||||||
is_python_patch(patch_text) if {
|
|
||||||
contains(patch_text, ".pyi")
|
|
||||||
}
|
|
||||||
|
|
||||||
stdlib_logger_pattern := `import logging|from logging import|logging\.getLogger`
|
|
||||||
file_path_pattern := `\.py$`
|
|
||||||
|
|
||||||
# Block Write/Edit operations that introduce stdlib logging
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(stdlib_logger_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-LOG-001",
|
|
||||||
"reason": "Stdlib logging usage is prohibited. Use the project logging utilities instead.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(stdlib_logger_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-LOG-001",
|
|
||||||
"reason": "Stdlib logging usage is prohibited. Use the project logging utilities instead.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
lower_patch := lower(patch)
|
|
||||||
is_python_patch(lower_patch)
|
|
||||||
regex.match(stdlib_logger_pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-LOG-001",
|
|
||||||
"reason": "Stdlib logging usage is prohibited. Use the project logging utilities instead.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Assertion Roulette
|
|
||||||
# description: Blocks multiple bare asserts in a single test without messages
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_assertion_roulette
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "+++ b/")
|
|
||||||
path := replace(line, "+++ b/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "--- a/")
|
|
||||||
path := replace(line, "--- a/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
file_path_pattern := `tests?/.*\.py$`
|
|
||||||
assertion_pattern := `^\s*assert\s+[^,\n]+\n\s*assert\s+[^,\n]+$`
|
|
||||||
|
|
||||||
# Block Write/Edit operations that introduce assertion roulette
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(assertion_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-ASSERT-001",
|
|
||||||
"reason": "Multiple bare asserts detected. Use one assert per test or add assertion messages.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(assertion_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-ASSERT-001",
|
|
||||||
"reason": "Multiple bare asserts detected. Use one assert per test or add assertion messages.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
patch_targets_path(file_path_pattern)
|
|
||||||
|
|
||||||
regex.match(assertion_pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-ASSERT-001",
|
|
||||||
"reason": "Multiple bare asserts detected. Use one assert per test or add assertion messages.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Biome Ignore
|
|
||||||
# description: Blocks ignore directives in JS/TS files
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_biome_ignore
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "+++ b/")
|
|
||||||
path := replace(line, "+++ b/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "--- a/")
|
|
||||||
path := replace(line, "--- a/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
file_path_pattern := `\.(js|jsx|ts|tsx|mjs|cjs)$`
|
|
||||||
ignore_pattern := `//\s*biome-ignore|//\s*@ts-ignore|//\s*@ts-expect-error|//\s*@ts-nocheck|//\s*eslint-disable|/\*\s*eslint-disable`
|
|
||||||
|
|
||||||
# Block Write/Edit operations that introduce ignore directives
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(ignore_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-LINT-002",
|
|
||||||
"reason": "Ignore directives for Biome/TypeScript/ESLint are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(ignore_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-LINT-002",
|
|
||||||
"reason": "Ignore directives for Biome/TypeScript/ESLint are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
patch_targets_path(file_path_pattern)
|
|
||||||
|
|
||||||
regex.match(ignore_pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-LINT-002",
|
|
||||||
"reason": "Ignore directives for Biome/TypeScript/ESLint are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Biome Ignore (Bash)
|
|
||||||
# description: Blocks Bash commands that add ignore directives to JS/TS files
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["Bash"]
|
|
||||||
package cupcake.policies.opencode.block_biome_ignore_bash
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
ignore_pattern := `(biome-ignore|@ts-ignore|@ts-expect-error|@ts-nocheck|eslint-disable).*\.(js|jsx|ts|tsx|mjs|cjs)`
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
input.tool_name == "Bash"
|
|
||||||
|
|
||||||
command := input.tool_input.command
|
|
||||||
regex.match(ignore_pattern, command)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-LINT-001",
|
|
||||||
"reason": "Ignore directives for Biome/TypeScript/ESLint are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Broad Exception Handler
|
|
||||||
# description: Blocks bare Exception handlers that only log
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_broad_exception_handler
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
handler_pattern := `except\s+Exception\s*(?:as\s+\w+)?:\s*\n\s+(?:logger\.|logging\.)`
|
|
||||||
|
|
||||||
# Block Write/Edit operations that introduce broad exception handlers
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(handler_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-EXC-001",
|
|
||||||
"reason": "Broad Exception handlers that only log are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(handler_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-EXC-001",
|
|
||||||
"reason": "Broad Exception handlers that only log are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
|
|
||||||
regex.match(handler_pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-EXC-001",
|
|
||||||
"reason": "Broad Exception handlers that only log are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Code Quality Test (Bash)
|
|
||||||
# description: Blocks Bash edits to src/test/code-quality.test.ts
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["Bash"]
|
|
||||||
package cupcake.policies.opencode.block_code_quality_test_bash
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
pattern := `(sed|awk|cat\s*>|echo\s*>|tee|cp\s+.*code-quality\.test\.ts|mv\s+.*code-quality\.test\.ts|rm\s+.*code-quality\.test\.ts|>|>>).*code-quality\.test\.ts|code-quality\.test\.ts.*(>|>>|\|.*tee)`
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
input.tool_name == "Bash"
|
|
||||||
|
|
||||||
command := input.tool_input.command
|
|
||||||
regex.match(pattern, command)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-QUALITY-001",
|
|
||||||
"reason": "Direct edits to src/test/code-quality.test.ts are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Code Quality Test (Edits)
|
|
||||||
# description: Blocks file edits to src/test/code-quality.test.ts
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_code_quality_test_edits
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
file_path_pattern := `src/test/code-quality\.test\.ts$`
|
|
||||||
|
|
||||||
# Block Write/Edit operations targeting code-quality test file
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-QUALITY-002",
|
|
||||||
"reason": "Direct edits to src/test/code-quality.test.ts are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-QUALITY-002",
|
|
||||||
"reason": "Direct edits to src/test/code-quality.test.ts are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Code Quality Test (Serena)
|
|
||||||
# description: Blocks Serena edits to src/test/code-quality.test.ts
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools:
|
|
||||||
# - McpSerenaReplaceContent
|
|
||||||
# - McpSerenaReplaceSymbolBody
|
|
||||||
# - McpSerenaCreateTextFile
|
|
||||||
# - McpSerenaInsertBeforeSymbol
|
|
||||||
# - McpSerenaInsertAfterSymbol
|
|
||||||
# - McpSerenaRenameSymbol
|
|
||||||
package cupcake.policies.opencode.block_code_quality_test_serena
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
file_path_pattern := `(^|/)src/test/code-quality\.test\.ts$`
|
|
||||||
|
|
||||||
get_relative_path := path if {
|
|
||||||
path := tool_input.relative_path
|
|
||||||
} else := path if {
|
|
||||||
path := tool_input.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
# Block Serena operations targeting code-quality test file
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
|
|
||||||
tool_names := {"McpSerenaReplaceContent", "McpSerenaReplaceSymbolBody", "McpSerenaCreateTextFile", "McpSerenaInsertBeforeSymbol", "McpSerenaInsertAfterSymbol", "McpSerenaRenameSymbol"}
|
|
||||||
tool_name in tool_names
|
|
||||||
|
|
||||||
file_path := get_relative_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-QUALITY-003",
|
|
||||||
"reason": "Direct edits to src/test/code-quality.test.ts are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Code Quality Test (Serena Plugin)
|
|
||||||
# description: Blocks Serena plugin edits to src/test/code-quality.test.ts
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools:
|
|
||||||
# - McpPluginSerenaSerenaReplaceContent
|
|
||||||
# - McpPluginSerenaSerenaReplaceSymbolBody
|
|
||||||
# - McpPluginSerenaSerenaCreateTextFile
|
|
||||||
# - McpPluginSerenaSerenaInsertBeforeSymbol
|
|
||||||
# - McpPluginSerenaSerenaInsertAfterSymbol
|
|
||||||
# - McpPluginSerenaSerenaRenameSymbol
|
|
||||||
package cupcake.policies.opencode.block_code_quality_test_serena_plugin
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
file_path_pattern := `(^|/)src/test/code-quality\.test\.ts$`
|
|
||||||
|
|
||||||
get_relative_path := path if {
|
|
||||||
path := tool_input.relative_path
|
|
||||||
} else := path if {
|
|
||||||
path := tool_input.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
# Block Serena plugin operations targeting code-quality test file
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
|
|
||||||
tool_names := {"McpPluginSerenaSerenaReplaceContent", "McpPluginSerenaSerenaReplaceSymbolBody", "McpPluginSerenaSerenaCreateTextFile", "McpPluginSerenaSerenaInsertBeforeSymbol", "McpPluginSerenaSerenaInsertAfterSymbol", "McpPluginSerenaSerenaRenameSymbol"}
|
|
||||||
tool_name in tool_names
|
|
||||||
|
|
||||||
file_path := get_relative_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-QUALITY-004",
|
|
||||||
"reason": "Direct edits to src/test/code-quality.test.ts are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block datetime.now Fallback
|
|
||||||
# description: Blocks returning datetime.now() as a fallback
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_datetime_now_fallback
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
pattern := `return\s+datetime\.now\s*\(`
|
|
||||||
|
|
||||||
# Block Write/Edit operations that introduce datetime.now fallback
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-DT-001",
|
|
||||||
"reason": "Returning datetime.now() as a fallback is prohibited. Use a caller-provided timestamp.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-DT-001",
|
|
||||||
"reason": "Returning datetime.now() as a fallback is prohibited. Use a caller-provided timestamp.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
|
|
||||||
regex.match(pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-DT-001",
|
|
||||||
"reason": "Returning datetime.now() as a fallback is prohibited. Use a caller-provided timestamp.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Default Value Swallow
|
|
||||||
# description: Blocks exception handlers that warn and return defaults
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_default_value_swallow
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
pattern := `except\s+\w*(?:Error|Exception).*?:\s*\n\s+.*?(?:logger\.|logging\.).*?(?:warning|warn).*?\n\s+return\s+(?:\w+Settings|Defaults?\(|default_|\{[^}]*\}|[A-Z_]+_DEFAULT)`
|
|
||||||
|
|
||||||
# Block Write/Edit operations that swallow exceptions with defaults
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-EXC-002",
|
|
||||||
"reason": "Swallowing exceptions and returning defaults is prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-EXC-002",
|
|
||||||
"reason": "Swallowing exceptions and returning defaults is prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
|
|
||||||
regex.match(pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-EXC-002",
|
|
||||||
"reason": "Swallowing exceptions and returning defaults is prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Duplicate Fixtures
|
|
||||||
# description: Blocks redefining global pytest fixtures outside conftest.py
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_duplicate_fixtures
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "+++ b/")
|
|
||||||
path := replace(line, "+++ b/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "--- a/")
|
|
||||||
path := replace(line, "--- a/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
file_path_pattern := `tests?/.*\.py$`
|
|
||||||
conftest_pattern := `tests?/conftest\.py$`
|
|
||||||
fixture_pattern := `@pytest\.fixture[^@]*\ndef\s+(mock_uow|crypto|meetings_dir|webhook_config|webhook_config_all_events|sample_datetime|calendar_settings|meeting_id|sample_meeting|recording_meeting|mock_grpc_context|mock_asr_engine|mock_optional_extras)\s*\(`
|
|
||||||
|
|
||||||
# Block Write/Edit operations that introduce duplicate fixtures
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
not regex.match(conftest_pattern, file_path)
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(fixture_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-FIX-001",
|
|
||||||
"reason": "Duplicate global fixtures are prohibited. Use tests/conftest.py fixtures instead.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
not regex.match(conftest_pattern, file_path)
|
|
||||||
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(fixture_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-FIX-001",
|
|
||||||
"reason": "Duplicate global fixtures are prohibited. Use tests/conftest.py fixtures instead.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
patch_targets_path(file_path_pattern)
|
|
||||||
not regex.match(conftest_pattern, patch)
|
|
||||||
|
|
||||||
regex.match(fixture_pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-FIX-001",
|
|
||||||
"reason": "Duplicate global fixtures are prohibited. Use tests/conftest.py fixtures instead.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Frontend Linter Config
|
|
||||||
# description: Blocks edits to frontend linter config files
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_linter_config_frontend
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
file_path_pattern := `(^|/)client/.*(?:\.?eslint(?:rc|\.config).*|\.?prettier(?:rc|\.config).*|biome\.json|tsconfig\.json|\.?rustfmt\.toml|\.?clippy\.toml)$`
|
|
||||||
|
|
||||||
# Block Write/Edit operations targeting frontend linter configs
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
not contains(lower(file_path), "node_modules/")
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-CONFIG-002",
|
|
||||||
"reason": "Frontend linter/config file edits are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
not contains(lower(file_path), "node_modules/")
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-CONFIG-002",
|
|
||||||
"reason": "Frontend linter/config file edits are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Frontend Linter Config (Bash)
|
|
||||||
# description: Blocks Bash edits to frontend linter config files
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["Bash"]
|
|
||||||
package cupcake.policies.opencode.block_linter_config_frontend_bash
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
pattern := `(rm|mv|cp|sed|awk|chmod|chown|touch|truncate|tee|>|>>)\s.*client/.*(?:biome\.json|tsconfig\.json|\.?eslint(?:rc|\.config)|\.?prettier(?:rc|\.config)|\.?rustfmt\.toml|\.?clippy\.toml)`
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
input.tool_name == "Bash"
|
|
||||||
|
|
||||||
command := input.tool_input.command
|
|
||||||
regex.match(pattern, command)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TS-CONFIG-001",
|
|
||||||
"reason": "Frontend linter/config file edits are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Python Linter Config
|
|
||||||
# description: Blocks edits to Python linter config files
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_linter_config_python
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
file_path_pattern := `(?:pyproject\.toml|\.?ruff\.toml|\.?pyrightconfig\.json|\.?mypy\.ini|setup\.cfg|\.flake8|tox\.ini|\.?pylintrc)$`
|
|
||||||
|
|
||||||
# Block Write/Edit operations targeting Python linter configs
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
not contains(lower(file_path), "/.venv/")
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-CONFIG-002",
|
|
||||||
"reason": "Python linter/config file edits are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
not contains(lower(file_path), "/.venv/")
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-CONFIG-002",
|
|
||||||
"reason": "Python linter/config file edits are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Python Linter Config (Bash)
|
|
||||||
# description: Blocks Bash edits to Python linter config files
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["Bash"]
|
|
||||||
package cupcake.policies.opencode.block_linter_config_python_bash
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
pattern := `(rm|mv|cp|sed|awk|chmod|chown|touch|truncate|tee|>|>>)\s.*(?:pyproject\.toml|\.?ruff\.toml|\.?pyrightconfig\.json|\.?mypy\.ini|setup\.cfg|\.flake8|tox\.ini|\.?pylintrc)`
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
input.tool_name == "Bash"
|
|
||||||
|
|
||||||
command := input.tool_input.command
|
|
||||||
regex.match(pattern, command)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-CONFIG-001",
|
|
||||||
"reason": "Python linter/config file edits are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Magic Numbers
|
|
||||||
# description: Blocks introduction of magic numbers outside constants modules
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_magic_numbers
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "+++ b/")
|
|
||||||
path := replace(line, "+++ b/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "--- a/")
|
|
||||||
path := replace(line, "--- a/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
file_path_pattern := `\.(py|ts|tsx|js|jsx)$`
|
|
||||||
number_pattern := `(?:timeout|delay|interval|duration|limit|max|min|size|count|threshold|retry|retries|attempts|port|width|height|margin|padding|offset|index|length|capacity|buffer|batch|chunk|page|rate|fps|dpi|quality|level|priority|weight|score|factor|multiplier|divisor|percentage|ratio|scale)\s*[=:]\s*([2-9]|[1-9]\d+)|(?:if|while|for|elif|range|slice|sleep|wait|setTimeout|setInterval)\s*\([^)]*([2-9]|[1-9]\d+)`
|
|
||||||
|
|
||||||
# Block Write/Edit operations that introduce magic numbers
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
not contains(lower(file_path), "constants")
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(number_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "STYLE-001",
|
|
||||||
"reason": "Magic numbers are prohibited. Use named constants.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
not contains(lower(file_path), "constants")
|
|
||||||
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(number_pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "STYLE-001",
|
|
||||||
"reason": "Magic numbers are prohibited. Use named constants.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
patch_targets_path(file_path_pattern)
|
|
||||||
not contains(lower(patch), "constants")
|
|
||||||
|
|
||||||
regex.match(number_pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "STYLE-001",
|
|
||||||
"reason": "Magic numbers are prohibited. Use named constants.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Makefile Edit (Bash)
|
|
||||||
# description: Blocks Bash edits to Makefile
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["Bash"]
|
|
||||||
package cupcake.policies.opencode.block_makefile_bash
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
pattern := `(>>?\s*Makefile|sed\s+.*-i.*Makefile|sed\s+-i.*Makefile|perl\s+-[pi].*Makefile|tee\s+.*Makefile|(mv|cp)\s+\S+\s+Makefile\b|>\s*Makefile)`
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
input.tool_name == "Bash"
|
|
||||||
|
|
||||||
command := input.tool_input.command
|
|
||||||
regex.match(pattern, command)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "BUILD-001",
|
|
||||||
"reason": "Makefile edits are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Makefile Edit
|
|
||||||
# description: Blocks file edits to Makefile
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_makefile_edit
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
file_path_pattern := `(?:^|/)Makefile$`
|
|
||||||
|
|
||||||
# Block Write/Edit operations targeting Makefile
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "BUILD-002",
|
|
||||||
"reason": "Makefile edits are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "BUILD-002",
|
|
||||||
"reason": "Makefile edits are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Git --no-verify
|
|
||||||
# description: Blocks git commit --no-verify
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["Bash"]
|
|
||||||
package cupcake.policies.opencode.block_no_verify
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
pattern := `git\s+commit\s+.*--no-verify|git\s+commit\s+--no-verify`
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
input.tool_name == "Bash"
|
|
||||||
|
|
||||||
command := input.tool_input.command
|
|
||||||
regex.match(pattern, command)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "GIT-001",
|
|
||||||
"reason": "Git commit --no-verify is prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Silent None Return
|
|
||||||
# description: Blocks exception handlers that log and return empty values
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_silent_none_return
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
pattern := `except\s+\w*Error.*?:\s*\n\s+.*?(?:logger\.|logging\.).*?\n\s+return\s+(?:None|\[\]|False|\{\}|0)`
|
|
||||||
|
|
||||||
# Block Write/Edit operations that swallow exceptions with empty returns
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-EXC-003",
|
|
||||||
"reason": "Silent exception handlers returning empty values are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-EXC-003",
|
|
||||||
"reason": "Silent exception handlers returning empty values are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
|
|
||||||
regex.match(pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-EXC-003",
|
|
||||||
"reason": "Silent exception handlers returning empty values are prohibited.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Test Loops/Conditionals
|
|
||||||
# description: Blocks loops or conditionals inside tests with asserts
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_test_loops_conditionals
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "+++ b/")
|
|
||||||
path := replace(line, "+++ b/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "--- a/")
|
|
||||||
path := replace(line, "--- a/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
file_path_pattern := `tests?/.*\.py$`
|
|
||||||
pattern := `def test_[^(]+\([^)]*\)[^:]*:[\s\S]*?\b(for|while|if)\s+[^:]+:[\s\S]*?assert`
|
|
||||||
|
|
||||||
# Block Write/Edit operations that introduce loops/conditionals in tests
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-STRUCT-001",
|
|
||||||
"reason": "Loops or conditionals inside tests are prohibited. Use parametrization.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-STRUCT-001",
|
|
||||||
"reason": "Loops or conditionals inside tests are prohibited. Use parametrization.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
patch_targets_path(file_path_pattern)
|
|
||||||
|
|
||||||
regex.match(pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-STRUCT-001",
|
|
||||||
"reason": "Loops or conditionals inside tests are prohibited. Use parametrization.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Tests Quality
|
|
||||||
# description: Blocks edits to tests/quality (except baselines.json)
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.block_tests_quality
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
file_path_pattern := `tests/quality/`
|
|
||||||
exclude_pattern := `baselines\.json$`
|
|
||||||
|
|
||||||
# Block Write/Edit operations targeting tests/quality
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
not regex.match(exclude_pattern, file_path)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-QUALITY-002",
|
|
||||||
"reason": "Direct edits to tests/quality are prohibited (except baselines.json).",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
not regex.match(exclude_pattern, file_path)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-QUALITY-002",
|
|
||||||
"reason": "Direct edits to tests/quality are prohibited (except baselines.json).",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Block Tests Quality (Bash)
|
|
||||||
# description: Blocks Bash edits to tests/quality (except baselines.json)
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["Bash"]
|
|
||||||
package cupcake.policies.opencode.block_tests_quality_bash
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
pattern := `(rm|mv|cp|sed|awk|chmod|chown|touch|mkdir|rmdir|truncate|tee|>|>>)\s.*tests/quality/`
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
input.tool_name == "Bash"
|
|
||||||
|
|
||||||
command := input.tool_input.command
|
|
||||||
regex.match(pattern, command)
|
|
||||||
not contains(lower(command), "tests/quality/baselines.json")
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-QUALITY-001",
|
|
||||||
"reason": "Direct edits to tests/quality are prohibited (except baselines.json).",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Example Policy
|
|
||||||
# description: A minimal example policy that never fires
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["Bash"]
|
|
||||||
package cupcake.policies.example
|
|
||||||
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
# This rule will never fire - it's just here to prevent OPA compilation issues
|
|
||||||
# It checks for a command that nobody would ever type
|
|
||||||
deny contains decision if {
|
|
||||||
input.tool_input.command == "CUPCAKE_EXAMPLE_RULE_THAT_NEVER_FIRES_12345"
|
|
||||||
decision := {
|
|
||||||
"reason": "This will never happen",
|
|
||||||
"severity": "LOW",
|
|
||||||
"rule_id": "EXAMPLE-001"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Replace the above with your actual policies
|
|
||||||
# Example of a real policy:
|
|
||||||
# deny contains decision if {
|
|
||||||
# contains(input.tool_input.command, "rm -rf /")
|
|
||||||
# decision := {
|
|
||||||
# "reason": "Dangerous command blocked",
|
|
||||||
# "severity": "HIGH",
|
|
||||||
# "rule_id": "SAFETY-001"
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Ban Python Any Type
|
|
||||||
# description: Blocks introduction of typing.Any in Python code
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.prevent_any_type
|
|
||||||
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
is_python_file(path) if {
|
|
||||||
endswith(path, ".py")
|
|
||||||
}
|
|
||||||
|
|
||||||
is_python_file(path) if {
|
|
||||||
endswith(path, ".pyi")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Regex patterns indicating use of Any in type annotations/imports
|
|
||||||
any_type_patterns := [
|
|
||||||
`(?m)^\s*from\s+typing\s+import\s+[^#\n]*\bAny\b`,
|
|
||||||
`\btyping\.Any\b`,
|
|
||||||
`:\s*Any\b`,
|
|
||||||
`:\s*"Any"`,
|
|
||||||
`:\s*'Any'`,
|
|
||||||
`->\s*Any\b`,
|
|
||||||
`->\s*"Any"`,
|
|
||||||
`->\s*'Any'`,
|
|
||||||
`\[\s*Any\s*\]`,
|
|
||||||
`\[\s*Any\s*,`,
|
|
||||||
`,\s*Any\s*\]`,
|
|
||||||
`,\s*Any\s*,`,
|
|
||||||
`Union\[[^\]]*\bAny\b[^\]]*\]`,
|
|
||||||
`Optional\[Any\]`,
|
|
||||||
]
|
|
||||||
|
|
||||||
# Block Write/Edit operations that introduce Any in Python files
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
# Only enforce for Python files
|
|
||||||
file_path := lower(resolved_file_path)
|
|
||||||
is_python_file(file_path)
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
|
|
||||||
some pattern in any_type_patterns
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-TYPE-001",
|
|
||||||
"reason": "Use of Any is prohibited in Python type annotations/imports. Replace with Protocol, TypeVar, TypedDict, or a concrete type.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
content := patch_content
|
|
||||||
content != null
|
|
||||||
|
|
||||||
some pattern in any_type_patterns
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-TYPE-001",
|
|
||||||
"reason": "Use of Any is prohibited in Python type annotations/imports. Replace with Protocol, TypeVar, TypedDict, or a concrete type.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := lower(edit_path(edit))
|
|
||||||
is_python_file(file_path)
|
|
||||||
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
|
|
||||||
some pattern in any_type_patterns
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-TYPE-001",
|
|
||||||
"reason": "Use of Any is prohibited in Python type annotations/imports. Replace with Protocol, TypeVar, TypedDict, or a concrete type.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Ban Python Type Suppression
|
|
||||||
# description: Blocks type suppression directives in Python code
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.prevent_type_suppression
|
|
||||||
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
is_python_file(path) if {
|
|
||||||
endswith(path, ".py")
|
|
||||||
}
|
|
||||||
|
|
||||||
is_python_file(path) if {
|
|
||||||
endswith(path, ".pyi")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Regex patterns indicating type suppression directives
|
|
||||||
type_suppression_patterns := [
|
|
||||||
`#\s*type:\s*ignore(\[[^\]]+\])?\b`,
|
|
||||||
`#\s*pyright:\s*ignore(\[[^\]]+\])?\b`,
|
|
||||||
`#\s*mypy:\s*ignore(\[[^\]]+\])?\b`,
|
|
||||||
`#\s*pyre-ignore\b`,
|
|
||||||
`#\s*pyre-fixme\b`,
|
|
||||||
`#\s*pyrefly:\s*ignore(\[[^\]]+\])?\b`,
|
|
||||||
`#\s*basedpyright:\s*ignore(\[[^\]]+\])?\b`,
|
|
||||||
`#\s*noqa\b`,
|
|
||||||
`#\s*noqa:\s*\w+`,
|
|
||||||
]
|
|
||||||
|
|
||||||
# Block Write/Edit operations that introduce type suppression in Python files
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
# Only enforce for Python files
|
|
||||||
file_path := lower(resolved_file_path)
|
|
||||||
is_python_file(file_path)
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
|
|
||||||
some pattern in type_suppression_patterns
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-TYPE-002",
|
|
||||||
"reason": "Type suppression directives are prohibited in Python code. Fix the underlying type/lint issues instead.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
content := patch_content
|
|
||||||
content != null
|
|
||||||
|
|
||||||
some pattern in type_suppression_patterns
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-TYPE-002",
|
|
||||||
"reason": "Type suppression directives are prohibited in Python code. Fix the underlying type/lint issues instead.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := lower(edit_path(edit))
|
|
||||||
is_python_file(file_path)
|
|
||||||
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
|
|
||||||
some pattern in type_suppression_patterns
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "PY-TYPE-002",
|
|
||||||
"reason": "Type suppression directives are prohibited in Python code. Fix the underlying type/lint issues instead.",
|
|
||||||
"severity": "HIGH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Warn on Baselines Edit
|
|
||||||
# description: Warns on edits to tests/quality/baselines.json
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.warn_baselines_edit
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
file_path_pattern := `tests/quality/baselines\.json$`
|
|
||||||
|
|
||||||
# Warn on Write/Edit operations targeting baselines.json
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-QUALITY-004",
|
|
||||||
"reason": "Warning: editing tests/quality/baselines.json should be avoided unless explicitly required.",
|
|
||||||
"severity": "LOW"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-QUALITY-004",
|
|
||||||
"reason": "Warning: editing tests/quality/baselines.json should be avoided unless explicitly required.",
|
|
||||||
"severity": "LOW"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Warn on Baselines Edit (Bash)
|
|
||||||
# description: Warns on Bash edits to tests/quality/baselines.json
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["Bash"]
|
|
||||||
package cupcake.policies.opencode.warn_baselines_edit_bash
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
pattern := `(sed|awk|echo|cat|tee|>|>>|cp|mv).*tests/quality/baselines\.json`
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
input.tool_name == "Bash"
|
|
||||||
|
|
||||||
command := input.tool_input.command
|
|
||||||
regex.match(pattern, command)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "TEST-QUALITY-003",
|
|
||||||
"reason": "Warning: editing tests/quality/baselines.json should be avoided unless explicitly required.",
|
|
||||||
"severity": "LOW"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
# METADATA
|
|
||||||
# scope: package
|
|
||||||
# title: Warn on Large File
|
|
||||||
# description: Warns when writing large files (>= 500 lines)
|
|
||||||
# custom:
|
|
||||||
# routing:
|
|
||||||
# required_events: ["PreToolUse"]
|
|
||||||
# required_tools: ["ApplyPatch", "Edit", "MultiEdit", "NotebookEdit", "Patch", "Write"]
|
|
||||||
package cupcake.policies.opencode.warn_large_file
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
tool_name := input.tool_name
|
|
||||||
tool_input := input.tool_input
|
|
||||||
|
|
||||||
resolved_file_path := input.resolved_file_path if {
|
|
||||||
input.resolved_file_path != null
|
|
||||||
} else := tool_input.file_path if {
|
|
||||||
tool_input.file_path != null
|
|
||||||
} else := tool_input.filePath if {
|
|
||||||
tool_input.filePath != null
|
|
||||||
} else := tool_input.path if {
|
|
||||||
tool_input.path != null
|
|
||||||
} else := tool_input.notebook_path if {
|
|
||||||
tool_input.notebook_path != null
|
|
||||||
} else := tool_input.notebookPath if {
|
|
||||||
tool_input.notebookPath != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
new_content := tool_input.new_string if {
|
|
||||||
tool_input.new_string != null
|
|
||||||
} else := tool_input.newText if {
|
|
||||||
tool_input.newText != null
|
|
||||||
} else := tool_input.new_text if {
|
|
||||||
tool_input.new_text != null
|
|
||||||
} else := tool_input.content if {
|
|
||||||
tool_input.content != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
old_content := tool_input.old_string if {
|
|
||||||
tool_input.old_string != null
|
|
||||||
} else := tool_input.oldText if {
|
|
||||||
tool_input.oldText != null
|
|
||||||
} else := tool_input.old_text if {
|
|
||||||
tool_input.old_text != null
|
|
||||||
} else := tool_input.previousContent if {
|
|
||||||
tool_input.previousContent != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
patch_content := tool_input.patch if {
|
|
||||||
tool_input.patch != null
|
|
||||||
} else := tool_input.patchText if {
|
|
||||||
tool_input.patchText != null
|
|
||||||
} else := tool_input.patch_text if {
|
|
||||||
tool_input.patch_text != null
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_path(edit) := path if {
|
|
||||||
edit.resolved_file_path != null
|
|
||||||
path := edit.resolved_file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.file_path != null
|
|
||||||
path := edit.file_path
|
|
||||||
} else := path if {
|
|
||||||
edit.filePath != null
|
|
||||||
path := edit.filePath
|
|
||||||
} else := path if {
|
|
||||||
edit.path != null
|
|
||||||
path := edit.path
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_new_content(edit) := content if {
|
|
||||||
edit.new_string != null
|
|
||||||
content := edit.new_string
|
|
||||||
} else := content if {
|
|
||||||
edit.newText != null
|
|
||||||
content := edit.newText
|
|
||||||
} else := content if {
|
|
||||||
edit.new_text != null
|
|
||||||
content := edit.new_text
|
|
||||||
} else := content if {
|
|
||||||
edit.content != null
|
|
||||||
content := edit.content
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
edit_old_content(edit) := content if {
|
|
||||||
edit.old_string != null
|
|
||||||
content := edit.old_string
|
|
||||||
} else := content if {
|
|
||||||
edit.oldText != null
|
|
||||||
content := edit.oldText
|
|
||||||
} else := content if {
|
|
||||||
edit.old_text != null
|
|
||||||
content := edit.old_text
|
|
||||||
} else := ""
|
|
||||||
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "+++ b/")
|
|
||||||
path := replace(line, "+++ b/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_targets_path(pattern) if {
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
lines := split(patch, "\n")
|
|
||||||
some line in lines
|
|
||||||
startswith(line, "--- a/")
|
|
||||||
path := replace(line, "--- a/", "")
|
|
||||||
regex.match(pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
file_path_pattern := `\.(py|ts|tsx|js|jsx)$`
|
|
||||||
pattern := `(?:.*\n){500,}`
|
|
||||||
|
|
||||||
# Warn on Write/Edit operations that introduce large file content
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Write", "Edit", "NotebookEdit"}
|
|
||||||
|
|
||||||
file_path := resolved_file_path
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
content := new_content
|
|
||||||
content != null
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "STYLE-002",
|
|
||||||
"reason": "Warning: file content exceeds 500 lines. Consider refactoring.",
|
|
||||||
"severity": "LOW"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name == "MultiEdit"
|
|
||||||
|
|
||||||
some edit in tool_input.edits
|
|
||||||
file_path := edit_path(edit)
|
|
||||||
regex.match(file_path_pattern, file_path)
|
|
||||||
|
|
||||||
content := edit_new_content(edit)
|
|
||||||
content != null
|
|
||||||
regex.match(pattern, content)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "STYLE-002",
|
|
||||||
"reason": "Warning: file content exceeds 500 lines. Consider refactoring.",
|
|
||||||
"severity": "LOW"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deny contains decision if {
|
|
||||||
input.hook_event_name == "PreToolUse"
|
|
||||||
tool_name in {"Patch", "ApplyPatch"}
|
|
||||||
|
|
||||||
patch := patch_content
|
|
||||||
patch != null
|
|
||||||
|
|
||||||
patch_targets_path(file_path_pattern)
|
|
||||||
|
|
||||||
regex.match(pattern, patch)
|
|
||||||
|
|
||||||
decision := {
|
|
||||||
"rule_id": "STYLE-002",
|
|
||||||
"reason": "Warning: file content exceeds 500 lines. Consider refactoring.",
|
|
||||||
"severity": "LOW"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,972 +0,0 @@
|
|||||||
{
|
|
||||||
"machine_info": {
|
|
||||||
"node": "little",
|
|
||||||
"processor": "x86_64",
|
|
||||||
"machine": "x86_64",
|
|
||||||
"python_compiler": "GCC 13.3.0",
|
|
||||||
"python_implementation": "CPython",
|
|
||||||
"python_implementation_version": "3.12.3",
|
|
||||||
"python_version": "3.12.3",
|
|
||||||
"python_build": [
|
|
||||||
"main",
|
|
||||||
"Nov 6 2025 13:44:16"
|
|
||||||
],
|
|
||||||
"release": "6.14.0-1018-oem",
|
|
||||||
"system": "Linux",
|
|
||||||
"cpu": {
|
|
||||||
"python_version": "3.12.3.final.0 (64 bit)",
|
|
||||||
"cpuinfo_version": [
|
|
||||||
9,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"cpuinfo_version_string": "9.0.0",
|
|
||||||
"arch": "X86_64",
|
|
||||||
"bits": 64,
|
|
||||||
"count": 14,
|
|
||||||
"arch_string_raw": "x86_64",
|
|
||||||
"vendor_id_raw": "AuthenticAMD",
|
|
||||||
"brand_raw": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S",
|
|
||||||
"hz_advertised_friendly": "3.0000 GHz",
|
|
||||||
"hz_actual_friendly": "3.0000 GHz",
|
|
||||||
"hz_advertised": [
|
|
||||||
2999956000,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"hz_actual": [
|
|
||||||
2999956000,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"model": 112,
|
|
||||||
"family": 26,
|
|
||||||
"flags": [
|
|
||||||
"3dnowprefetch",
|
|
||||||
"abm",
|
|
||||||
"adx",
|
|
||||||
"aes",
|
|
||||||
"apic",
|
|
||||||
"arat",
|
|
||||||
"arch_capabilities",
|
|
||||||
"avx",
|
|
||||||
"avx2",
|
|
||||||
"avx512_bf16",
|
|
||||||
"avx512_bitalg",
|
|
||||||
"avx512_vbmi2",
|
|
||||||
"avx512_vnni",
|
|
||||||
"avx512_vp2intersect",
|
|
||||||
"avx512_vpopcntdq",
|
|
||||||
"avx512bitalg",
|
|
||||||
"avx512bw",
|
|
||||||
"avx512cd",
|
|
||||||
"avx512dq",
|
|
||||||
"avx512f",
|
|
||||||
"avx512ifma",
|
|
||||||
"avx512vbmi",
|
|
||||||
"avx512vbmi2",
|
|
||||||
"avx512vl",
|
|
||||||
"avx512vnni",
|
|
||||||
"avx512vpopcntdq",
|
|
||||||
"avx_vnni",
|
|
||||||
"bmi1",
|
|
||||||
"bmi2",
|
|
||||||
"clflush",
|
|
||||||
"clflushopt",
|
|
||||||
"clwb",
|
|
||||||
"clzero",
|
|
||||||
"cmov",
|
|
||||||
"cmp_legacy",
|
|
||||||
"cpuid",
|
|
||||||
"cr8_legacy",
|
|
||||||
"cx16",
|
|
||||||
"cx8",
|
|
||||||
"de",
|
|
||||||
"erms",
|
|
||||||
"extd_apicid",
|
|
||||||
"f16c",
|
|
||||||
"flush_l1d",
|
|
||||||
"flushbyasid",
|
|
||||||
"fma",
|
|
||||||
"fpu",
|
|
||||||
"fsgsbase",
|
|
||||||
"fsrm",
|
|
||||||
"fxsr",
|
|
||||||
"fxsr_opt",
|
|
||||||
"gfni",
|
|
||||||
"ht",
|
|
||||||
"hypervisor",
|
|
||||||
"ibpb",
|
|
||||||
"ibrs",
|
|
||||||
"ibrs_enhanced",
|
|
||||||
"invpcid",
|
|
||||||
"lahf_lm",
|
|
||||||
"lbrv",
|
|
||||||
"lm",
|
|
||||||
"mca",
|
|
||||||
"mce",
|
|
||||||
"misalignsse",
|
|
||||||
"mmx",
|
|
||||||
"mmxext",
|
|
||||||
"movbe",
|
|
||||||
"movdir64b",
|
|
||||||
"movdiri",
|
|
||||||
"msr",
|
|
||||||
"mtrr",
|
|
||||||
"nopl",
|
|
||||||
"npt",
|
|
||||||
"nrip_save",
|
|
||||||
"nx",
|
|
||||||
"ospke",
|
|
||||||
"osvw",
|
|
||||||
"osxsave",
|
|
||||||
"overflow_recov",
|
|
||||||
"pae",
|
|
||||||
"pat",
|
|
||||||
"pausefilter",
|
|
||||||
"pclmulqdq",
|
|
||||||
"pdpe1gb",
|
|
||||||
"perfctr_core",
|
|
||||||
"perfmon_v2",
|
|
||||||
"pfthreshold",
|
|
||||||
"pge",
|
|
||||||
"pku",
|
|
||||||
"pni",
|
|
||||||
"popcnt",
|
|
||||||
"pse",
|
|
||||||
"pse36",
|
|
||||||
"rdpid",
|
|
||||||
"rdrand",
|
|
||||||
"rdrnd",
|
|
||||||
"rdseed",
|
|
||||||
"rdtscp",
|
|
||||||
"rep_good",
|
|
||||||
"sep",
|
|
||||||
"sha",
|
|
||||||
"sha_ni",
|
|
||||||
"smap",
|
|
||||||
"smep",
|
|
||||||
"ssbd",
|
|
||||||
"sse",
|
|
||||||
"sse2",
|
|
||||||
"sse4_1",
|
|
||||||
"sse4_2",
|
|
||||||
"sse4a",
|
|
||||||
"ssse3",
|
|
||||||
"stibp",
|
|
||||||
"succor",
|
|
||||||
"svm",
|
|
||||||
"syscall",
|
|
||||||
"tsc",
|
|
||||||
"tsc_adjust",
|
|
||||||
"tsc_deadline_timer",
|
|
||||||
"tsc_known_freq",
|
|
||||||
"tsc_scale",
|
|
||||||
"tscdeadline",
|
|
||||||
"umip",
|
|
||||||
"v_vmsave_vmload",
|
|
||||||
"vaes",
|
|
||||||
"vgif",
|
|
||||||
"vmcb_clean",
|
|
||||||
"vme",
|
|
||||||
"vmmcall",
|
|
||||||
"vnmi",
|
|
||||||
"vpclmulqdq",
|
|
||||||
"wbnoinvd",
|
|
||||||
"x2apic",
|
|
||||||
"xgetbv1",
|
|
||||||
"xsave",
|
|
||||||
"xsavec",
|
|
||||||
"xsaveerptr",
|
|
||||||
"xsaveopt",
|
|
||||||
"xsaves"
|
|
||||||
],
|
|
||||||
"l3_cache_size": 524288,
|
|
||||||
"l2_cache_size": 7340032,
|
|
||||||
"l1_data_cache_size": 917504,
|
|
||||||
"l1_instruction_cache_size": 917504,
|
|
||||||
"l2_cache_line_size": 512,
|
|
||||||
"l2_cache_associativity": 8
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"commit_info": {
|
|
||||||
"id": "7292f0fc29a9a16b9f34fb78b33363f459c37523",
|
|
||||||
"time": "2025-12-29T23:28:35+00:00",
|
|
||||||
"author_time": "2025-12-29T23:28:35+00:00",
|
|
||||||
"dirty": true,
|
|
||||||
"project": "noteflow",
|
|
||||||
"branch": "master"
|
|
||||||
},
|
|
||||||
"benchmarks": [
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_compute_rms_typical_chunk",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestComputeRmsBenchmark::test_compute_rms_typical_chunk",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.449000359978527e-06,
|
|
||||||
"max": 4.6748999011470005e-05,
|
|
||||||
"mean": 5.254236109048915e-06,
|
|
||||||
"stddev": 5.406737467323485e-06,
|
|
||||||
"rounds": 5993,
|
|
||||||
"median": 3.550001565599814e-06,
|
|
||||||
"iqr": 7.00001692166552e-08,
|
|
||||||
"q1": 3.529999958118424e-06,
|
|
||||||
"q3": 3.600000127335079e-06,
|
|
||||||
"iqr_outliers": 1178,
|
|
||||||
"stddev_outliers": 472,
|
|
||||||
"outliers": "472;1178",
|
|
||||||
"ld15iqr": 3.449000359978527e-06,
|
|
||||||
"hd15iqr": 3.7089994293637574e-06,
|
|
||||||
"ops": 190322.62335485584,
|
|
||||||
"total": 0.03148863700153015,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_compute_rms_silence",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestComputeRmsBenchmark::test_compute_rms_silence",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.429999196669087e-06,
|
|
||||||
"max": 5.3219000619719736e-05,
|
|
||||||
"mean": 4.240495678882168e-06,
|
|
||||||
"stddev": 3.363396020443664e-06,
|
|
||||||
"rounds": 28075,
|
|
||||||
"median": 3.5199991543777287e-06,
|
|
||||||
"iqr": 4.000139597337693e-08,
|
|
||||||
"q1": 3.499999365885742e-06,
|
|
||||||
"q3": 3.540000761859119e-06,
|
|
||||||
"iqr_outliers": 3382,
|
|
||||||
"stddev_outliers": 1091,
|
|
||||||
"outliers": "1091;3382",
|
|
||||||
"ld15iqr": 3.440000000409782e-06,
|
|
||||||
"hd15iqr": 3.6010005715070292e-06,
|
|
||||||
"ops": 235821.48779918315,
|
|
||||||
"total": 0.11905191618461686,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_compute_rms_speech",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestComputeRmsBenchmark::test_compute_rms_speech",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.359000402269885e-06,
|
|
||||||
"max": 0.0003828669996437384,
|
|
||||||
"mean": 4.002095375594478e-06,
|
|
||||||
"stddev": 3.627403301293051e-06,
|
|
||||||
"rounds": 34664,
|
|
||||||
"median": 3.529999958118424e-06,
|
|
||||||
"iqr": 8.999995770864189e-08,
|
|
||||||
"q1": 3.4900003811344504e-06,
|
|
||||||
"q3": 3.5800003388430923e-06,
|
|
||||||
"iqr_outliers": 3474,
|
|
||||||
"stddev_outliers": 717,
|
|
||||||
"outliers": "717;3474",
|
|
||||||
"ld15iqr": 3.359000402269885e-06,
|
|
||||||
"hd15iqr": 3.718998414115049e-06,
|
|
||||||
"ops": 249869.1075925341,
|
|
||||||
"total": 0.138728634099607,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_energy_vad_process",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestVadBenchmark::test_energy_vad_process",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.510000169626437e-06,
|
|
||||||
"max": 8.923800123739056e-05,
|
|
||||||
"mean": 4.2858499286555344e-06,
|
|
||||||
"stddev": 3.3828911298869402e-06,
|
|
||||||
"rounds": 34603,
|
|
||||||
"median": 3.610000931075774e-06,
|
|
||||||
"iqr": 5.00003807246685e-08,
|
|
||||||
"q1": 3.5900011425837874e-06,
|
|
||||||
"q3": 3.640001523308456e-06,
|
|
||||||
"iqr_outliers": 3951,
|
|
||||||
"stddev_outliers": 1194,
|
|
||||||
"outliers": "1194;3951",
|
|
||||||
"ld15iqr": 3.5189987102057785e-06,
|
|
||||||
"hd15iqr": 3.718998414115049e-06,
|
|
||||||
"ops": 233325.94856248237,
|
|
||||||
"total": 0.14830326508126745,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_streaming_vad_process_chunk",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestVadBenchmark::test_streaming_vad_process_chunk",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.5800003388430923e-06,
|
|
||||||
"max": 0.00010890600060520228,
|
|
||||||
"mean": 4.529488871753616e-06,
|
|
||||||
"stddev": 3.7911652114629043e-06,
|
|
||||||
"rounds": 43013,
|
|
||||||
"median": 3.690000085043721e-06,
|
|
||||||
"iqr": 5.000219971407205e-08,
|
|
||||||
"q1": 3.6699984775623307e-06,
|
|
||||||
"q3": 3.7200006772764027e-06,
|
|
||||||
"iqr_outliers": 6322,
|
|
||||||
"stddev_outliers": 1571,
|
|
||||||
"outliers": "1571;6322",
|
|
||||||
"ld15iqr": 3.598999683163129e-06,
|
|
||||||
"hd15iqr": 3.7989993870723993e-06,
|
|
||||||
"ops": 220775.4623785718,
|
|
||||||
"total": 0.19482690484073828,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_energy_vad_speech_detection",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestVadBenchmark::test_energy_vad_speech_detection",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.5700013540918007e-06,
|
|
||||||
"max": 6.072900032449979e-05,
|
|
||||||
"mean": 4.189390656398419e-06,
|
|
||||||
"stddev": 3.0348496487482607e-06,
|
|
||||||
"rounds": 42001,
|
|
||||||
"median": 3.6800011002924293e-06,
|
|
||||||
"iqr": 3.9999576983973384e-08,
|
|
||||||
"q1": 3.668999852379784e-06,
|
|
||||||
"q3": 3.7089994293637574e-06,
|
|
||||||
"iqr_outliers": 3425,
|
|
||||||
"stddev_outliers": 1102,
|
|
||||||
"outliers": "1102;3425",
|
|
||||||
"ld15iqr": 3.609000486903824e-06,
|
|
||||||
"hd15iqr": 3.769000613829121e-06,
|
|
||||||
"ops": 238698.19790443964,
|
|
||||||
"total": 0.17595859695938998,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_energy_vad_silence_detection",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestVadBenchmark::test_energy_vad_silence_detection",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.609000486903824e-06,
|
|
||||||
"max": 5.7467999795335345e-05,
|
|
||||||
"mean": 4.000768088102557e-06,
|
|
||||||
"stddev": 2.261540943065658e-06,
|
|
||||||
"rounds": 37260,
|
|
||||||
"median": 3.690000085043721e-06,
|
|
||||||
"iqr": 4.799949238076806e-08,
|
|
||||||
"q1": 3.6710007407236844e-06,
|
|
||||||
"q3": 3.7190002331044525e-06,
|
|
||||||
"iqr_outliers": 2187,
|
|
||||||
"stddev_outliers": 909,
|
|
||||||
"outliers": "909;2187",
|
|
||||||
"ld15iqr": 3.609000486903824e-06,
|
|
||||||
"hd15iqr": 3.791001290665008e-06,
|
|
||||||
"ops": 249952.003709935,
|
|
||||||
"total": 0.1490686189627013,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_segmenter_idle_silence",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestSegmenterBenchmark::test_segmenter_idle_silence",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 5.79000698053278e-07,
|
|
||||||
"max": 2.313799996045418e-05,
|
|
||||||
"mean": 6.564644165580224e-07,
|
|
||||||
"stddev": 5.256608812213979e-07,
|
|
||||||
"rounds": 88818,
|
|
||||||
"median": 6.099999154685065e-07,
|
|
||||||
"iqr": 1.0000803740695119e-08,
|
|
||||||
"q1": 6.099999154685065e-07,
|
|
||||||
"q3": 6.200007192092016e-07,
|
|
||||||
"iqr_outliers": 9309,
|
|
||||||
"stddev_outliers": 1236,
|
|
||||||
"outliers": "1236;9309",
|
|
||||||
"ld15iqr": 5.989986675558612e-07,
|
|
||||||
"hd15iqr": 6.389982445398346e-07,
|
|
||||||
"ops": 1523311.812151533,
|
|
||||||
"total": 0.05830585654985043,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_segmenter_speech_accumulation",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestSegmenterBenchmark::test_segmenter_speech_accumulation",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.92333337610277e-07,
|
|
||||||
"max": 1.8954433350396964e-05,
|
|
||||||
"mean": 6.502446459889802e-07,
|
|
||||||
"stddev": 6.140182926016494e-07,
|
|
||||||
"rounds": 69595,
|
|
||||||
"median": 4.1999998453926913e-07,
|
|
||||||
"iqr": 2.369997673667964e-08,
|
|
||||||
"q1": 4.1296668011151877e-07,
|
|
||||||
"q3": 4.366666568481984e-07,
|
|
||||||
"iqr_outliers": 12877,
|
|
||||||
"stddev_outliers": 7206,
|
|
||||||
"outliers": "7206;12877",
|
|
||||||
"ld15iqr": 3.92333337610277e-07,
|
|
||||||
"hd15iqr": 4.7229999230088043e-07,
|
|
||||||
"ops": 1537882.7125582318,
|
|
||||||
"total": 0.04525377613760308,
|
|
||||||
"iterations": 30
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_segmenter_transition_idle_to_speech",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestSegmenterBenchmark::test_segmenter_transition_idle_to_speech",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 9.800005500437692e-07,
|
|
||||||
"max": 0.001683107000644668,
|
|
||||||
"mean": 1.1487242486780888e-06,
|
|
||||||
"stddev": 6.228963542121108e-06,
|
|
||||||
"rounds": 74963,
|
|
||||||
"median": 1.0500007192604244e-06,
|
|
||||||
"iqr": 2.0001607481390238e-08,
|
|
||||||
"q1": 1.0399999155197293e-06,
|
|
||||||
"q3": 1.0600015230011195e-06,
|
|
||||||
"iqr_outliers": 4632,
|
|
||||||
"stddev_outliers": 209,
|
|
||||||
"outliers": "209;4632",
|
|
||||||
"ld15iqr": 1.0099993232870474e-06,
|
|
||||||
"hd15iqr": 1.0909989214269444e-06,
|
|
||||||
"ops": 870530.9399977972,
|
|
||||||
"total": 0.08611181585365557,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_get_rms",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestRmsLevelProviderBenchmark::test_get_rms",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.6690016713691875e-06,
|
|
||||||
"max": 8.10370002000127e-05,
|
|
||||||
"mean": 4.130748244247385e-06,
|
|
||||||
"stddev": 2.485301198628286e-06,
|
|
||||||
"rounds": 12794,
|
|
||||||
"median": 3.760000254260376e-06,
|
|
||||||
"iqr": 3.9999576983973384e-08,
|
|
||||||
"q1": 3.7400004657683894e-06,
|
|
||||||
"q3": 3.7800000427523628e-06,
|
|
||||||
"iqr_outliers": 1053,
|
|
||||||
"stddev_outliers": 342,
|
|
||||||
"outliers": "342;1053",
|
|
||||||
"ld15iqr": 3.6800011002924293e-06,
|
|
||||||
"hd15iqr": 3.840001227217726e-06,
|
|
||||||
"ops": 242086.891011243,
|
|
||||||
"total": 0.05284879303690104,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_get_db",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestRmsLevelProviderBenchmark::test_get_db",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.790000846493058e-06,
|
|
||||||
"max": 8.7697000708431e-05,
|
|
||||||
"mean": 4.408465139383066e-06,
|
|
||||||
"stddev": 2.99667632703755e-06,
|
|
||||||
"rounds": 23625,
|
|
||||||
"median": 3.920000381185673e-06,
|
|
||||||
"iqr": 4.100184014532715e-08,
|
|
||||||
"q1": 3.899998773704283e-06,
|
|
||||||
"q3": 3.94100061384961e-06,
|
|
||||||
"iqr_outliers": 2281,
|
|
||||||
"stddev_outliers": 606,
|
|
||||||
"outliers": "606;2281",
|
|
||||||
"ld15iqr": 3.838998964056373e-06,
|
|
||||||
"hd15iqr": 4.008999894722365e-06,
|
|
||||||
"ops": 226836.31794351517,
|
|
||||||
"total": 0.10414998891792493,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_rms_to_db_conversion",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestRmsLevelProviderBenchmark::test_rms_to_db_conversion",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 1.6821429328826654e-07,
|
|
||||||
"max": 2.489571475702438e-06,
|
|
||||||
"mean": 1.8857932409648374e-07,
|
|
||||||
"stddev": 6.388702698443576e-08,
|
|
||||||
"rounds": 196851,
|
|
||||||
"median": 1.7607141801688287e-07,
|
|
||||||
"iqr": 1.821458032022101e-09,
|
|
||||||
"q1": 1.7532140970745657e-07,
|
|
||||||
"q3": 1.7714286773947867e-07,
|
|
||||||
"iqr_outliers": 25379,
|
|
||||||
"stddev_outliers": 10574,
|
|
||||||
"outliers": "10574;25379",
|
|
||||||
"ld15iqr": 1.728214036640046e-07,
|
|
||||||
"hd15iqr": 1.7996425023219282e-07,
|
|
||||||
"ops": 5302808.273341595,
|
|
||||||
"total": 0.03712202852771692,
|
|
||||||
"iterations": 28
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_array_copy",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestNumpyOperationsBenchmark::test_array_copy",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 1.868000254034996e-07,
|
|
||||||
"max": 4.698279954027385e-06,
|
|
||||||
"mean": 2.0344677179673465e-07,
|
|
||||||
"stddev": 6.667938193365902e-08,
|
|
||||||
"rounds": 193799,
|
|
||||||
"median": 1.9279999833088368e-07,
|
|
||||||
"iqr": 2.400047378614549e-09,
|
|
||||||
"q1": 1.915999746415764e-07,
|
|
||||||
"q3": 1.9400002202019095e-07,
|
|
||||||
"iqr_outliers": 11953,
|
|
||||||
"stddev_outliers": 7096,
|
|
||||||
"outliers": "7096;11953",
|
|
||||||
"ld15iqr": 1.8799997633323074e-07,
|
|
||||||
"hd15iqr": 1.976399653358385e-07,
|
|
||||||
"ops": 4915290.575360459,
|
|
||||||
"total": 0.03942778092743538,
|
|
||||||
"iterations": 25
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_array_concatenate_small",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestNumpyOperationsBenchmark::test_array_concatenate_small",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 1.019998308038339e-06,
|
|
||||||
"max": 4.340899977250956e-05,
|
|
||||||
"mean": 1.1834804079043573e-06,
|
|
||||||
"stddev": 8.861083095740762e-07,
|
|
||||||
"rounds": 96071,
|
|
||||||
"median": 1.059999704011716e-06,
|
|
||||||
"iqr": 2.9998773243278265e-08,
|
|
||||||
"q1": 1.0500007192604244e-06,
|
|
||||||
"q3": 1.0799994925037026e-06,
|
|
||||||
"iqr_outliers": 8523,
|
|
||||||
"stddev_outliers": 1612,
|
|
||||||
"outliers": "1612;8523",
|
|
||||||
"ld15iqr": 1.019998308038339e-06,
|
|
||||||
"hd15iqr": 1.128999429056421e-06,
|
|
||||||
"ops": 844965.4031626476,
|
|
||||||
"total": 0.11369814626777952,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_array_concatenate_large",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestNumpyOperationsBenchmark::test_array_concatenate_large",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 2.999999196617864e-06,
|
|
||||||
"max": 3.1288000172935426e-05,
|
|
||||||
"mean": 3.3309941825889935e-06,
|
|
||||||
"stddev": 1.1706137650278387e-06,
|
|
||||||
"rounds": 26640,
|
|
||||||
"median": 3.2099997042678297e-06,
|
|
||||||
"iqr": 1.4000215742271394e-07,
|
|
||||||
"q1": 3.1299987313104793e-06,
|
|
||||||
"q3": 3.2700008887331933e-06,
|
|
||||||
"iqr_outliers": 727,
|
|
||||||
"stddev_outliers": 429,
|
|
||||||
"outliers": "429;727",
|
|
||||||
"ld15iqr": 2.999999196617864e-06,
|
|
||||||
"hd15iqr": 3.4889999369625002e-06,
|
|
||||||
"ops": 300210.67140464246,
|
|
||||||
"total": 0.08873768502417079,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_array_square",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestNumpyOperationsBenchmark::test_array_square",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.3599999369471336e-07,
|
|
||||||
"max": 3.1568999474984595e-06,
|
|
||||||
"mean": 3.5837566215609753e-07,
|
|
||||||
"stddev": 9.067377964642227e-08,
|
|
||||||
"rounds": 141443,
|
|
||||||
"median": 3.46000069839647e-07,
|
|
||||||
"iqr": 4.950015863869318e-09,
|
|
||||||
"q1": 3.440000000409782e-07,
|
|
||||||
"q3": 3.489500159048475e-07,
|
|
||||||
"iqr_outliers": 4615,
|
|
||||||
"stddev_outliers": 3055,
|
|
||||||
"outliers": "3055;4615",
|
|
||||||
"ld15iqr": 3.3745000109774993e-07,
|
|
||||||
"hd15iqr": 3.5644998206407765e-07,
|
|
||||||
"ops": 2790368.056758359,
|
|
||||||
"total": 0.0506897287823449,
|
|
||||||
"iterations": 20
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_array_mean",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestNumpyOperationsBenchmark::test_array_mean",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 2.67999894276727e-06,
|
|
||||||
"max": 5.860900091647636e-05,
|
|
||||||
"mean": 2.954065997680174e-06,
|
|
||||||
"stddev": 1.737545708579586e-06,
|
|
||||||
"rounds": 14363,
|
|
||||||
"median": 2.749999111983925e-06,
|
|
||||||
"iqr": 3.0999217415228486e-08,
|
|
||||||
"q1": 2.730001142481342e-06,
|
|
||||||
"q3": 2.7610003598965704e-06,
|
|
||||||
"iqr_outliers": 897,
|
|
||||||
"stddev_outliers": 283,
|
|
||||||
"outliers": "283;897",
|
|
||||||
"ld15iqr": 2.688999302336015e-06,
|
|
||||||
"hd15iqr": 2.8089998522773385e-06,
|
|
||||||
"ops": 338516.47213884164,
|
|
||||||
"total": 0.042429249924680335,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_list_append",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestBufferOperationsBenchmark::test_list_append",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 2.5500003175693564e-07,
|
|
||||||
"max": 0.0006309430000328575,
|
|
||||||
"mean": 3.0804353053803723e-06,
|
|
||||||
"stddev": 1.165474475076179e-05,
|
|
||||||
"rounds": 50356,
|
|
||||||
"median": 1.2219500604260248e-06,
|
|
||||||
"iqr": 5.370500730350612e-07,
|
|
||||||
"q1": 1.1269499736954459e-06,
|
|
||||||
"q3": 1.664000046730507e-06,
|
|
||||||
"iqr_outliers": 6448,
|
|
||||||
"stddev_outliers": 1234,
|
|
||||||
"outliers": "1234;6448",
|
|
||||||
"ld15iqr": 3.254500370530877e-07,
|
|
||||||
"hd15iqr": 2.470399977028137e-06,
|
|
||||||
"ops": 324629.44384950167,
|
|
||||||
"total": 0.15511840023773402,
|
|
||||||
"iterations": 20
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_list_clear",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestBufferOperationsBenchmark::test_list_clear",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.850000211969018e-06,
|
|
||||||
"max": 4.9208001655642875e-05,
|
|
||||||
"mean": 4.4985737419180015e-06,
|
|
||||||
"stddev": 1.841199779668339e-06,
|
|
||||||
"rounds": 132644,
|
|
||||||
"median": 4.05999890062958e-06,
|
|
||||||
"iqr": 7.100061338860542e-08,
|
|
||||||
"q1": 4.0289996832143515e-06,
|
|
||||||
"q3": 4.100000296602957e-06,
|
|
||||||
"iqr_outliers": 16629,
|
|
||||||
"stddev_outliers": 10011,
|
|
||||||
"outliers": "10011;16629",
|
|
||||||
"ld15iqr": 3.9289989217650145e-06,
|
|
||||||
"hd15iqr": 4.208999598631635e-06,
|
|
||||||
"ops": 222292.67705049165,
|
|
||||||
"total": 0.5967088154229714,
|
|
||||||
"iterations": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_sum_lengths_naive",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestBufferOperationsBenchmark::test_sum_lengths_naive",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 5.070000042906031e-07,
|
|
||||||
"max": 6.428855003832723e-05,
|
|
||||||
"mean": 5.806604613237722e-07,
|
|
||||||
"stddev": 2.6627529629995264e-07,
|
|
||||||
"rounds": 94340,
|
|
||||||
"median": 5.419999979494606e-07,
|
|
||||||
"iqr": 7.050039130263115e-09,
|
|
||||||
"q1": 5.389999387261923e-07,
|
|
||||||
"q3": 5.460499778564554e-07,
|
|
||||||
"iqr_outliers": 15957,
|
|
||||||
"stddev_outliers": 6262,
|
|
||||||
"outliers": "6262;15957",
|
|
||||||
"ld15iqr": 5.284499820845667e-07,
|
|
||||||
"hd15iqr": 5.569499990087934e-07,
|
|
||||||
"ops": 1722176.8427632046,
|
|
||||||
"total": 0.05477950792128468,
|
|
||||||
"iterations": 20
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": null,
|
|
||||||
"name": "test_cached_length",
|
|
||||||
"fullname": "tests/benchmarks/test_hot_paths.py::TestBufferOperationsBenchmark::test_cached_length",
|
|
||||||
"params": null,
|
|
||||||
"param": null,
|
|
||||||
"extra_info": {},
|
|
||||||
"options": {
|
|
||||||
"disable_gc": false,
|
|
||||||
"timer": "perf_counter",
|
|
||||||
"min_rounds": 5,
|
|
||||||
"max_time": 1.0,
|
|
||||||
"min_time": 5e-06,
|
|
||||||
"warmup": false
|
|
||||||
},
|
|
||||||
"stats": {
|
|
||||||
"min": 3.2465758933590036e-08,
|
|
||||||
"max": 5.197123331751368e-07,
|
|
||||||
"mean": 3.6134694196367755e-08,
|
|
||||||
"stddev": 9.28983695660366e-09,
|
|
||||||
"rounds": 198060,
|
|
||||||
"median": 3.452054418269417e-08,
|
|
||||||
"iqr": 4.1095455805451644e-10,
|
|
||||||
"q1": 3.431507313308268e-08,
|
|
||||||
"q3": 3.4726027691137196e-08,
|
|
||||||
"iqr_outliers": 19406,
|
|
||||||
"stddev_outliers": 10291,
|
|
||||||
"outliers": "10291;19406",
|
|
||||||
"ld15iqr": 3.3705474965095723e-08,
|
|
||||||
"hd15iqr": 3.5342465757634747e-08,
|
|
||||||
"ops": 27674234.478522852,
|
|
||||||
"total": 0.007156837532532597,
|
|
||||||
"iterations": 146
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"datetime": "2025-12-29T23:37:15.755048+00:00",
|
|
||||||
"version": "5.2.3"
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
18
.coveragerc
18
.coveragerc
@@ -1,18 +0,0 @@
|
|||||||
[run]
|
|
||||||
source = src/noteflow
|
|
||||||
omit =
|
|
||||||
*/grpc/proto/*
|
|
||||||
*/grpc/client.py
|
|
||||||
*/grpc/service.py
|
|
||||||
*/grpc/server.py
|
|
||||||
*/grpc/meeting_store.py
|
|
||||||
*/client/*
|
|
||||||
*/domain/ports/*
|
|
||||||
*/infrastructure/persistence/migrations/*
|
|
||||||
*/infrastructure/audio/playback.py
|
|
||||||
*/infrastructure/persistence/*
|
|
||||||
*/config/settings.py
|
|
||||||
|
|
||||||
[report]
|
|
||||||
precision = 2
|
|
||||||
show_missing = True
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,6 +12,7 @@ build/
|
|||||||
.mypy_cache/
|
.mypy_cache/
|
||||||
.ruff_cache/
|
.ruff_cache/
|
||||||
.coverage
|
.coverage
|
||||||
|
.coveragerc
|
||||||
htmlcov/
|
htmlcov/
|
||||||
*.egg
|
*.egg
|
||||||
.hygeine/
|
.hygeine/
|
||||||
|
|||||||
@@ -1,537 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"info": {
|
|
||||||
"title": "NoteFlow API",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Intelligent meeting notetaker API - real-time audio transcription, meeting management, and AI-powered summarization",
|
|
||||||
"protocol": "gRPC",
|
|
||||||
"package": "noteflow"
|
|
||||||
},
|
|
||||||
"service": {
|
|
||||||
"name": "NoteFlowService",
|
|
||||||
"description": "Main service providing real-time ASR streaming and meeting management"
|
|
||||||
},
|
|
||||||
"endpoints": {
|
|
||||||
"StreamTranscription": {
|
|
||||||
"type": "bidirectional_streaming",
|
|
||||||
"description": "Bidirectional streaming: client sends audio chunks, server returns transcripts in real-time",
|
|
||||||
"request": {
|
|
||||||
"type": "stream",
|
|
||||||
"message": "AudioChunk"
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"type": "stream",
|
|
||||||
"message": "TranscriptUpdate"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"CreateMeeting": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Create a new meeting session",
|
|
||||||
"request": "CreateMeetingRequest",
|
|
||||||
"response": "Meeting"
|
|
||||||
},
|
|
||||||
"StopMeeting": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Stop an active meeting recording",
|
|
||||||
"request": "StopMeetingRequest",
|
|
||||||
"response": "Meeting"
|
|
||||||
},
|
|
||||||
"ListMeetings": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "List meetings with optional filtering and pagination",
|
|
||||||
"request": "ListMeetingsRequest",
|
|
||||||
"response": "ListMeetingsResponse"
|
|
||||||
},
|
|
||||||
"GetMeeting": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Get a specific meeting by ID with optional transcript and summary",
|
|
||||||
"request": "GetMeetingRequest",
|
|
||||||
"response": "Meeting"
|
|
||||||
},
|
|
||||||
"DeleteMeeting": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Delete a meeting and all associated data",
|
|
||||||
"request": "DeleteMeetingRequest",
|
|
||||||
"response": "DeleteMeetingResponse"
|
|
||||||
},
|
|
||||||
"GenerateSummary": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Generate an AI-powered summary for a meeting",
|
|
||||||
"request": "GenerateSummaryRequest",
|
|
||||||
"response": "Summary"
|
|
||||||
},
|
|
||||||
"AddAnnotation": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Add a user annotation to a meeting (action item, decision, note, or risk)",
|
|
||||||
"request": "AddAnnotationRequest",
|
|
||||||
"response": "Annotation"
|
|
||||||
},
|
|
||||||
"GetAnnotation": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Get a specific annotation by ID",
|
|
||||||
"request": "GetAnnotationRequest",
|
|
||||||
"response": "Annotation"
|
|
||||||
},
|
|
||||||
"ListAnnotations": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "List all annotations for a meeting with optional time range filter",
|
|
||||||
"request": "ListAnnotationsRequest",
|
|
||||||
"response": "ListAnnotationsResponse"
|
|
||||||
},
|
|
||||||
"UpdateAnnotation": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Update an existing annotation",
|
|
||||||
"request": "UpdateAnnotationRequest",
|
|
||||||
"response": "Annotation"
|
|
||||||
},
|
|
||||||
"DeleteAnnotation": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Delete an annotation",
|
|
||||||
"request": "DeleteAnnotationRequest",
|
|
||||||
"response": "DeleteAnnotationResponse"
|
|
||||||
},
|
|
||||||
"ExportTranscript": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Export meeting transcript to Markdown or HTML format",
|
|
||||||
"request": "ExportTranscriptRequest",
|
|
||||||
"response": "ExportTranscriptResponse"
|
|
||||||
},
|
|
||||||
"RefineSpeakerDiarization": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Run offline speaker diarization to improve speaker labels (background job)",
|
|
||||||
"request": "RefineSpeakerDiarizationRequest",
|
|
||||||
"response": "RefineSpeakerDiarizationResponse"
|
|
||||||
},
|
|
||||||
"RenameSpeaker": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Rename a speaker ID to a human-readable name",
|
|
||||||
"request": "RenameSpeakerRequest",
|
|
||||||
"response": "RenameSpeakerResponse"
|
|
||||||
},
|
|
||||||
"GetDiarizationJobStatus": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Check status of a background diarization job",
|
|
||||||
"request": "GetDiarizationJobStatusRequest",
|
|
||||||
"response": "DiarizationJobStatus"
|
|
||||||
},
|
|
||||||
"GetServerInfo": {
|
|
||||||
"type": "unary",
|
|
||||||
"description": "Get server health and capabilities information",
|
|
||||||
"request": "ServerInfoRequest",
|
|
||||||
"response": "ServerInfo"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"enums": {
|
|
||||||
"UpdateType": {
|
|
||||||
"description": "Type of transcript update",
|
|
||||||
"values": {
|
|
||||||
"UPDATE_TYPE_UNSPECIFIED": { "value": 0, "description": "Default/unspecified" },
|
|
||||||
"UPDATE_TYPE_PARTIAL": { "value": 1, "description": "Tentative transcript, may change" },
|
|
||||||
"UPDATE_TYPE_FINAL": { "value": 2, "description": "Confirmed segment" },
|
|
||||||
"UPDATE_TYPE_VAD_START": { "value": 3, "description": "Voice activity started" },
|
|
||||||
"UPDATE_TYPE_VAD_END": { "value": 4, "description": "Voice activity ended" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MeetingState": {
|
|
||||||
"description": "Current state of a meeting",
|
|
||||||
"values": {
|
|
||||||
"MEETING_STATE_UNSPECIFIED": { "value": 0, "description": "Default/unspecified" },
|
|
||||||
"MEETING_STATE_CREATED": { "value": 1, "description": "Created but not started" },
|
|
||||||
"MEETING_STATE_RECORDING": { "value": 2, "description": "Actively recording audio" },
|
|
||||||
"MEETING_STATE_STOPPED": { "value": 3, "description": "Recording stopped, processing may continue" },
|
|
||||||
"MEETING_STATE_COMPLETED": { "value": 4, "description": "All processing complete" },
|
|
||||||
"MEETING_STATE_ERROR": { "value": 5, "description": "Error occurred" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"SortOrder": {
|
|
||||||
"description": "Sort order for listing meetings",
|
|
||||||
"values": {
|
|
||||||
"SORT_ORDER_UNSPECIFIED": { "value": 0, "description": "Default (newest first)" },
|
|
||||||
"SORT_ORDER_CREATED_DESC": { "value": 1, "description": "Newest first" },
|
|
||||||
"SORT_ORDER_CREATED_ASC": { "value": 2, "description": "Oldest first" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Priority": {
|
|
||||||
"description": "Priority level for action items",
|
|
||||||
"values": {
|
|
||||||
"PRIORITY_UNSPECIFIED": { "value": 0, "description": "Default/unspecified" },
|
|
||||||
"PRIORITY_LOW": { "value": 1, "description": "Low priority" },
|
|
||||||
"PRIORITY_MEDIUM": { "value": 2, "description": "Medium priority" },
|
|
||||||
"PRIORITY_HIGH": { "value": 3, "description": "High priority" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AnnotationType": {
|
|
||||||
"description": "Type of user annotation",
|
|
||||||
"values": {
|
|
||||||
"ANNOTATION_TYPE_UNSPECIFIED": { "value": 0, "description": "Default/unspecified" },
|
|
||||||
"ANNOTATION_TYPE_ACTION_ITEM": { "value": 1, "description": "Action item to be done" },
|
|
||||||
"ANNOTATION_TYPE_DECISION": { "value": 2, "description": "Decision made" },
|
|
||||||
"ANNOTATION_TYPE_NOTE": { "value": 3, "description": "General note" },
|
|
||||||
"ANNOTATION_TYPE_RISK": { "value": 4, "description": "Risk or concern" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ExportFormat": {
|
|
||||||
"description": "Transcript export format",
|
|
||||||
"values": {
|
|
||||||
"EXPORT_FORMAT_UNSPECIFIED": { "value": 0, "description": "Default/unspecified" },
|
|
||||||
"EXPORT_FORMAT_MARKDOWN": { "value": 1, "description": "Markdown format" },
|
|
||||||
"EXPORT_FORMAT_HTML": { "value": 2, "description": "HTML format" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"JobStatus": {
|
|
||||||
"description": "Background job status",
|
|
||||||
"values": {
|
|
||||||
"JOB_STATUS_UNSPECIFIED": { "value": 0, "description": "Default/unspecified" },
|
|
||||||
"JOB_STATUS_QUEUED": { "value": 1, "description": "Job is queued" },
|
|
||||||
"JOB_STATUS_RUNNING": { "value": 2, "description": "Job is running" },
|
|
||||||
"JOB_STATUS_COMPLETED": { "value": 3, "description": "Job completed successfully" },
|
|
||||||
"JOB_STATUS_FAILED": { "value": 4, "description": "Job failed" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"messages": {
|
|
||||||
"AudioChunk": {
|
|
||||||
"description": "Audio data chunk for streaming transcription",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "required": true, "description": "Meeting ID this audio belongs to" },
|
|
||||||
"audio_data": { "type": "bytes", "required": true, "description": "Raw audio data (float32, mono, 16kHz expected)" },
|
|
||||||
"timestamp": { "type": "double", "required": false, "description": "Timestamp when audio was captured (monotonic, seconds)" },
|
|
||||||
"sample_rate": { "type": "int32", "required": false, "default": 16000, "description": "Sample rate in Hz" },
|
|
||||||
"channels": { "type": "int32", "required": false, "default": 1, "description": "Number of channels (1 for mono)" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"TranscriptUpdate": {
|
|
||||||
"description": "Real-time transcript update from server",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "description": "Meeting ID this transcript belongs to" },
|
|
||||||
"update_type": { "type": "UpdateType", "description": "Type of update (partial, final, VAD events)" },
|
|
||||||
"partial_text": { "type": "string", "description": "For partial updates - tentative transcript text" },
|
|
||||||
"segment": { "type": "FinalSegment", "description": "For final updates - confirmed transcript segment" },
|
|
||||||
"server_timestamp": { "type": "double", "description": "Server-side processing timestamp" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"FinalSegment": {
|
|
||||||
"description": "Confirmed transcript segment with word-level timing",
|
|
||||||
"fields": {
|
|
||||||
"segment_id": { "type": "int32", "description": "Segment ID (sequential within meeting)" },
|
|
||||||
"text": { "type": "string", "description": "Transcript text" },
|
|
||||||
"start_time": { "type": "double", "description": "Start time relative to meeting start (seconds)" },
|
|
||||||
"end_time": { "type": "double", "description": "End time relative to meeting start (seconds)" },
|
|
||||||
"words": { "type": "array", "items": "WordTiming", "description": "Word-level timestamps" },
|
|
||||||
"language": { "type": "string", "description": "Detected language code" },
|
|
||||||
"language_confidence": { "type": "float", "description": "Language detection confidence (0.0-1.0)" },
|
|
||||||
"avg_logprob": { "type": "float", "description": "Average log probability (quality indicator)" },
|
|
||||||
"no_speech_prob": { "type": "float", "description": "Probability that segment contains no speech" },
|
|
||||||
"speaker_id": { "type": "string", "description": "Speaker identification (from diarization)" },
|
|
||||||
"speaker_confidence": { "type": "float", "description": "Speaker assignment confidence (0.0-1.0)" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"WordTiming": {
|
|
||||||
"description": "Word-level timing information",
|
|
||||||
"fields": {
|
|
||||||
"word": { "type": "string", "description": "The word text" },
|
|
||||||
"start_time": { "type": "double", "description": "Start time in seconds" },
|
|
||||||
"end_time": { "type": "double", "description": "End time in seconds" },
|
|
||||||
"probability": { "type": "float", "description": "Recognition confidence (0.0-1.0)" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Meeting": {
|
|
||||||
"description": "Complete meeting record with transcript and summary",
|
|
||||||
"fields": {
|
|
||||||
"id": { "type": "string", "description": "Unique meeting identifier (UUID)" },
|
|
||||||
"title": { "type": "string", "description": "User-provided or auto-generated title" },
|
|
||||||
"state": { "type": "MeetingState", "description": "Current meeting state" },
|
|
||||||
"created_at": { "type": "double", "description": "Creation timestamp (Unix epoch seconds)" },
|
|
||||||
"started_at": { "type": "double", "description": "Recording start timestamp" },
|
|
||||||
"ended_at": { "type": "double", "description": "Recording end timestamp" },
|
|
||||||
"duration_seconds": { "type": "double", "description": "Total duration in seconds" },
|
|
||||||
"segments": { "type": "array", "items": "FinalSegment", "description": "Full transcript segments" },
|
|
||||||
"summary": { "type": "Summary", "description": "Generated summary (if available)" },
|
|
||||||
"metadata": { "type": "map<string, string>", "description": "Custom metadata key-value pairs" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"CreateMeetingRequest": {
|
|
||||||
"description": "Request to create a new meeting",
|
|
||||||
"fields": {
|
|
||||||
"title": { "type": "string", "required": false, "description": "Optional title (auto-generated if not provided)" },
|
|
||||||
"metadata": { "type": "map<string, string>", "required": false, "description": "Optional custom metadata" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"StopMeetingRequest": {
|
|
||||||
"description": "Request to stop a meeting recording",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "required": true, "description": "Meeting ID to stop" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ListMeetingsRequest": {
|
|
||||||
"description": "Request to list meetings with filters",
|
|
||||||
"fields": {
|
|
||||||
"states": { "type": "array", "items": "MeetingState", "required": false, "description": "Filter by meeting states" },
|
|
||||||
"limit": { "type": "int32", "required": false, "default": 50, "description": "Max results to return" },
|
|
||||||
"offset": { "type": "int32", "required": false, "default": 0, "description": "Pagination offset" },
|
|
||||||
"sort_order": { "type": "SortOrder", "required": false, "default": "SORT_ORDER_CREATED_DESC", "description": "Sort order" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ListMeetingsResponse": {
|
|
||||||
"description": "Response containing list of meetings",
|
|
||||||
"fields": {
|
|
||||||
"meetings": { "type": "array", "items": "Meeting", "description": "List of meetings" },
|
|
||||||
"total_count": { "type": "int32", "description": "Total number of meetings matching filter" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"GetMeetingRequest": {
|
|
||||||
"description": "Request to get a specific meeting",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "required": true, "description": "Meeting ID to retrieve" },
|
|
||||||
"include_segments": { "type": "bool", "required": false, "default": false, "description": "Include full transcript segments" },
|
|
||||||
"include_summary": { "type": "bool", "required": false, "default": false, "description": "Include summary if available" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DeleteMeetingRequest": {
|
|
||||||
"description": "Request to delete a meeting",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "required": true, "description": "Meeting ID to delete" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DeleteMeetingResponse": {
|
|
||||||
"description": "Response confirming meeting deletion",
|
|
||||||
"fields": {
|
|
||||||
"success": { "type": "bool", "description": "Whether deletion was successful" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Summary": {
|
|
||||||
"description": "AI-generated meeting summary with evidence linking",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "description": "Meeting this summary belongs to" },
|
|
||||||
"executive_summary": { "type": "string", "description": "Executive summary (2-3 sentences)" },
|
|
||||||
"key_points": { "type": "array", "items": "KeyPoint", "description": "Key points/highlights extracted" },
|
|
||||||
"action_items": { "type": "array", "items": "ActionItem", "description": "Action items extracted" },
|
|
||||||
"generated_at": { "type": "double", "description": "Generation timestamp (Unix epoch)" },
|
|
||||||
"model_version": { "type": "string", "description": "Model/version used for generation" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"KeyPoint": {
|
|
||||||
"description": "Key point from meeting with evidence linking",
|
|
||||||
"fields": {
|
|
||||||
"text": { "type": "string", "description": "The key point text" },
|
|
||||||
"segment_ids": { "type": "array", "items": "int32", "description": "Segment IDs that support this point" },
|
|
||||||
"start_time": { "type": "double", "description": "Start of relevant time range" },
|
|
||||||
"end_time": { "type": "double", "description": "End of relevant time range" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ActionItem": {
|
|
||||||
"description": "Action item extracted from meeting",
|
|
||||||
"fields": {
|
|
||||||
"text": { "type": "string", "description": "Action item description" },
|
|
||||||
"assignee": { "type": "string", "description": "Person assigned (if mentioned)" },
|
|
||||||
"due_date": { "type": "double", "description": "Due date (Unix epoch, if mentioned)" },
|
|
||||||
"priority": { "type": "Priority", "description": "Priority level" },
|
|
||||||
"segment_ids": { "type": "array", "items": "int32", "description": "Segment IDs mentioning this action" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"GenerateSummaryRequest": {
|
|
||||||
"description": "Request to generate meeting summary",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "required": true, "description": "Meeting ID to summarize" },
|
|
||||||
"force_regenerate": { "type": "bool", "required": false, "default": false, "description": "Force regeneration even if summary exists" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Annotation": {
|
|
||||||
"description": "User-created annotation on meeting timeline",
|
|
||||||
"fields": {
|
|
||||||
"id": { "type": "string", "description": "Unique annotation identifier (UUID)" },
|
|
||||||
"meeting_id": { "type": "string", "description": "Meeting this annotation belongs to" },
|
|
||||||
"annotation_type": { "type": "AnnotationType", "description": "Type of annotation" },
|
|
||||||
"text": { "type": "string", "description": "Annotation text content" },
|
|
||||||
"start_time": { "type": "double", "description": "Start time relative to meeting start (seconds)" },
|
|
||||||
"end_time": { "type": "double", "description": "End time relative to meeting start (seconds)" },
|
|
||||||
"segment_ids": { "type": "array", "items": "int32", "description": "Linked transcript segment IDs" },
|
|
||||||
"created_at": { "type": "double", "description": "Creation timestamp (Unix epoch)" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AddAnnotationRequest": {
|
|
||||||
"description": "Request to add an annotation",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "required": true, "description": "Meeting ID to annotate" },
|
|
||||||
"annotation_type": { "type": "AnnotationType", "required": true, "description": "Type of annotation" },
|
|
||||||
"text": { "type": "string", "required": true, "description": "Annotation text" },
|
|
||||||
"start_time": { "type": "double", "required": true, "description": "Start time in seconds" },
|
|
||||||
"end_time": { "type": "double", "required": true, "description": "End time in seconds" },
|
|
||||||
"segment_ids": { "type": "array", "items": "int32", "required": false, "description": "Optional linked segment IDs" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"GetAnnotationRequest": {
|
|
||||||
"description": "Request to get an annotation",
|
|
||||||
"fields": {
|
|
||||||
"annotation_id": { "type": "string", "required": true, "description": "Annotation ID to retrieve" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ListAnnotationsRequest": {
|
|
||||||
"description": "Request to list annotations for a meeting",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "required": true, "description": "Meeting ID to list annotations for" },
|
|
||||||
"start_time": { "type": "double", "required": false, "description": "Filter: start of time range" },
|
|
||||||
"end_time": { "type": "double", "required": false, "description": "Filter: end of time range" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ListAnnotationsResponse": {
|
|
||||||
"description": "Response containing annotations",
|
|
||||||
"fields": {
|
|
||||||
"annotations": { "type": "array", "items": "Annotation", "description": "List of annotations" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"UpdateAnnotationRequest": {
|
|
||||||
"description": "Request to update an annotation",
|
|
||||||
"fields": {
|
|
||||||
"annotation_id": { "type": "string", "required": true, "description": "Annotation ID to update" },
|
|
||||||
"annotation_type": { "type": "AnnotationType", "required": false, "description": "New type (keeps existing if not set)" },
|
|
||||||
"text": { "type": "string", "required": false, "description": "New text (keeps existing if empty)" },
|
|
||||||
"start_time": { "type": "double", "required": false, "description": "New start time (keeps existing if 0)" },
|
|
||||||
"end_time": { "type": "double", "required": false, "description": "New end time (keeps existing if 0)" },
|
|
||||||
"segment_ids": { "type": "array", "items": "int32", "required": false, "description": "New segment IDs (replaces existing)" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DeleteAnnotationRequest": {
|
|
||||||
"description": "Request to delete an annotation",
|
|
||||||
"fields": {
|
|
||||||
"annotation_id": { "type": "string", "required": true, "description": "Annotation ID to delete" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DeleteAnnotationResponse": {
|
|
||||||
"description": "Response confirming annotation deletion",
|
|
||||||
"fields": {
|
|
||||||
"success": { "type": "bool", "description": "Whether deletion was successful" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ExportTranscriptRequest": {
|
|
||||||
"description": "Request to export meeting transcript",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "required": true, "description": "Meeting ID to export" },
|
|
||||||
"format": { "type": "ExportFormat", "required": true, "description": "Export format (Markdown or HTML)" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ExportTranscriptResponse": {
|
|
||||||
"description": "Response containing exported transcript",
|
|
||||||
"fields": {
|
|
||||||
"content": { "type": "string", "description": "Exported content as string" },
|
|
||||||
"format_name": { "type": "string", "description": "Human-readable format name" },
|
|
||||||
"file_extension": { "type": "string", "description": "Suggested file extension (.md or .html)" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RefineSpeakerDiarizationRequest": {
|
|
||||||
"description": "Request to run offline speaker diarization",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "required": true, "description": "Meeting ID to process" },
|
|
||||||
"num_speakers": { "type": "int32", "required": false, "description": "Known number of speakers (auto-detect if 0)" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RefineSpeakerDiarizationResponse": {
|
|
||||||
"description": "Response from diarization job start",
|
|
||||||
"fields": {
|
|
||||||
"segments_updated": { "type": "int32", "description": "Number of segments updated (0 if job is async)" },
|
|
||||||
"speaker_ids": { "type": "array", "items": "string", "description": "Distinct speaker IDs found" },
|
|
||||||
"error_message": { "type": "string", "description": "Error message if failed" },
|
|
||||||
"job_id": { "type": "string", "description": "Background job ID for polling" },
|
|
||||||
"status": { "type": "JobStatus", "description": "Current job status" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RenameSpeakerRequest": {
|
|
||||||
"description": "Request to rename a speaker",
|
|
||||||
"fields": {
|
|
||||||
"meeting_id": { "type": "string", "required": true, "description": "Meeting ID" },
|
|
||||||
"old_speaker_id": { "type": "string", "required": true, "description": "Original speaker ID (e.g., 'SPEAKER_00')" },
|
|
||||||
"new_speaker_name": { "type": "string", "required": true, "description": "New human-readable name (e.g., 'Alice')" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RenameSpeakerResponse": {
|
|
||||||
"description": "Response from speaker rename",
|
|
||||||
"fields": {
|
|
||||||
"segments_updated": { "type": "int32", "description": "Number of segments updated" },
|
|
||||||
"success": { "type": "bool", "description": "Whether rename was successful" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"GetDiarizationJobStatusRequest": {
|
|
||||||
"description": "Request to check diarization job status",
|
|
||||||
"fields": {
|
|
||||||
"job_id": { "type": "string", "required": true, "description": "Job ID from RefineSpeakerDiarization" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DiarizationJobStatus": {
|
|
||||||
"description": "Status of a diarization job",
|
|
||||||
"fields": {
|
|
||||||
"job_id": { "type": "string", "description": "Job ID" },
|
|
||||||
"status": { "type": "JobStatus", "description": "Current status" },
|
|
||||||
"segments_updated": { "type": "int32", "description": "Segments updated (when completed)" },
|
|
||||||
"speaker_ids": { "type": "array", "items": "string", "description": "Speaker IDs found (when completed)" },
|
|
||||||
"error_message": { "type": "string", "description": "Error message if failed" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ServerInfoRequest": {
|
|
||||||
"description": "Request for server info (empty message)",
|
|
||||||
"fields": {}
|
|
||||||
},
|
|
||||||
"ServerInfo": {
|
|
||||||
"description": "Server health and capabilities",
|
|
||||||
"fields": {
|
|
||||||
"version": { "type": "string", "description": "Server version string" },
|
|
||||||
"asr_model": { "type": "string", "description": "Loaded ASR model name" },
|
|
||||||
"asr_ready": { "type": "bool", "description": "Whether ASR is ready" },
|
|
||||||
"supported_sample_rates": { "type": "array", "items": "int32", "description": "Supported audio sample rates" },
|
|
||||||
"max_chunk_size": { "type": "int32", "description": "Maximum audio chunk size in bytes" },
|
|
||||||
"uptime_seconds": { "type": "double", "description": "Server uptime in seconds" },
|
|
||||||
"active_meetings": { "type": "int32", "description": "Number of active meetings" },
|
|
||||||
"diarization_enabled": { "type": "bool", "description": "Whether diarization is enabled" },
|
|
||||||
"diarization_ready": { "type": "bool", "description": "Whether diarization models are ready" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"uiHints": {
|
|
||||||
"primaryEntities": ["Meeting", "Summary", "Annotation"],
|
|
||||||
"listViews": {
|
|
||||||
"meetings": {
|
|
||||||
"endpoint": "ListMeetings",
|
|
||||||
"displayFields": ["title", "state", "created_at", "duration_seconds"],
|
|
||||||
"actions": ["view", "delete", "export"]
|
|
||||||
},
|
|
||||||
"annotations": {
|
|
||||||
"endpoint": "ListAnnotations",
|
|
||||||
"displayFields": ["annotation_type", "text", "start_time"],
|
|
||||||
"actions": ["edit", "delete"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"detailViews": {
|
|
||||||
"meeting": {
|
|
||||||
"endpoint": "GetMeeting",
|
|
||||||
"sections": [
|
|
||||||
{ "name": "Overview", "fields": ["title", "state", "created_at", "duration_seconds"] },
|
|
||||||
{ "name": "Transcript", "field": "segments", "type": "timeline" },
|
|
||||||
{ "name": "Summary", "field": "summary", "type": "expandable" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"forms": {
|
|
||||||
"createMeeting": {
|
|
||||||
"endpoint": "CreateMeeting",
|
|
||||||
"fields": [
|
|
||||||
{ "name": "title", "label": "Meeting Title", "type": "text", "placeholder": "Optional - will be auto-generated" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"addAnnotation": {
|
|
||||||
"endpoint": "AddAnnotation",
|
|
||||||
"fields": [
|
|
||||||
{ "name": "annotation_type", "label": "Type", "type": "select", "options": "AnnotationType" },
|
|
||||||
{ "name": "text", "label": "Note", "type": "textarea" },
|
|
||||||
{ "name": "start_time", "label": "Start Time", "type": "number" },
|
|
||||||
{ "name": "end_time", "label": "End Time", "type": "number" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"realTimeFeatures": {
|
|
||||||
"transcription": {
|
|
||||||
"endpoint": "StreamTranscription",
|
|
||||||
"description": "Real-time audio-to-text with live updates",
|
|
||||||
"updateTypes": ["partial", "final", "vad_start", "vad_end"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
3677
repomix-output.md
3677
repomix-output.md
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
|||||||
from typing import Any
|
|
||||||
|
|
||||||
|
|
||||||
def process(data: Any) -> Any:
|
|
||||||
result: Any = data
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def store(items: dict[str, Any]) -> None:
|
|
||||||
pass
|
|
||||||
Reference in New Issue
Block a user