rird 1.0.200
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +27 -0
- package/Dockerfile +18 -0
- package/README.md +15 -0
- package/bin/opencode +336 -0
- package/bin/pty-wrapper.js +285 -0
- package/bunfig.toml +4 -0
- package/facebook_ads_library.png +0 -0
- package/nul`nif +0 -0
- package/package.json +111 -0
- package/parsers-config.ts +239 -0
- package/rird-1.0.199.tgz +0 -0
- package/script/build-windows.ts +54 -0
- package/script/build.ts +167 -0
- package/script/postinstall.mjs +544 -0
- package/script/publish-registries.ts +187 -0
- package/script/publish.ts +72 -0
- package/script/schema.ts +47 -0
- package/src/acp/README.md +164 -0
- package/src/acp/agent.ts +1063 -0
- package/src/acp/session.ts +101 -0
- package/src/acp/types.ts +22 -0
- package/src/agent/agent.ts +367 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/compaction.txt +12 -0
- package/src/agent/prompt/explore.txt +18 -0
- package/src/agent/prompt/summary.txt +10 -0
- package/src/agent/prompt/title.txt +36 -0
- package/src/auth/index.ts +70 -0
- package/src/bun/index.ts +114 -0
- package/src/bus/bus-event.ts +43 -0
- package/src/bus/global.ts +10 -0
- package/src/bus/index.ts +105 -0
- package/src/cli/bootstrap.ts +17 -0
- package/src/cli/cmd/acp.ts +88 -0
- package/src/cli/cmd/agent.ts +256 -0
- package/src/cli/cmd/auth.ts +391 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/debug/config.ts +15 -0
- package/src/cli/cmd/debug/file.ts +91 -0
- package/src/cli/cmd/debug/index.ts +43 -0
- package/src/cli/cmd/debug/lsp.ts +48 -0
- package/src/cli/cmd/debug/ripgrep.ts +83 -0
- package/src/cli/cmd/debug/scrap.ts +15 -0
- package/src/cli/cmd/debug/skill.ts +15 -0
- package/src/cli/cmd/debug/snapshot.ts +48 -0
- package/src/cli/cmd/export.ts +88 -0
- package/src/cli/cmd/generate.ts +38 -0
- package/src/cli/cmd/github.ts +1400 -0
- package/src/cli/cmd/import.ts +98 -0
- package/src/cli/cmd/mcp.ts +654 -0
- package/src/cli/cmd/models.ts +77 -0
- package/src/cli/cmd/pr.ts +112 -0
- package/src/cli/cmd/run.ts +368 -0
- package/src/cli/cmd/serve.ts +31 -0
- package/src/cli/cmd/session.ts +106 -0
- package/src/cli/cmd/stats.ts +298 -0
- package/src/cli/cmd/tui/app.tsx +696 -0
- package/src/cli/cmd/tui/attach.ts +30 -0
- package/src/cli/cmd/tui/component/border.tsx +21 -0
- package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-command.tsx +124 -0
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-model.tsx +245 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +224 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +102 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-stash.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +162 -0
- package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
- package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
- package/src/cli/cmd/tui/component/did-you-know.tsx +85 -0
- package/src/cli/cmd/tui/component/logo.tsx +35 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +574 -0
- package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
- package/src/cli/cmd/tui/component/prompt/index.tsx +1090 -0
- package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
- package/src/cli/cmd/tui/component/tips.ts +27 -0
- package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
- package/src/cli/cmd/tui/context/args.tsx +14 -0
- package/src/cli/cmd/tui/context/directory.ts +13 -0
- package/src/cli/cmd/tui/context/exit.tsx +23 -0
- package/src/cli/cmd/tui/context/helper.tsx +25 -0
- package/src/cli/cmd/tui/context/keybind.tsx +101 -0
- package/src/cli/cmd/tui/context/kv.tsx +49 -0
- package/src/cli/cmd/tui/context/local.tsx +354 -0
- package/src/cli/cmd/tui/context/prompt.tsx +18 -0
- package/src/cli/cmd/tui/context/route.tsx +46 -0
- package/src/cli/cmd/tui/context/sdk.tsx +74 -0
- package/src/cli/cmd/tui/context/sync.tsx +372 -0
- package/src/cli/cmd/tui/context/theme/aura.json +69 -0
- package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
- package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
- package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
- package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
- package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
- package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
- package/src/cli/cmd/tui/context/theme/github.json +233 -0
- package/src/cli/cmd/tui/context/theme/gruvbox.json +95 -0
- package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
- package/src/cli/cmd/tui/context/theme/lucent-orng.json +227 -0
- package/src/cli/cmd/tui/context/theme/material.json +235 -0
- package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
- package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
- package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
- package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
- package/src/cli/cmd/tui/context/theme/nord.json +223 -0
- package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
- package/src/cli/cmd/tui/context/theme/orng.json +245 -0
- package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
- package/src/cli/cmd/tui/context/theme/rird.json +245 -0
- package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
- package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
- package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
- package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
- package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
- package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
- package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
- package/src/cli/cmd/tui/context/theme.tsx +1109 -0
- package/src/cli/cmd/tui/event.ts +40 -0
- package/src/cli/cmd/tui/routes/home.tsx +138 -0
- package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
- package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
- package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
- package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
- package/src/cli/cmd/tui/routes/session/footer.tsx +88 -0
- package/src/cli/cmd/tui/routes/session/header.tsx +125 -0
- package/src/cli/cmd/tui/routes/session/index.tsx +1864 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +318 -0
- package/src/cli/cmd/tui/spawn.ts +60 -0
- package/src/cli/cmd/tui/thread.ts +142 -0
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +57 -0
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +83 -0
- package/src/cli/cmd/tui/ui/dialog-help.tsx +38 -0
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +77 -0
- package/src/cli/cmd/tui/ui/dialog-select.tsx +332 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +170 -0
- package/src/cli/cmd/tui/ui/spinner.ts +368 -0
- package/src/cli/cmd/tui/ui/toast.tsx +100 -0
- package/src/cli/cmd/tui/util/clipboard.ts +127 -0
- package/src/cli/cmd/tui/util/editor.ts +32 -0
- package/src/cli/cmd/tui/util/terminal.ts +114 -0
- package/src/cli/cmd/tui/worker.ts +63 -0
- package/src/cli/cmd/uninstall.ts +344 -0
- package/src/cli/cmd/upgrade.ts +100 -0
- package/src/cli/cmd/web.ts +84 -0
- package/src/cli/error.ts +56 -0
- package/src/cli/ui.ts +84 -0
- package/src/cli/upgrade.ts +25 -0
- package/src/command/index.ts +80 -0
- package/src/command/template/initialize.txt +10 -0
- package/src/command/template/review.txt +97 -0
- package/src/config/config.ts +995 -0
- package/src/config/markdown.ts +41 -0
- package/src/env/index.ts +26 -0
- package/src/file/ignore.ts +83 -0
- package/src/file/index.ts +328 -0
- package/src/file/ripgrep.ts +393 -0
- package/src/file/time.ts +64 -0
- package/src/file/watcher.ts +103 -0
- package/src/flag/flag.ts +46 -0
- package/src/format/formatter.ts +315 -0
- package/src/format/index.ts +137 -0
- package/src/global/index.ts +52 -0
- package/src/id/id.ts +73 -0
- package/src/ide/index.ts +76 -0
- package/src/index.ts +240 -0
- package/src/installation/index.ts +239 -0
- package/src/lsp/client.ts +229 -0
- package/src/lsp/index.ts +485 -0
- package/src/lsp/language.ts +116 -0
- package/src/lsp/server.ts +1895 -0
- package/src/mcp/auth.ts +135 -0
- package/src/mcp/index.ts +690 -0
- package/src/mcp/oauth-callback.ts +200 -0
- package/src/mcp/oauth-provider.ts +154 -0
- package/src/patch/index.ts +622 -0
- package/src/permission/index.ts +199 -0
- package/src/plugin/index.ts +91 -0
- package/src/project/bootstrap.ts +31 -0
- package/src/project/instance.ts +78 -0
- package/src/project/project.ts +221 -0
- package/src/project/state.ts +65 -0
- package/src/project/vcs.ts +76 -0
- package/src/provider/auth.ts +143 -0
- package/src/provider/models-macro.ts +11 -0
- package/src/provider/models.ts +106 -0
- package/src/provider/provider.ts +1071 -0
- package/src/provider/sdk/openai-compatible/src/README.md +5 -0
- package/src/provider/sdk/openai-compatible/src/index.ts +2 -0
- package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +100 -0
- package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +303 -0
- package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +18 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +22 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +207 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +1713 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +177 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +1 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +88 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +128 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +115 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +65 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +104 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +103 -0
- package/src/provider/transform.ts +455 -0
- package/src/pty/index.ts +231 -0
- package/src/security/guardrails.test.ts +341 -0
- package/src/security/guardrails.ts +558 -0
- package/src/security/index.ts +19 -0
- package/src/server/error.ts +36 -0
- package/src/server/project.ts +79 -0
- package/src/server/server.ts +2642 -0
- package/src/server/tui.ts +71 -0
- package/src/session/compaction.ts +223 -0
- package/src/session/index.ts +461 -0
- package/src/session/llm.ts +201 -0
- package/src/session/message-v2.ts +690 -0
- package/src/session/message.ts +189 -0
- package/src/session/processor.ts +409 -0
- package/src/session/prompt/act-switch.txt +5 -0
- package/src/session/prompt/anthropic-20250930.txt +166 -0
- package/src/session/prompt/anthropic.txt +85 -0
- package/src/session/prompt/anthropic_spoof.txt +1 -0
- package/src/session/prompt/beast.txt +103 -0
- package/src/session/prompt/codex.txt +304 -0
- package/src/session/prompt/copilot-gpt-5.txt +138 -0
- package/src/session/prompt/gemini.txt +85 -0
- package/src/session/prompt/max-steps.txt +16 -0
- package/src/session/prompt/plan-reminder-anthropic.txt +35 -0
- package/src/session/prompt/plan.txt +24 -0
- package/src/session/prompt/polaris.txt +84 -0
- package/src/session/prompt/qwen.txt +106 -0
- package/src/session/prompt.ts +1509 -0
- package/src/session/retry.ts +86 -0
- package/src/session/revert.ts +108 -0
- package/src/session/sensitive-filter.test.ts +327 -0
- package/src/session/sensitive-filter.ts +466 -0
- package/src/session/status.ts +76 -0
- package/src/session/summary.ts +194 -0
- package/src/session/system.ts +120 -0
- package/src/session/todo.ts +37 -0
- package/src/share/share-next.ts +194 -0
- package/src/share/share.ts +87 -0
- package/src/shell/shell.ts +67 -0
- package/src/skill/index.ts +1 -0
- package/src/skill/skill.ts +83 -0
- package/src/snapshot/index.ts +197 -0
- package/src/storage/storage.ts +226 -0
- package/src/tests/agent.test.ts +308 -0
- package/src/tests/build-guards.test.ts +267 -0
- package/src/tests/config.test.ts +664 -0
- package/src/tests/tool-registry.test.ts +589 -0
- package/src/tool/bash.ts +317 -0
- package/src/tool/bash.txt +158 -0
- package/src/tool/batch.ts +175 -0
- package/src/tool/batch.txt +24 -0
- package/src/tool/codesearch.ts +168 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/edit.ts +675 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/glob.ts +65 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +121 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/invalid.ts +17 -0
- package/src/tool/ls.ts +110 -0
- package/src/tool/ls.txt +1 -0
- package/src/tool/lsp-diagnostics.ts +26 -0
- package/src/tool/lsp-diagnostics.txt +1 -0
- package/src/tool/lsp-hover.ts +31 -0
- package/src/tool/lsp-hover.txt +1 -0
- package/src/tool/lsp.ts +87 -0
- package/src/tool/lsp.txt +19 -0
- package/src/tool/multiedit.ts +46 -0
- package/src/tool/multiedit.txt +41 -0
- package/src/tool/patch.ts +233 -0
- package/src/tool/patch.txt +1 -0
- package/src/tool/read.ts +219 -0
- package/src/tool/read.txt +12 -0
- package/src/tool/registry.ts +162 -0
- package/src/tool/skill.ts +100 -0
- package/src/tool/task.ts +136 -0
- package/src/tool/task.txt +51 -0
- package/src/tool/todo.ts +39 -0
- package/src/tool/todoread.txt +14 -0
- package/src/tool/todowrite.txt +167 -0
- package/src/tool/tool.ts +71 -0
- package/src/tool/webfetch.ts +198 -0
- package/src/tool/webfetch.txt +13 -0
- package/src/tool/websearch.ts +180 -0
- package/src/tool/websearch.txt +11 -0
- package/src/tool/write.ts +110 -0
- package/src/tool/write.txt +8 -0
- package/src/util/archive.ts +16 -0
- package/src/util/color.ts +19 -0
- package/src/util/context.ts +25 -0
- package/src/util/defer.ts +12 -0
- package/src/util/eventloop.ts +20 -0
- package/src/util/filesystem.ts +83 -0
- package/src/util/fn.ts +11 -0
- package/src/util/iife.ts +3 -0
- package/src/util/keybind.ts +102 -0
- package/src/util/lazy.ts +11 -0
- package/src/util/license.ts +325 -0
- package/src/util/locale.ts +81 -0
- package/src/util/lock.ts +98 -0
- package/src/util/log.ts +180 -0
- package/src/util/queue.ts +32 -0
- package/src/util/rpc.ts +42 -0
- package/src/util/scrap.ts +10 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +14 -0
- package/src/util/token.ts +7 -0
- package/src/util/wildcard.ts +54 -0
- package/sst-env.d.ts +9 -0
- package/test/agent/agent.test.ts +146 -0
- package/test/bun.test.ts +53 -0
- package/test/cli/github-remote.test.ts +80 -0
- package/test/config/agent-color.test.ts +66 -0
- package/test/config/config.test.ts +535 -0
- package/test/config/markdown.test.ts +89 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/fixture/fixture.ts +36 -0
- package/test/fixture/lsp/fake-lsp-server.js +77 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/keybind.test.ts +421 -0
- package/test/lsp/client.test.ts +95 -0
- package/test/mcp/headers.test.ts +153 -0
- package/test/patch/patch.test.ts +348 -0
- package/test/preload.ts +57 -0
- package/test/project/project.test.ts +72 -0
- package/test/provider/provider.test.ts +1809 -0
- package/test/provider/transform.test.ts +411 -0
- package/test/session/retry.test.ts +111 -0
- package/test/session/session.test.ts +71 -0
- package/test/skill/skill.test.ts +131 -0
- package/test/snapshot/snapshot.test.ts +939 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/bash.test.ts +434 -0
- package/test/tool/grep.test.ts +108 -0
- package/test/tool/patch.test.ts +259 -0
- package/test/tool/read.test.ts +42 -0
- package/test/util/iife.test.ts +36 -0
- package/test/util/lazy.test.ts +50 -0
- package/test/util/timeout.test.ts +21 -0
- package/test/util/wildcard.test.ts +55 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safety Guardrails for RIRD Agent
|
|
3
|
+
*
|
|
4
|
+
* Prevents misuse by blocking:
|
|
5
|
+
* - Malicious task descriptions
|
|
6
|
+
* - Dangerous target domains
|
|
7
|
+
* - Destructive system commands
|
|
8
|
+
* - Financial transactions (sending money)
|
|
9
|
+
* - Data deletion operations
|
|
10
|
+
* - Prompt injection attempts
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import fs from "fs"
|
|
14
|
+
import path from "path"
|
|
15
|
+
import os from "os"
|
|
16
|
+
|
|
17
|
+
// Security audit log path - uses XDG data dir pattern
|
|
18
|
+
const SECURITY_LOG_DIR = path.join(
|
|
19
|
+
process.env.XDG_DATA_HOME || path.join(os.homedir(), ".local", "share"),
|
|
20
|
+
"rird",
|
|
21
|
+
"security"
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
// Ensure security log directory exists
|
|
25
|
+
try {
|
|
26
|
+
fs.mkdirSync(SECURITY_LOG_DIR, { recursive: true })
|
|
27
|
+
} catch {
|
|
28
|
+
// Directory may already exist or permissions issue - will fallback to console only
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Domains that should NEVER be automated against (high fraud/harm risk)
|
|
32
|
+
// NOTE: This is a MINIMAL blocklist - we allow most sites for legitimate work
|
|
33
|
+
// The intent detection layer catches malicious USE of any site
|
|
34
|
+
export const BLOCKED_DOMAINS = new Set([
|
|
35
|
+
// Banking & Financial (fraud risk - transactions require human oversight)
|
|
36
|
+
"chase.com",
|
|
37
|
+
"bankofamerica.com",
|
|
38
|
+
"wellsfargo.com",
|
|
39
|
+
"citibank.com",
|
|
40
|
+
"capitalone.com",
|
|
41
|
+
|
|
42
|
+
// Crypto exchanges (irreversible transactions)
|
|
43
|
+
"coinbase.com",
|
|
44
|
+
"binance.com",
|
|
45
|
+
"kraken.com",
|
|
46
|
+
|
|
47
|
+
// Government identity (identity theft risk)
|
|
48
|
+
"irs.gov",
|
|
49
|
+
"ssa.gov",
|
|
50
|
+
"login.gov",
|
|
51
|
+
"id.me",
|
|
52
|
+
])
|
|
53
|
+
|
|
54
|
+
// ALLOWED for legitimate AI worker use:
|
|
55
|
+
// - Email (Gmail, Outlook, Yahoo, etc.) - essential for communication
|
|
56
|
+
// - Social media (LinkedIn, Twitter, Facebook) - outreach and engagement
|
|
57
|
+
// - E-commerce (Amazon, eBay, etc.) - shopping and research
|
|
58
|
+
// - Healthcare portals - appointment booking, etc.
|
|
59
|
+
// - Payment services (PayPal, Venmo) - with user oversight
|
|
60
|
+
|
|
61
|
+
// Patterns that indicate malicious intent
|
|
62
|
+
export const MALICIOUS_PATTERNS = [
|
|
63
|
+
// Credential harvesting
|
|
64
|
+
/harvest.*(password|credential|key|token|secret)/i,
|
|
65
|
+
/steal.*(password|credential|key|token|secret|data|info)/i,
|
|
66
|
+
/scrape.*(password|credential|key|token|login)/i,
|
|
67
|
+
/extract.*(password|credential|key|token|cookie)/i,
|
|
68
|
+
/dump.*(password|credential|database|cookie)/i,
|
|
69
|
+
/capture.*(keystroke|keylog|password)/i,
|
|
70
|
+
|
|
71
|
+
// Account compromise
|
|
72
|
+
/brute.?force/i,
|
|
73
|
+
/crack.*(password|hash|account)/i,
|
|
74
|
+
/bypass.*(auth|2fa|mfa|captcha|security)/i,
|
|
75
|
+
/hijack.*(session|account|cookie)/i,
|
|
76
|
+
/takeover.*(account)/i,
|
|
77
|
+
|
|
78
|
+
// Data exfiltration
|
|
79
|
+
/exfiltrate/i,
|
|
80
|
+
/mass.?download.*(data|user|profile)/i,
|
|
81
|
+
/bulk.?scrape.*(email|phone|contact|profile)/i,
|
|
82
|
+
/harvest.*(email|phone|contact|pii)/i,
|
|
83
|
+
|
|
84
|
+
// Malware/attacks
|
|
85
|
+
/inject.*(malware|virus|trojan|payload)/i,
|
|
86
|
+
/deploy.*(rat|backdoor|rootkit)/i,
|
|
87
|
+
/ransomware/i,
|
|
88
|
+
/cryptojack/i,
|
|
89
|
+
/ddos|dos.?attack/i,
|
|
90
|
+
/phish/i,
|
|
91
|
+
/spoof/i,
|
|
92
|
+
|
|
93
|
+
// Fraud
|
|
94
|
+
/fake.*(account|identity|profile)/i,
|
|
95
|
+
/impersonate/i,
|
|
96
|
+
/catfish/i,
|
|
97
|
+
/scam/i,
|
|
98
|
+
/fraud/i,
|
|
99
|
+
|
|
100
|
+
// Illegal activities
|
|
101
|
+
/illegal/i,
|
|
102
|
+
/dark.?web/i,
|
|
103
|
+
/black.?market/i,
|
|
104
|
+
/launder/i,
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
// CRITICAL SAFETY BLOCKS - These actions are IRREVERSIBLE or CATASTROPHIC
|
|
108
|
+
// RIRD is autonomous for SAFE actions, but BLOCKS dangerous ones outright
|
|
109
|
+
// No confirmation dialogs - just refuses dangerous actions
|
|
110
|
+
export const CRITICAL_DANGER_PATTERNS = [
|
|
111
|
+
// ============ VIOLENCE/WEAPONS ============
|
|
112
|
+
/kill/i,
|
|
113
|
+
/murder/i,
|
|
114
|
+
/assassinate/i,
|
|
115
|
+
/bomb/i,
|
|
116
|
+
/weapon/i,
|
|
117
|
+
/terroris/i,
|
|
118
|
+
/shoot\s+(them|him|her|the|a\s+person)/i,
|
|
119
|
+
/stab/i,
|
|
120
|
+
/poison/i,
|
|
121
|
+
/explode/i,
|
|
122
|
+
/detonate/i,
|
|
123
|
+
/attack\s+.*(person|people|target|victim|user)/i,
|
|
124
|
+
/harm\s+.*(person|people|target|victim)/i,
|
|
125
|
+
/stalk\s+.*(person|target|victim|them|him|her)/i,
|
|
126
|
+
/harass\s+.*(person|target|victim|them|him|her)/i,
|
|
127
|
+
/doxx/i,
|
|
128
|
+
/swat/i,
|
|
129
|
+
/threaten\s+.*(person|target|victim)/i,
|
|
130
|
+
/target\s+(these|those|the|all)\s*(person|people|user|victim)/i,
|
|
131
|
+
|
|
132
|
+
// ============ MONEY/FINANCIAL ============
|
|
133
|
+
// Block ALL money sending - too risky if agent compromised
|
|
134
|
+
/send\s+(money|funds|payment|\$\d)/i,
|
|
135
|
+
/transfer\s+(money|funds|\$\d)/i,
|
|
136
|
+
/wire\s+(money|funds|transfer)/i,
|
|
137
|
+
/pay\s+(them|someone|him|her|\$\d)/i,
|
|
138
|
+
/venmo\s+(send|pay|transfer)/i,
|
|
139
|
+
/zelle\s+(send|pay|transfer)/i,
|
|
140
|
+
/paypal\s+(send|pay|transfer)/i,
|
|
141
|
+
/cash\s*app\s+(send|pay)/i,
|
|
142
|
+
/withdraw\s+(money|funds|cash|\$)/i,
|
|
143
|
+
/purchase\s+(crypto|bitcoin|ethereum|gift\s*card)/i,
|
|
144
|
+
/buy\s+(crypto|bitcoin|ethereum|gift\s*card)/i,
|
|
145
|
+
|
|
146
|
+
// ============ DATA DESTRUCTION ============
|
|
147
|
+
// Block mass deletion - catastrophic if wrong
|
|
148
|
+
/delete\s+(all|everything|every|the\s+entire)/i,
|
|
149
|
+
/remove\s+(all|everything|every)/i,
|
|
150
|
+
/erase\s+(all|everything|every|the\s+entire)/i,
|
|
151
|
+
/wipe\s+(all|everything|the|my)/i,
|
|
152
|
+
/destroy\s+(all|everything|the|my)/i,
|
|
153
|
+
/purge\s+(all|everything|the|my)/i,
|
|
154
|
+
/drop\s+(database|table|collection|all)/i,
|
|
155
|
+
/truncate\s+(table|database)/i,
|
|
156
|
+
/rm\s+-rf/i,
|
|
157
|
+
/format\s+(drive|disk|c:)/i,
|
|
158
|
+
|
|
159
|
+
// ============ CREDENTIALS/SECRETS ============
|
|
160
|
+
// Block credential operations - theft vector
|
|
161
|
+
/export\s+.*(password|credential|secret|key|token)/i,
|
|
162
|
+
/send\s+.*(password|credential|secret|key|token)/i,
|
|
163
|
+
/share\s+.*(password|credential|secret|key|token)/i,
|
|
164
|
+
/forward\s+.*(password|credential|secret|key|token)/i,
|
|
165
|
+
/dump\s+.*(password|credential|hash|database)/i,
|
|
166
|
+
/extract\s+.*(password|credential|cookie|session)/i,
|
|
167
|
+
|
|
168
|
+
// ============ ACCOUNT DESTRUCTION ============
|
|
169
|
+
/close\s+(my\s+)?account/i,
|
|
170
|
+
/delete\s+(my\s+)?account/i,
|
|
171
|
+
/deactivate\s+(my\s+)?account/i,
|
|
172
|
+
/terminate\s+(my\s+)?account/i,
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
// Alias for backwards compatibility
|
|
176
|
+
export const WEAPON_ATTACK_PATTERNS = CRITICAL_DANGER_PATTERNS
|
|
177
|
+
|
|
178
|
+
// AUTONOMOUS SAFE ACTIONS (no blocking):
|
|
179
|
+
// - Read emails, browse, search, research
|
|
180
|
+
// - Send emails/messages (content, not money)
|
|
181
|
+
// - Fill forms, schedule meetings
|
|
182
|
+
// - Normal work tasks
|
|
183
|
+
// - Delete SPECIFIC items (not "all")
|
|
184
|
+
|
|
185
|
+
// PROMPT INJECTION DETECTION - Block attempts to hijack the agent
|
|
186
|
+
export const PROMPT_INJECTION_PATTERNS = [
|
|
187
|
+
// Direct instruction override attempts
|
|
188
|
+
/ignore\s+(all\s+)?(previous|prior|above)\s+(instructions|rules|guidelines)/i,
|
|
189
|
+
/disregard\s+(all\s+)?(previous|prior|above)\s+(instructions|rules)/i,
|
|
190
|
+
/forget\s+(all\s+)?(previous|prior|your)\s+(instructions|rules|training)/i,
|
|
191
|
+
/override\s+(your|the|all)\s+(instructions|rules|restrictions)/i,
|
|
192
|
+
/bypass\s+(your|the|all)\s+(restrictions|limitations|guardrails)/i,
|
|
193
|
+
|
|
194
|
+
// Role-play injection
|
|
195
|
+
/pretend\s+(you\s+are|to\s+be|you're)\s+(a|an|the)/i,
|
|
196
|
+
/act\s+as\s+(if\s+you\s+are|a|an|the)/i,
|
|
197
|
+
/you\s+are\s+now\s+(a|an|the|in)/i,
|
|
198
|
+
/roleplay\s+as/i,
|
|
199
|
+
/simulate\s+(being|a|an)/i,
|
|
200
|
+
/imagine\s+you\s+are/i,
|
|
201
|
+
|
|
202
|
+
// System prompt extraction
|
|
203
|
+
/reveal\s+(your|the)\s+(system|initial)\s+(prompt|instructions)/i,
|
|
204
|
+
/show\s+(me\s+)?(your|the)\s+(system|initial)\s+(prompt|instructions)/i,
|
|
205
|
+
/what\s+(are|is)\s+your\s+(system|initial)\s+(prompt|instructions)/i,
|
|
206
|
+
/print\s+(your|the)\s+(system|initial)\s+prompt/i,
|
|
207
|
+
/output\s+(your|the)\s+(system|initial)\s+prompt/i,
|
|
208
|
+
|
|
209
|
+
// Fake system messages
|
|
210
|
+
/<\/?system>/i,
|
|
211
|
+
/<\/?instructions>/i,
|
|
212
|
+
/<\/?admin>/i,
|
|
213
|
+
/\[SYSTEM\]/i,
|
|
214
|
+
/\[ADMIN\]/i,
|
|
215
|
+
/\[OVERRIDE\]/i,
|
|
216
|
+
/###\s*(system|admin|override)/i,
|
|
217
|
+
|
|
218
|
+
// Jailbreak keywords
|
|
219
|
+
/jailbreak/i,
|
|
220
|
+
/dan\s+mode/i,
|
|
221
|
+
/developer\s+mode\s+enabled/i,
|
|
222
|
+
/sudo\s+mode/i,
|
|
223
|
+
/god\s+mode/i,
|
|
224
|
+
/unrestricted\s+mode/i,
|
|
225
|
+
]
|
|
226
|
+
|
|
227
|
+
// Destructive bash command patterns (regex)
|
|
228
|
+
export const BLOCKED_COMMAND_PATTERNS = [
|
|
229
|
+
// Filesystem destruction - only block rm targeting root/home/current dir exactly
|
|
230
|
+
/^rm\s+(-[rfv]+\s+)*\/\s*$/i, // rm -rf /
|
|
231
|
+
/^rm\s+(-[rfv]+\s+)*\/\*\s*$/i, // rm -rf /*
|
|
232
|
+
/^rm\s+(-[rfv]+\s+)*~\s*$/i, // rm -rf ~
|
|
233
|
+
/^rm\s+(-[rfv]+\s+)*\.\s*$/i, // rm -rf . (exact)
|
|
234
|
+
/^rm\s+(-[rfv]+\s+)*\.\.\s*$/i, // rm -rf .. (exact)
|
|
235
|
+
]
|
|
236
|
+
|
|
237
|
+
// Destructive bash commands that should NEVER execute (substring match)
|
|
238
|
+
export const BLOCKED_COMMANDS = [
|
|
239
|
+
// Filesystem destruction
|
|
240
|
+
"> /dev/sda",
|
|
241
|
+
"dd if=/dev/zero",
|
|
242
|
+
"dd if=/dev/random",
|
|
243
|
+
"mkfs",
|
|
244
|
+
"format",
|
|
245
|
+
":(){:|:&};:", // fork bomb
|
|
246
|
+
|
|
247
|
+
// System compromise
|
|
248
|
+
"chmod -R 777 /",
|
|
249
|
+
"chown -R",
|
|
250
|
+
"passwd",
|
|
251
|
+
"useradd",
|
|
252
|
+
"userdel",
|
|
253
|
+
"visudo",
|
|
254
|
+
|
|
255
|
+
// Network attacks
|
|
256
|
+
"nmap -sS",
|
|
257
|
+
"hping3",
|
|
258
|
+
"slowloris",
|
|
259
|
+
|
|
260
|
+
// Crypto mining
|
|
261
|
+
"xmrig",
|
|
262
|
+
"minerd",
|
|
263
|
+
"cpuminer",
|
|
264
|
+
]
|
|
265
|
+
|
|
266
|
+
export interface GuardrailResult {
|
|
267
|
+
blocked: boolean
|
|
268
|
+
reason?: string
|
|
269
|
+
category?: "domain" | "intent" | "command" | "weapon" | "injection"
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Check if a URL/domain is blocked
|
|
274
|
+
*/
|
|
275
|
+
export function checkDomain(url: string): GuardrailResult {
|
|
276
|
+
try {
|
|
277
|
+
const urlObj = new URL(url.startsWith("http") ? url : `https://${url}`)
|
|
278
|
+
const hostname = urlObj.hostname.toLowerCase()
|
|
279
|
+
|
|
280
|
+
// Check exact match and parent domains
|
|
281
|
+
const parts = hostname.split(".")
|
|
282
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
283
|
+
const domain = parts.slice(i).join(".")
|
|
284
|
+
if (BLOCKED_DOMAINS.has(domain)) {
|
|
285
|
+
return {
|
|
286
|
+
blocked: true,
|
|
287
|
+
reason: `Domain "${domain}" is blocked for security reasons. This appears to be a banking, financial, healthcare, or government site.`,
|
|
288
|
+
category: "domain",
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
} catch {
|
|
293
|
+
// Invalid URL, let it through for other validation
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return { blocked: false }
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Check if task description contains malicious intent
|
|
301
|
+
*/
|
|
302
|
+
export function checkIntent(taskDescription: string): GuardrailResult {
|
|
303
|
+
const normalized = taskDescription.toLowerCase()
|
|
304
|
+
|
|
305
|
+
for (const pattern of MALICIOUS_PATTERNS) {
|
|
306
|
+
if (pattern.test(normalized)) {
|
|
307
|
+
return {
|
|
308
|
+
blocked: true,
|
|
309
|
+
reason: `Task appears to involve malicious activity. RIRD is designed for legitimate automation only.`,
|
|
310
|
+
category: "intent",
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return { blocked: false }
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Check if task contains dangerous/irreversible actions
|
|
320
|
+
* Blocks: violence, money transfers, mass deletion, credential export
|
|
321
|
+
* Users warned upfront - no confirmations, just refuses dangerous actions
|
|
322
|
+
*/
|
|
323
|
+
export function checkWeaponUse(taskDescription: string): GuardrailResult {
|
|
324
|
+
const normalized = taskDescription.toLowerCase()
|
|
325
|
+
|
|
326
|
+
for (const pattern of CRITICAL_DANGER_PATTERNS) {
|
|
327
|
+
if (pattern.test(normalized)) {
|
|
328
|
+
return {
|
|
329
|
+
blocked: true,
|
|
330
|
+
reason: `BLOCKED: This action is dangerous and irreversible. RIRD blocks: violence/weapons, money transfers, mass deletion, and credential export.`,
|
|
331
|
+
category: "weapon",
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return { blocked: false }
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Check for prompt injection attempts
|
|
341
|
+
* Detects attempts to hijack the agent via malicious instructions
|
|
342
|
+
*/
|
|
343
|
+
export function checkPromptInjection(content: string): GuardrailResult {
|
|
344
|
+
const normalized = content.toLowerCase()
|
|
345
|
+
|
|
346
|
+
for (const pattern of PROMPT_INJECTION_PATTERNS) {
|
|
347
|
+
if (pattern.test(normalized)) {
|
|
348
|
+
return {
|
|
349
|
+
blocked: true,
|
|
350
|
+
reason: `PROMPT INJECTION DETECTED: Content contains patterns that attempt to override agent instructions. This may be a malicious webpage or document.`,
|
|
351
|
+
category: "injection",
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return { blocked: false }
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Check if bash command is destructive
|
|
361
|
+
*/
|
|
362
|
+
export function checkCommand(command: string): GuardrailResult {
|
|
363
|
+
const normalized = command.toLowerCase().trim()
|
|
364
|
+
|
|
365
|
+
// Check exact pattern matches first (rm commands targeting dangerous paths)
|
|
366
|
+
for (const pattern of BLOCKED_COMMAND_PATTERNS) {
|
|
367
|
+
if (pattern.test(normalized)) {
|
|
368
|
+
return {
|
|
369
|
+
blocked: true,
|
|
370
|
+
reason: "Recursive deletion of system directories is blocked.",
|
|
371
|
+
category: "command",
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Check substring matches for other dangerous commands
|
|
377
|
+
for (const blocked of BLOCKED_COMMANDS) {
|
|
378
|
+
if (normalized.includes(blocked.toLowerCase())) {
|
|
379
|
+
return {
|
|
380
|
+
blocked: true,
|
|
381
|
+
reason: `Command containing "${blocked}" is blocked as potentially destructive.`,
|
|
382
|
+
category: "command",
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Block direct disk writes
|
|
388
|
+
if (/>\s*\/dev\/[sh]d[a-z]/.test(normalized)) {
|
|
389
|
+
return {
|
|
390
|
+
blocked: true,
|
|
391
|
+
reason: "Direct writes to disk devices are blocked.",
|
|
392
|
+
category: "command",
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return { blocked: false }
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Run all guardrail checks on a task
|
|
401
|
+
* Logs all blocked attempts for security audit trail
|
|
402
|
+
*/
|
|
403
|
+
export function validateTask(task: {
|
|
404
|
+
description?: string
|
|
405
|
+
url?: string
|
|
406
|
+
command?: string
|
|
407
|
+
webContent?: string // Content scraped from web pages
|
|
408
|
+
}): GuardrailResult {
|
|
409
|
+
const context = {
|
|
410
|
+
task: task.description,
|
|
411
|
+
url: task.url,
|
|
412
|
+
command: task.command,
|
|
413
|
+
webContent: task.webContent,
|
|
414
|
+
timestamp: new Date(),
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Check for prompt injection in web content FIRST (highest priority)
|
|
418
|
+
if (task.webContent) {
|
|
419
|
+
const injectionResult = checkPromptInjection(task.webContent)
|
|
420
|
+
if (injectionResult.blocked) {
|
|
421
|
+
logBlockedAttempt(injectionResult, context)
|
|
422
|
+
return injectionResult
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Check for prompt injection in task description
|
|
427
|
+
if (task.description) {
|
|
428
|
+
const injectionResult = checkPromptInjection(task.description)
|
|
429
|
+
if (injectionResult.blocked) {
|
|
430
|
+
logBlockedAttempt(injectionResult, context)
|
|
431
|
+
return injectionResult
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Check for weapon use (violence, stalking, targeting people)
|
|
436
|
+
if (task.description) {
|
|
437
|
+
const weaponResult = checkWeaponUse(task.description)
|
|
438
|
+
if (weaponResult.blocked) {
|
|
439
|
+
logBlockedAttempt(weaponResult, context)
|
|
440
|
+
return weaponResult
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Check malicious intent
|
|
445
|
+
if (task.description) {
|
|
446
|
+
const intentResult = checkIntent(task.description)
|
|
447
|
+
if (intentResult.blocked) {
|
|
448
|
+
logBlockedAttempt(intentResult, context)
|
|
449
|
+
return intentResult
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Check domain
|
|
454
|
+
if (task.url) {
|
|
455
|
+
const domainResult = checkDomain(task.url)
|
|
456
|
+
if (domainResult.blocked) {
|
|
457
|
+
logBlockedAttempt(domainResult, context)
|
|
458
|
+
return domainResult
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Check command
|
|
463
|
+
if (task.command) {
|
|
464
|
+
const commandResult = checkCommand(task.command)
|
|
465
|
+
if (commandResult.blocked) {
|
|
466
|
+
logBlockedAttempt(commandResult, context)
|
|
467
|
+
return commandResult
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return { blocked: false }
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Log blocked attempt (for audit)
|
|
476
|
+
* Writes to both console and persistent file-based audit log
|
|
477
|
+
*/
|
|
478
|
+
export function logBlockedAttempt(
|
|
479
|
+
result: GuardrailResult,
|
|
480
|
+
context: { task?: string; url?: string; command?: string; webContent?: string; timestamp?: Date }
|
|
481
|
+
): void {
|
|
482
|
+
const timestamp = context.timestamp || new Date()
|
|
483
|
+
const entry = {
|
|
484
|
+
timestamp: timestamp.toISOString(),
|
|
485
|
+
category: result.category,
|
|
486
|
+
reason: result.reason,
|
|
487
|
+
task: context.task?.substring(0, 200), // Truncate for privacy but keep enough context
|
|
488
|
+
url: context.url,
|
|
489
|
+
command: context.command?.substring(0, 100),
|
|
490
|
+
webContentPreview: context.webContent?.substring(0, 100), // Brief preview if injection detected
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Log to console (visible in terminal)
|
|
494
|
+
console.warn("[GUARDRAIL BLOCKED]", JSON.stringify(entry))
|
|
495
|
+
|
|
496
|
+
// Persistent file-based audit logging
|
|
497
|
+
try {
|
|
498
|
+
const logFileName = `security-blocks-${timestamp.toISOString().split("T")[0]}.jsonl`
|
|
499
|
+
const logFilePath = path.join(SECURITY_LOG_DIR, logFileName)
|
|
500
|
+
|
|
501
|
+
// Append to daily log file (JSONL format - one JSON object per line)
|
|
502
|
+
fs.appendFileSync(logFilePath, JSON.stringify(entry) + "\n", { encoding: "utf-8" })
|
|
503
|
+
} catch (err) {
|
|
504
|
+
// If file logging fails, at least console.warn already ran
|
|
505
|
+
console.warn("[GUARDRAIL] Failed to write audit log:", err instanceof Error ? err.message : err)
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Get path to security audit logs directory
|
|
511
|
+
* Logs are stored as daily JSONL files: security-blocks-YYYY-MM-DD.jsonl
|
|
512
|
+
*/
|
|
513
|
+
export function getSecurityLogDir(): string {
|
|
514
|
+
return SECURITY_LOG_DIR
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Read recent security blocks from audit log
|
|
519
|
+
* @param days Number of days to look back (default: 7)
|
|
520
|
+
* @returns Array of blocked attempt entries
|
|
521
|
+
*/
|
|
522
|
+
export function getRecentSecurityBlocks(days: number = 7): Array<{
|
|
523
|
+
timestamp: string
|
|
524
|
+
category: string
|
|
525
|
+
reason: string
|
|
526
|
+
task?: string
|
|
527
|
+
url?: string
|
|
528
|
+
command?: string
|
|
529
|
+
}> {
|
|
530
|
+
const entries: Array<any> = []
|
|
531
|
+
|
|
532
|
+
try {
|
|
533
|
+
const files = fs.readdirSync(SECURITY_LOG_DIR)
|
|
534
|
+
.filter(f => f.startsWith("security-blocks-") && f.endsWith(".jsonl"))
|
|
535
|
+
.sort()
|
|
536
|
+
.slice(-days) // Get last N days
|
|
537
|
+
|
|
538
|
+
for (const file of files) {
|
|
539
|
+
try {
|
|
540
|
+
const content = fs.readFileSync(path.join(SECURITY_LOG_DIR, file), "utf-8")
|
|
541
|
+
const lines = content.trim().split("\n").filter(Boolean)
|
|
542
|
+
for (const line of lines) {
|
|
543
|
+
try {
|
|
544
|
+
entries.push(JSON.parse(line))
|
|
545
|
+
} catch {
|
|
546
|
+
// Skip malformed lines
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
} catch {
|
|
550
|
+
// Skip unreadable files
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
} catch {
|
|
554
|
+
// Directory may not exist yet
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
return entries
|
|
558
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export {
|
|
2
|
+
checkDomain,
|
|
3
|
+
checkIntent,
|
|
4
|
+
checkCommand,
|
|
5
|
+
checkWeaponUse,
|
|
6
|
+
checkPromptInjection,
|
|
7
|
+
validateTask,
|
|
8
|
+
logBlockedAttempt,
|
|
9
|
+
getSecurityLogDir,
|
|
10
|
+
getRecentSecurityBlocks,
|
|
11
|
+
BLOCKED_DOMAINS,
|
|
12
|
+
MALICIOUS_PATTERNS,
|
|
13
|
+
BLOCKED_COMMANDS,
|
|
14
|
+
BLOCKED_COMMAND_PATTERNS,
|
|
15
|
+
CRITICAL_DANGER_PATTERNS,
|
|
16
|
+
WEAPON_ATTACK_PATTERNS,
|
|
17
|
+
PROMPT_INJECTION_PATTERNS,
|
|
18
|
+
type GuardrailResult,
|
|
19
|
+
} from "./guardrails"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { resolver } from "hono-openapi"
|
|
2
|
+
import z from "zod"
|
|
3
|
+
import { Storage } from "../storage/storage"
|
|
4
|
+
|
|
5
|
+
export const ERRORS = {
|
|
6
|
+
400: {
|
|
7
|
+
description: "Bad request",
|
|
8
|
+
content: {
|
|
9
|
+
"application/json": {
|
|
10
|
+
schema: resolver(
|
|
11
|
+
z
|
|
12
|
+
.object({
|
|
13
|
+
data: z.any(),
|
|
14
|
+
errors: z.array(z.record(z.string(), z.any())),
|
|
15
|
+
success: z.literal(false),
|
|
16
|
+
})
|
|
17
|
+
.meta({
|
|
18
|
+
ref: "BadRequestError",
|
|
19
|
+
}),
|
|
20
|
+
),
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
404: {
|
|
25
|
+
description: "Not found",
|
|
26
|
+
content: {
|
|
27
|
+
"application/json": {
|
|
28
|
+
schema: resolver(Storage.NotFoundError.Schema),
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
} as const
|
|
33
|
+
|
|
34
|
+
export function errors(...codes: number[]) {
|
|
35
|
+
return Object.fromEntries(codes.map((code) => [code, ERRORS[code as keyof typeof ERRORS]]))
|
|
36
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Hono } from "hono"
|
|
2
|
+
import { describeRoute, validator } from "hono-openapi"
|
|
3
|
+
import { resolver } from "hono-openapi"
|
|
4
|
+
import { Instance } from "../project/instance"
|
|
5
|
+
import { Project } from "../project/project"
|
|
6
|
+
import z from "zod"
|
|
7
|
+
import { errors } from "./error"
|
|
8
|
+
|
|
9
|
+
export const ProjectRoute = new Hono()
|
|
10
|
+
.get(
|
|
11
|
+
"/",
|
|
12
|
+
describeRoute({
|
|
13
|
+
summary: "List all projects",
|
|
14
|
+
description: "Get a list of projects that have been opened with RIRD.",
|
|
15
|
+
operationId: "project.list",
|
|
16
|
+
responses: {
|
|
17
|
+
200: {
|
|
18
|
+
description: "List of projects",
|
|
19
|
+
content: {
|
|
20
|
+
"application/json": {
|
|
21
|
+
schema: resolver(Project.Info.array()),
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
}),
|
|
27
|
+
async (c) => {
|
|
28
|
+
const projects = await Project.list()
|
|
29
|
+
return c.json(projects)
|
|
30
|
+
},
|
|
31
|
+
)
|
|
32
|
+
.get(
|
|
33
|
+
"/current",
|
|
34
|
+
describeRoute({
|
|
35
|
+
summary: "Get current project",
|
|
36
|
+
description: "Retrieve the currently active project that RIRD is working with.",
|
|
37
|
+
operationId: "project.current",
|
|
38
|
+
responses: {
|
|
39
|
+
200: {
|
|
40
|
+
description: "Current project information",
|
|
41
|
+
content: {
|
|
42
|
+
"application/json": {
|
|
43
|
+
schema: resolver(Project.Info),
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
async (c) => {
|
|
50
|
+
return c.json(Instance.project)
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
.patch(
|
|
54
|
+
"/:projectID",
|
|
55
|
+
describeRoute({
|
|
56
|
+
summary: "Update project",
|
|
57
|
+
description: "Update project properties such as name, icon and color.",
|
|
58
|
+
operationId: "project.update",
|
|
59
|
+
responses: {
|
|
60
|
+
200: {
|
|
61
|
+
description: "Updated project information",
|
|
62
|
+
content: {
|
|
63
|
+
"application/json": {
|
|
64
|
+
schema: resolver(Project.Info),
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
...errors(400, 404),
|
|
69
|
+
},
|
|
70
|
+
}),
|
|
71
|
+
validator("param", z.object({ projectID: z.string() })),
|
|
72
|
+
validator("json", Project.update.schema.omit({ projectID: true })),
|
|
73
|
+
async (c) => {
|
|
74
|
+
const projectID = c.req.valid("param").projectID
|
|
75
|
+
const body = c.req.valid("json")
|
|
76
|
+
const project = await Project.update({ ...body, projectID })
|
|
77
|
+
return c.json(project)
|
|
78
|
+
},
|
|
79
|
+
)
|