@vellumai/assistant 0.5.9 → 0.5.11
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 +9 -1
- package/ARCHITECTURE.md +48 -48
- package/Dockerfile +2 -0
- package/README.md +1 -1
- package/docs/architecture/integrations.md +6 -13
- package/docs/architecture/memory.md +7 -12
- package/docs/architecture/security.md +5 -5
- package/docs/credential-execution-service.md +9 -9
- package/docs/skills.md +1 -1
- package/node_modules/@vellumai/credential-storage/src/index.ts +2 -2
- package/node_modules/@vellumai/credential-storage/src/static-credentials.ts +1 -1
- package/openapi.yaml +7130 -0
- package/package.json +2 -1
- package/scripts/generate-openapi.ts +562 -0
- package/src/__tests__/acp-session.test.ts +239 -44
- package/src/__tests__/assistant-feature-flag-guard.test.ts +8 -8
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +5 -86
- package/src/__tests__/assistant-feature-flags-integration.test.ts +7 -14
- package/src/__tests__/browser-skill-endstate.test.ts +1 -1
- package/src/__tests__/btw-routes.test.ts +8 -0
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +10 -10
- package/src/__tests__/channel-approvals.test.ts +7 -7
- package/src/__tests__/channel-readiness-service.test.ts +41 -0
- package/src/__tests__/config-schema.test.ts +10 -2
- package/src/__tests__/context-memory-e2e.test.ts +2 -6
- package/src/__tests__/conversation-skill-tools.test.ts +1 -3
- package/src/__tests__/conversation-title-service.test.ts +2 -15
- package/src/__tests__/credential-execution-feature-gates.test.ts +4 -8
- package/src/__tests__/credential-execution-managed-contract.test.ts +8 -8
- package/src/__tests__/credential-security-e2e.test.ts +4 -4
- package/src/__tests__/credential-security-invariants.test.ts +3 -3
- package/src/__tests__/credentials-cli.test.ts +3 -3
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -1
- package/src/__tests__/gateway-only-guard.test.ts +3 -0
- package/src/__tests__/heartbeat-service.test.ts +35 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +3 -3
- package/src/__tests__/llm-request-log-turn-query.test.ts +64 -0
- package/src/__tests__/log-export-workspace.test.ts +1 -1
- package/src/__tests__/mcp-client-auth.test.ts +1 -1
- package/src/__tests__/memory-lifecycle-e2e.test.ts +2 -2
- package/src/__tests__/memory-recall-log-store.test.ts +182 -0
- package/src/__tests__/memory-recall-quality.test.ts +6 -8
- package/src/__tests__/memory-regressions.test.ts +53 -42
- package/src/__tests__/memory-retrieval.benchmark.test.ts +5 -9
- package/src/__tests__/messaging-skill-split.test.ts +2 -17
- package/src/__tests__/oauth-cli.test.ts +98 -551
- package/src/__tests__/platform-callback-registration.test.ts +119 -0
- package/src/__tests__/secret-ingress-channel.test.ts +261 -0
- package/src/__tests__/secret-ingress-cli.test.ts +201 -0
- package/src/__tests__/secret-ingress-http.test.ts +312 -0
- package/src/__tests__/secret-ingress.test.ts +283 -0
- package/src/__tests__/secret-onetime-send.test.ts +4 -4
- package/src/__tests__/skill-feature-flags-integration.test.ts +4 -4
- package/src/__tests__/skill-feature-flags.test.ts +11 -19
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -1
- package/src/__tests__/skill-load-inline-command.test.ts +3 -3
- package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
- package/src/__tests__/skill-memory.test.ts +2 -4
- package/src/__tests__/skill-projection-feature-flag.test.ts +2 -4
- package/src/__tests__/skill-projection.benchmark.test.ts +1 -3
- package/src/__tests__/skills.test.ts +16 -2
- package/src/__tests__/slack-channel-config.test.ts +1 -1
- package/src/__tests__/slack-skill.test.ts +5 -69
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -1
- package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +5 -238
- package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +5 -206
- package/src/__tests__/workspace-migration-018-rekey-compound-credential-keys.test.ts +181 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +15 -7
- package/src/acp/client-handler.ts +113 -31
- package/src/acp/session-manager.ts +29 -27
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/cli/AGENTS.md +73 -0
- package/src/cli/commands/autonomy.ts +3 -5
- package/src/cli/commands/credential-execution.ts +1 -2
- package/src/cli/commands/credentials.ts +4 -4
- package/src/cli/commands/memory.ts +2 -3
- package/src/cli/commands/oauth/__tests__/connect.test.ts +785 -0
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +760 -0
- package/src/cli/commands/oauth/__tests__/mode.test.ts +672 -0
- package/src/cli/commands/oauth/__tests__/ping.test.ts +690 -0
- package/src/cli/commands/oauth/__tests__/status.test.ts +579 -0
- package/src/cli/commands/oauth/__tests__/token.test.ts +467 -0
- package/src/cli/commands/oauth/apps.ts +29 -11
- package/src/cli/commands/oauth/connect.ts +373 -0
- package/src/cli/commands/oauth/connections.ts +14 -493
- package/src/cli/commands/oauth/disconnect.ts +333 -0
- package/src/cli/commands/oauth/index.ts +62 -10
- package/src/cli/commands/oauth/mode.ts +263 -0
- package/src/cli/commands/oauth/ping.ts +222 -0
- package/src/cli/commands/oauth/providers.ts +30 -3
- package/src/cli/commands/oauth/request.ts +576 -0
- package/src/cli/commands/oauth/shared.ts +132 -0
- package/src/cli/commands/oauth/status.ts +202 -0
- package/src/cli/commands/oauth/token.ts +159 -0
- package/src/cli/commands/platform.ts +20 -14
- package/src/cli.ts +82 -17
- package/src/config/assistant-feature-flags.ts +74 -11
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +13 -36
- package/src/config/bundled-skills/messaging/TOOLS.json +9 -9
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
- package/src/config/bundled-skills/notifications/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +2 -2
- package/src/config/bundled-skills/settings/SKILL.md +5 -3
- package/src/config/bundled-skills/settings/TOOLS.json +17 -0
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +50 -0
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +7 -0
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +6 -1
- package/src/config/bundled-skills/settings/tools/identity-avatar.ts +55 -0
- package/src/config/bundled-skills/skills-catalog/SKILL.md +3 -3
- package/src/config/bundled-skills/slack/SKILL.md +58 -44
- package/src/config/bundled-tool-registry.ts +2 -19
- package/src/config/env.ts +5 -1
- package/src/config/feature-flag-registry.json +57 -41
- package/src/config/loader.ts +4 -0
- package/src/config/schemas/platform.ts +0 -8
- package/src/config/schemas/security.ts +9 -1
- package/src/config/schemas/services.ts +1 -1
- package/src/config/skill-state.ts +1 -3
- package/src/config/skills.ts +2 -4
- package/src/credential-execution/feature-gates.ts +9 -16
- package/src/credential-execution/process-manager.ts +12 -0
- package/src/daemon/config-watcher.ts +4 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +10 -0
- package/src/daemon/conversation-agent-loop.ts +49 -2
- package/src/daemon/conversation-memory.ts +0 -1
- package/src/daemon/handlers/config-slack-channel.ts +43 -1
- package/src/daemon/handlers/conversations.ts +41 -33
- package/src/daemon/lifecycle.ts +28 -5
- package/src/daemon/message-types/acp.ts +0 -15
- package/src/daemon/message-types/memory.ts +0 -1
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/schedules.ts +9 -0
- package/src/daemon/server.ts +19 -7
- package/src/email/feature-gate.ts +3 -3
- package/src/heartbeat/heartbeat-service.ts +48 -0
- package/src/inbound/platform-callback-registration.ts +61 -7
- package/src/mcp/mcp-oauth-provider.ts +3 -3
- package/src/memory/app-store.ts +3 -3
- package/src/memory/conversation-crud.ts +124 -0
- package/src/memory/conversation-title-service.ts +7 -17
- package/src/memory/db-init.ts +8 -0
- package/src/memory/embedding-local.ts +47 -2
- package/src/memory/indexer.ts +13 -10
- package/src/memory/items-extractor.ts +12 -4
- package/src/memory/job-utils.ts +5 -0
- package/src/memory/jobs-store.ts +10 -2
- package/src/memory/journal-memory.ts +6 -2
- package/src/memory/llm-request-log-store.ts +88 -21
- package/src/memory/memory-recall-log-store.ts +128 -0
- package/src/memory/migrations/194-memory-recall-logs.ts +50 -0
- package/src/memory/migrations/195-oauth-providers-ping-config.ts +23 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/migrations/validate-migration-state.ts +14 -1
- package/src/memory/retriever.test.ts +4 -5
- package/src/memory/schema/infrastructure.ts +31 -0
- package/src/memory/schema/oauth.ts +3 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -1
- package/src/oauth/connect-orchestrator.ts +54 -0
- package/src/oauth/manual-token-connection.ts +5 -5
- package/src/oauth/oauth-store.ts +26 -5
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +2 -2
- package/src/permissions/trust-client.ts +2 -2
- package/src/platform/client.ts +2 -2
- package/src/prompts/journal-context.ts +6 -1
- package/src/providers/anthropic/client.ts +143 -1
- package/src/runtime/auth/__tests__/middleware.test.ts +19 -0
- package/src/runtime/auth/route-policy.ts +0 -1
- package/src/runtime/btw-sidechain.ts +7 -1
- package/src/runtime/channel-approvals.ts +2 -2
- package/src/runtime/channel-readiness-service.ts +30 -7
- package/src/runtime/http-router.ts +31 -0
- package/src/runtime/http-server.ts +21 -4
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/pending-interactions.ts +21 -3
- package/src/runtime/routes/acp-routes.ts +46 -28
- package/src/runtime/routes/app-management-routes.ts +123 -0
- package/src/runtime/routes/app-routes.ts +31 -0
- package/src/runtime/routes/approval-routes.ts +108 -3
- package/src/runtime/routes/attachment-routes.ts +45 -0
- package/src/runtime/routes/avatar-routes.ts +16 -0
- package/src/runtime/routes/brain-graph-routes.ts +18 -0
- package/src/runtime/routes/btw-routes.ts +20 -0
- package/src/runtime/routes/call-routes.ts +81 -0
- package/src/runtime/routes/channel-readiness-routes.ts +48 -7
- package/src/runtime/routes/channel-routes.ts +18 -0
- package/src/runtime/routes/channel-verification-routes.ts +49 -1
- package/src/runtime/routes/contact-routes.ts +77 -0
- package/src/runtime/routes/conversation-attention-routes.ts +37 -0
- package/src/runtime/routes/conversation-management-routes.ts +94 -0
- package/src/runtime/routes/conversation-query-routes.ts +78 -0
- package/src/runtime/routes/conversation-routes.ts +115 -38
- package/src/runtime/routes/conversation-starter-routes.ts +29 -0
- package/src/runtime/routes/debug-routes.ts +23 -0
- package/src/runtime/routes/diagnostics-routes.ts +30 -0
- package/src/runtime/routes/documents-routes.ts +42 -0
- package/src/runtime/routes/events-routes.ts +10 -0
- package/src/runtime/routes/global-search-routes.ts +35 -0
- package/src/runtime/routes/guardian-action-routes.ts +47 -2
- package/src/runtime/routes/guardian-approval-prompt.ts +77 -2
- package/src/runtime/routes/heartbeat-routes.ts +278 -0
- package/src/runtime/routes/host-bash-routes.ts +16 -1
- package/src/runtime/routes/host-cu-routes.ts +23 -1
- package/src/runtime/routes/host-file-routes.ts +18 -1
- package/src/runtime/routes/identity-routes.ts +35 -0
- package/src/runtime/routes/inbound-message-handler.ts +46 -25
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +30 -2
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -2
- package/src/runtime/routes/integrations/twilio.ts +32 -22
- package/src/runtime/routes/invite-routes.ts +83 -0
- package/src/runtime/routes/log-export-routes.ts +14 -0
- package/src/runtime/routes/memory-item-routes.ts +99 -1
- package/src/runtime/routes/migration-rollback-routes.ts +25 -0
- package/src/runtime/routes/migration-routes.ts +40 -0
- package/src/runtime/routes/notification-routes.ts +20 -0
- package/src/runtime/routes/oauth-apps.ts +11 -3
- package/src/runtime/routes/pairing-routes.ts +15 -0
- package/src/runtime/routes/recording-routes.ts +72 -0
- package/src/runtime/routes/schedule-routes.ts +77 -5
- package/src/runtime/routes/secret-routes.ts +63 -1
- package/src/runtime/routes/settings-routes.ts +91 -1
- package/src/runtime/routes/skills-routes.ts +98 -16
- package/src/runtime/routes/subagents-routes.ts +38 -3
- package/src/runtime/routes/surface-action-routes.ts +66 -24
- package/src/runtime/routes/surface-content-routes.ts +20 -0
- package/src/runtime/routes/telemetry-routes.ts +12 -0
- package/src/runtime/routes/trace-event-routes.ts +25 -0
- package/src/runtime/routes/trust-rules-routes.ts +46 -0
- package/src/runtime/routes/tts-routes.ts +15 -4
- package/src/runtime/routes/upgrade-broadcast-routes.ts +38 -0
- package/src/runtime/routes/usage-routes.ts +59 -0
- package/src/runtime/routes/watch-routes.ts +28 -0
- package/src/runtime/routes/work-items-routes.ts +59 -0
- package/src/runtime/routes/workspace-commit-routes.ts +12 -0
- package/src/runtime/routes/workspace-routes.ts +102 -0
- package/src/schedule/scheduler.ts +7 -1
- package/src/security/AGENTS.md +7 -0
- package/src/security/credential-backend.ts +1 -1
- package/src/security/encrypted-store.ts +3 -3
- package/src/security/oauth2.ts +55 -0
- package/src/security/secret-ingress.ts +174 -0
- package/src/security/secret-patterns.ts +133 -0
- package/src/security/secret-scanner.ts +28 -117
- package/src/signals/confirm.ts +12 -8
- package/src/signals/user-message.ts +18 -3
- package/src/skills/skill-memory.ts +1 -2
- package/src/tasks/task-runner.ts +7 -1
- package/src/tools/credentials/broker.ts +1 -1
- package/src/tools/credentials/metadata-store.ts +1 -1
- package/src/tools/credentials/vault.ts +2 -3
- package/src/tools/memory/definitions.ts +1 -1
- package/src/tools/memory/handlers.test.ts +2 -4
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/terminal/safe-env.ts +7 -0
- package/src/tools/tool-manifest.ts +1 -1
- package/src/util/log-redact.ts +9 -34
- package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +13 -148
- package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +7 -145
- package/src/workspace/migrations/AGENTS.md +11 -0
- package/src/workspace/migrations/runner.ts +16 -6
- package/src/workspace/migrations/types.ts +7 -0
- package/docs/architecture/keychain-broker.md +0 -69
- package/src/__tests__/keychain-broker-client.test.ts +0 -800
- package/src/cli/commands/oauth/platform.ts +0 -525
- package/src/config/bundled-skills/slack/TOOLS.json +0 -272
- package/src/config/bundled-skills/slack/tools/shared.ts +0 -34
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +0 -27
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +0 -38
- package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +0 -146
- package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +0 -105
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +0 -26
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +0 -27
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +0 -25
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +0 -372
- package/src/security/keychain-broker-client.ts +0 -446
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* the same pattern as other gateway-forwarded control-plane endpoints.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
10
12
|
import { getWorkspaceDir } from "../../util/platform.js";
|
|
11
13
|
import { getWorkspaceGitService } from "../../workspace/git-service.js";
|
|
12
14
|
import { httpError } from "../http-errors.js";
|
|
@@ -17,6 +19,16 @@ export function workspaceCommitRouteDefinitions(): RouteDefinition[] {
|
|
|
17
19
|
{
|
|
18
20
|
endpoint: "admin/workspace-commit",
|
|
19
21
|
method: "POST",
|
|
22
|
+
summary: "Commit workspace changes",
|
|
23
|
+
description:
|
|
24
|
+
"Create a git commit in the workspace directory with all pending changes.",
|
|
25
|
+
tags: ["admin"],
|
|
26
|
+
requestBody: z.object({
|
|
27
|
+
message: z.string().describe("Commit message"),
|
|
28
|
+
}),
|
|
29
|
+
responseBody: z.object({
|
|
30
|
+
ok: z.boolean(),
|
|
31
|
+
}),
|
|
20
32
|
handler: async ({ req }) => {
|
|
21
33
|
let body: unknown;
|
|
22
34
|
try {
|
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
} from "node:fs";
|
|
17
17
|
import { basename, dirname, join } from "node:path";
|
|
18
18
|
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
|
|
19
21
|
import { getWorkspaceDir } from "../../util/platform.js";
|
|
20
22
|
import { httpError } from "../http-errors.js";
|
|
21
23
|
import type { RouteContext, RouteDefinition } from "../http-router.js";
|
|
@@ -382,36 +384,136 @@ export function workspaceRouteDefinitions(): RouteDefinition[] {
|
|
|
382
384
|
{
|
|
383
385
|
endpoint: "workspace/tree",
|
|
384
386
|
method: "GET",
|
|
387
|
+
summary: "List workspace directory",
|
|
388
|
+
description: "Return directory entries for a workspace path.",
|
|
389
|
+
tags: ["workspace"],
|
|
390
|
+
queryParams: [
|
|
391
|
+
{
|
|
392
|
+
name: "path",
|
|
393
|
+
schema: { type: "string" },
|
|
394
|
+
description: "Relative path (default root)",
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
name: "showHidden",
|
|
398
|
+
schema: { type: "string" },
|
|
399
|
+
description: "Include dotfiles (true/false)",
|
|
400
|
+
},
|
|
401
|
+
],
|
|
402
|
+
responseBody: z.object({
|
|
403
|
+
path: z.string(),
|
|
404
|
+
entries: z.array(z.unknown()).describe("Directory entry objects"),
|
|
405
|
+
}),
|
|
385
406
|
handler: (ctx) => handleWorkspaceTree(ctx),
|
|
386
407
|
},
|
|
387
408
|
{
|
|
388
409
|
endpoint: "workspace/file/content",
|
|
389
410
|
method: "GET",
|
|
411
|
+
summary: "Get workspace file content",
|
|
412
|
+
description: "Return raw file bytes with HTTP range support.",
|
|
413
|
+
tags: ["workspace"],
|
|
414
|
+
queryParams: [
|
|
415
|
+
{
|
|
416
|
+
name: "path",
|
|
417
|
+
schema: { type: "string" },
|
|
418
|
+
description: "Relative file path (required)",
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
name: "showHidden",
|
|
422
|
+
schema: { type: "string" },
|
|
423
|
+
description: "Allow hidden files (true/false)",
|
|
424
|
+
},
|
|
425
|
+
],
|
|
390
426
|
handler: (ctx) => handleWorkspaceFileContent(ctx),
|
|
391
427
|
},
|
|
392
428
|
{
|
|
393
429
|
endpoint: "workspace/file",
|
|
394
430
|
method: "GET",
|
|
431
|
+
summary: "Get workspace file metadata",
|
|
432
|
+
description:
|
|
433
|
+
"Return file metadata and inline text content (if small enough).",
|
|
434
|
+
tags: ["workspace"],
|
|
435
|
+
queryParams: [
|
|
436
|
+
{
|
|
437
|
+
name: "path",
|
|
438
|
+
schema: { type: "string" },
|
|
439
|
+
description: "Relative file path (required)",
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
name: "showHidden",
|
|
443
|
+
schema: { type: "string" },
|
|
444
|
+
description: "Allow hidden files (true/false)",
|
|
445
|
+
},
|
|
446
|
+
],
|
|
447
|
+
responseBody: z.object({
|
|
448
|
+
path: z.string(),
|
|
449
|
+
name: z.string(),
|
|
450
|
+
size: z.number(),
|
|
451
|
+
mimeType: z.string(),
|
|
452
|
+
modifiedAt: z.string(),
|
|
453
|
+
content: z.string().describe("Inline text content or null"),
|
|
454
|
+
isBinary: z.boolean(),
|
|
455
|
+
}),
|
|
395
456
|
handler: (ctx) => handleWorkspaceFile(ctx),
|
|
396
457
|
},
|
|
397
458
|
{
|
|
398
459
|
endpoint: "workspace/write",
|
|
399
460
|
method: "POST",
|
|
461
|
+
summary: "Write workspace file",
|
|
462
|
+
description: "Create or overwrite a file in the workspace.",
|
|
463
|
+
tags: ["workspace"],
|
|
464
|
+
requestBody: z.object({
|
|
465
|
+
path: z.string().describe("Relative file path"),
|
|
466
|
+
content: z.string().describe("File content").optional(),
|
|
467
|
+
encoding: z
|
|
468
|
+
.string()
|
|
469
|
+
.describe("Content encoding (base64 or utf-8)")
|
|
470
|
+
.optional(),
|
|
471
|
+
}),
|
|
472
|
+
responseBody: z.object({
|
|
473
|
+
path: z.string(),
|
|
474
|
+
size: z.number(),
|
|
475
|
+
}),
|
|
400
476
|
handler: (ctx) => handleWorkspaceWrite(ctx),
|
|
401
477
|
},
|
|
402
478
|
{
|
|
403
479
|
endpoint: "workspace/mkdir",
|
|
404
480
|
method: "POST",
|
|
481
|
+
summary: "Create workspace directory",
|
|
482
|
+
description: "Create directories recursively in the workspace.",
|
|
483
|
+
tags: ["workspace"],
|
|
484
|
+
requestBody: z.object({
|
|
485
|
+
path: z.string().describe("Relative directory path"),
|
|
486
|
+
}),
|
|
487
|
+
responseBody: z.object({
|
|
488
|
+
path: z.string(),
|
|
489
|
+
}),
|
|
405
490
|
handler: (ctx) => handleWorkspaceMkdir(ctx),
|
|
406
491
|
},
|
|
407
492
|
{
|
|
408
493
|
endpoint: "workspace/rename",
|
|
409
494
|
method: "POST",
|
|
495
|
+
summary: "Rename workspace entry",
|
|
496
|
+
description: "Rename or move a file or directory in the workspace.",
|
|
497
|
+
tags: ["workspace"],
|
|
498
|
+
requestBody: z.object({
|
|
499
|
+
oldPath: z.string().describe("Current relative path"),
|
|
500
|
+
newPath: z.string().describe("New relative path"),
|
|
501
|
+
}),
|
|
502
|
+
responseBody: z.object({
|
|
503
|
+
oldPath: z.string(),
|
|
504
|
+
newPath: z.string(),
|
|
505
|
+
}),
|
|
410
506
|
handler: (ctx) => handleWorkspaceRename(ctx),
|
|
411
507
|
},
|
|
412
508
|
{
|
|
413
509
|
endpoint: "workspace/delete",
|
|
414
510
|
method: "POST",
|
|
511
|
+
summary: "Delete workspace entry",
|
|
512
|
+
description: "Delete a file or directory from the workspace.",
|
|
513
|
+
tags: ["workspace"],
|
|
514
|
+
requestBody: z.object({
|
|
515
|
+
path: z.string().describe("Relative path to delete"),
|
|
516
|
+
}),
|
|
415
517
|
handler: (ctx) => handleWorkspaceDelete(ctx),
|
|
416
518
|
},
|
|
417
519
|
];
|
|
@@ -188,7 +188,7 @@ async function runScheduleOnce(
|
|
|
188
188
|
);
|
|
189
189
|
const { runTask } = await import("../tasks/task-runner.js");
|
|
190
190
|
const result = await runTask(
|
|
191
|
-
{ taskId, workingDir: process.cwd(), source: "schedule" },
|
|
191
|
+
{ taskId, workingDir: process.cwd(), source: "schedule", scheduleJobId: job.id },
|
|
192
192
|
processMessage as (
|
|
193
193
|
conversationId: string,
|
|
194
194
|
message: string,
|
|
@@ -196,6 +196,12 @@ async function runScheduleOnce(
|
|
|
196
196
|
) => Promise<void>,
|
|
197
197
|
);
|
|
198
198
|
|
|
199
|
+
onScheduleConversationCreated?.({
|
|
200
|
+
conversationId: result.conversationId,
|
|
201
|
+
scheduleJobId: job.id,
|
|
202
|
+
title: result.status === "failed" ? `${job.name}: Error` : job.name,
|
|
203
|
+
});
|
|
204
|
+
|
|
199
205
|
// Track the schedule run using the task's conversation
|
|
200
206
|
const runId = createScheduleRun(job.id, result.conversationId);
|
|
201
207
|
if (result.status === "failed") {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Security — Agent Instructions
|
|
2
|
+
|
|
3
|
+
## Integration API Key Patterns
|
|
4
|
+
|
|
5
|
+
When adding a new third-party integration, check whether the service uses a recognizable API key prefix (e.g., `lin_api_`, `sk-ant-`, `ghp_`). If it does, add a corresponding entry to `PREFIX_PATTERNS` in `secret-patterns.ts`. This is the single source of truth for prefix-based secret detection — ingress blocking, tool output scanning, and log redaction all consume this list.
|
|
6
|
+
|
|
7
|
+
OAuth-only services with opaque access tokens (no fixed prefix) do not need a pattern.
|
|
@@ -30,7 +30,7 @@ export interface CredentialListResult {
|
|
|
30
30
|
// ---------------------------------------------------------------------------
|
|
31
31
|
|
|
32
32
|
export interface CredentialBackend {
|
|
33
|
-
/** Human-readable name for logging (e.g. "
|
|
33
|
+
/** Human-readable name for logging (e.g. "encrypted-store"). */
|
|
34
34
|
readonly name: string;
|
|
35
35
|
|
|
36
36
|
/** Whether this backend is currently reachable. Sync and cheap. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Encrypted-at-rest key storage
|
|
2
|
+
* Encrypted-at-rest key storage.
|
|
3
3
|
*
|
|
4
4
|
* v2 stores use a cryptographically random 32-byte `store.key` file as the
|
|
5
5
|
* AES-256-GCM key directly (no key derivation). The key file lives alongside
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* v1 stores (legacy) derived the AES key from machine-specific entropy via
|
|
9
9
|
* PBKDF2. Existing v1 stores are automatically migrated to v2 on first access.
|
|
10
10
|
*
|
|
11
|
-
* Provides the
|
|
11
|
+
* Provides the standard get/set/delete credential storage interface.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import {
|
|
@@ -418,7 +418,7 @@ function decrypt(entry: EncryptedEntry, key: Buffer): string {
|
|
|
418
418
|
}
|
|
419
419
|
|
|
420
420
|
// ---------------------------------------------------------------------------
|
|
421
|
-
// Public API
|
|
421
|
+
// Public API
|
|
422
422
|
// ---------------------------------------------------------------------------
|
|
423
423
|
|
|
424
424
|
/**
|
package/src/security/oauth2.ts
CHANGED
|
@@ -289,6 +289,15 @@ function startLoopbackServerAndWaitForCode(
|
|
|
289
289
|
let boundRedirectUri = "";
|
|
290
290
|
|
|
291
291
|
const server: Server = createServer((req, res) => {
|
|
292
|
+
log.info(
|
|
293
|
+
{
|
|
294
|
+
method: req.method,
|
|
295
|
+
path: new URL(req.url ?? "/", "http://127.0.0.1").pathname,
|
|
296
|
+
settled,
|
|
297
|
+
},
|
|
298
|
+
"oauth2 loopback: received request",
|
|
299
|
+
);
|
|
300
|
+
|
|
292
301
|
if (settled) {
|
|
293
302
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
294
303
|
res.end(renderLoopbackPage("Authorization already completed", false));
|
|
@@ -298,6 +307,10 @@ function startLoopbackServerAndWaitForCode(
|
|
|
298
307
|
const url = new URL(req.url ?? "/", `http://127.0.0.1`);
|
|
299
308
|
|
|
300
309
|
if (url.pathname !== LOOPBACK_CALLBACK_PATH) {
|
|
310
|
+
log.info(
|
|
311
|
+
{ pathname: url.pathname },
|
|
312
|
+
"oauth2 loopback: non-callback path, returning 404",
|
|
313
|
+
);
|
|
301
314
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
302
315
|
res.end("Not found");
|
|
303
316
|
return;
|
|
@@ -308,6 +321,7 @@ function startLoopbackServerAndWaitForCode(
|
|
|
308
321
|
const error = url.searchParams.get("error");
|
|
309
322
|
|
|
310
323
|
if (callbackState !== state) {
|
|
324
|
+
log.warn("oauth2 loopback: state mismatch in callback");
|
|
311
325
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
312
326
|
res.end(renderLoopbackPage("Invalid state parameter", false));
|
|
313
327
|
return;
|
|
@@ -317,6 +331,10 @@ function startLoopbackServerAndWaitForCode(
|
|
|
317
331
|
|
|
318
332
|
if (error) {
|
|
319
333
|
const errorDesc = url.searchParams.get("error_description") ?? error;
|
|
334
|
+
log.error(
|
|
335
|
+
{ error, errorDesc },
|
|
336
|
+
"oauth2 loopback: authorization denied by user/provider",
|
|
337
|
+
);
|
|
320
338
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
321
339
|
res.end(
|
|
322
340
|
renderLoopbackPage(`Authorization failed: ${errorDesc}`, false),
|
|
@@ -327,6 +345,7 @@ function startLoopbackServerAndWaitForCode(
|
|
|
327
345
|
}
|
|
328
346
|
|
|
329
347
|
if (!code) {
|
|
348
|
+
log.error("oauth2 loopback: callback missing authorization code");
|
|
330
349
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
331
350
|
res.end(renderLoopbackPage("Missing authorization code", false));
|
|
332
351
|
cleanup();
|
|
@@ -334,6 +353,9 @@ function startLoopbackServerAndWaitForCode(
|
|
|
334
353
|
return;
|
|
335
354
|
}
|
|
336
355
|
|
|
356
|
+
log.info(
|
|
357
|
+
"oauth2 loopback: authorization code received, exchanging for tokens",
|
|
358
|
+
);
|
|
337
359
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
338
360
|
res.end(
|
|
339
361
|
renderLoopbackPage(
|
|
@@ -347,6 +369,10 @@ function startLoopbackServerAndWaitForCode(
|
|
|
347
369
|
|
|
348
370
|
const timeout = setTimeout(() => {
|
|
349
371
|
if (!settled) {
|
|
372
|
+
log.warn(
|
|
373
|
+
{ timeoutMs: LOOPBACK_TIMEOUT_MS, state },
|
|
374
|
+
"oauth2 loopback: callback timed out — no authorization code received",
|
|
375
|
+
);
|
|
350
376
|
settled = true;
|
|
351
377
|
cleanup();
|
|
352
378
|
reject(new Error("OAuth2 loopback callback timed out"));
|
|
@@ -359,10 +385,20 @@ function startLoopbackServerAndWaitForCode(
|
|
|
359
385
|
server.close();
|
|
360
386
|
}
|
|
361
387
|
|
|
388
|
+
log.info(
|
|
389
|
+
{ requestedPort: loopbackPort ?? "random" },
|
|
390
|
+
"oauth2 loopback: binding server",
|
|
391
|
+
);
|
|
392
|
+
|
|
362
393
|
server.listen(loopbackPort ?? 0, "localhost", () => {
|
|
363
394
|
const addr = server.address() as { port: number };
|
|
364
395
|
boundRedirectUri = `http://localhost:${addr.port}${LOOPBACK_CALLBACK_PATH}`;
|
|
365
396
|
|
|
397
|
+
log.info(
|
|
398
|
+
{ port: addr.port, redirectUri: boundRedirectUri },
|
|
399
|
+
"oauth2 loopback: server listening",
|
|
400
|
+
);
|
|
401
|
+
|
|
366
402
|
const authParams = new URLSearchParams({
|
|
367
403
|
...config.extraParams,
|
|
368
404
|
client_id: config.clientId,
|
|
@@ -375,10 +411,19 @@ function startLoopbackServerAndWaitForCode(
|
|
|
375
411
|
});
|
|
376
412
|
|
|
377
413
|
const authUrl = `${config.authUrl}?${authParams}`;
|
|
414
|
+
log.info(
|
|
415
|
+
{ authUrlLength: authUrl.length, state },
|
|
416
|
+
"oauth2 loopback: built auth URL, calling openUrl callback",
|
|
417
|
+
);
|
|
378
418
|
callbacks.openUrl(authUrl);
|
|
419
|
+
log.info("oauth2 loopback: openUrl callback returned");
|
|
379
420
|
});
|
|
380
421
|
|
|
381
422
|
server.on("error", (err) => {
|
|
423
|
+
log.error(
|
|
424
|
+
{ err: err.message, loopbackPort },
|
|
425
|
+
"oauth2 loopback: server error",
|
|
426
|
+
);
|
|
382
427
|
if (!settled) {
|
|
383
428
|
settled = true;
|
|
384
429
|
cleanup();
|
|
@@ -687,6 +732,16 @@ export async function startOAuth2Flow(
|
|
|
687
732
|
const transport =
|
|
688
733
|
options?.callbackTransport ?? (hasPublicUrl ? "gateway" : "loopback");
|
|
689
734
|
|
|
735
|
+
log.info(
|
|
736
|
+
{
|
|
737
|
+
transport,
|
|
738
|
+
hasPublicUrl,
|
|
739
|
+
explicitTransport: options?.callbackTransport,
|
|
740
|
+
loopbackPort: options?.loopbackPort,
|
|
741
|
+
},
|
|
742
|
+
"startOAuth2Flow: resolved transport",
|
|
743
|
+
);
|
|
744
|
+
|
|
690
745
|
if (transport === "gateway") {
|
|
691
746
|
if (!hasPublicUrl) {
|
|
692
747
|
throw new Error(
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ingress secret detection for user messages.
|
|
3
|
+
*
|
|
4
|
+
* Consumes `PREFIX_PATTERNS` from `secret-patterns.ts` — the single source
|
|
5
|
+
* of truth for prefix-based secret detection. This module intentionally
|
|
6
|
+
* does NOT import `scanText()` or any entropy/encoding logic to avoid
|
|
7
|
+
* false positives on legitimate user input.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { getConfig } from "../config/loader.js";
|
|
11
|
+
import { isAllowlisted } from "./secret-allowlist.js";
|
|
12
|
+
import { PREFIX_PATTERNS } from "./secret-patterns.js";
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Types
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
export interface IngressCheckResult {
|
|
19
|
+
blocked: boolean;
|
|
20
|
+
detectedTypes: string[];
|
|
21
|
+
userNotice?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Placeholder detection (inline — not imported from secret-scanner.ts)
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
const KNOWN_PLACEHOLDERS = new Set([
|
|
29
|
+
"your-api-key-here",
|
|
30
|
+
"your_api_key_here",
|
|
31
|
+
"insert-your-key-here",
|
|
32
|
+
"insert_your_key_here",
|
|
33
|
+
"replace-with-your-key",
|
|
34
|
+
"replace_with_your_key",
|
|
35
|
+
"xxx",
|
|
36
|
+
"xxxxxxxx",
|
|
37
|
+
"test",
|
|
38
|
+
"example",
|
|
39
|
+
"sample",
|
|
40
|
+
"demo",
|
|
41
|
+
"placeholder",
|
|
42
|
+
"changeme",
|
|
43
|
+
"CHANGEME",
|
|
44
|
+
"TODO",
|
|
45
|
+
"FIXME",
|
|
46
|
+
"your-token-here",
|
|
47
|
+
"your_token_here",
|
|
48
|
+
"my-api-key",
|
|
49
|
+
"my_api_key",
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
const PLACEHOLDER_PREFIXES = [
|
|
53
|
+
"sk-test-",
|
|
54
|
+
"sk_test_",
|
|
55
|
+
"fake_",
|
|
56
|
+
"fake-",
|
|
57
|
+
"dummy_",
|
|
58
|
+
"dummy-",
|
|
59
|
+
"test_",
|
|
60
|
+
"test-",
|
|
61
|
+
"example_",
|
|
62
|
+
"example-",
|
|
63
|
+
"sample_",
|
|
64
|
+
"sample-",
|
|
65
|
+
"mock_",
|
|
66
|
+
"mock-",
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Check if the text immediately before a matched value indicates
|
|
71
|
+
* a placeholder context (e.g. "fake_", "test_").
|
|
72
|
+
*/
|
|
73
|
+
function isPlaceholderContext(preContext: string): boolean {
|
|
74
|
+
const lower = preContext.toLowerCase();
|
|
75
|
+
for (const prefix of PLACEHOLDER_PREFIXES) {
|
|
76
|
+
if (lower.endsWith(prefix)) return true;
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Check if a matched value is a placeholder/test value that should not
|
|
83
|
+
* trigger blocking.
|
|
84
|
+
*/
|
|
85
|
+
function isPlaceholder(value: string): boolean {
|
|
86
|
+
const lower = value.toLowerCase();
|
|
87
|
+
|
|
88
|
+
// Known placeholder values
|
|
89
|
+
if (KNOWN_PLACEHOLDERS.has(lower)) return true;
|
|
90
|
+
|
|
91
|
+
// Placeholder prefixes
|
|
92
|
+
for (const prefix of PLACEHOLDER_PREFIXES) {
|
|
93
|
+
if (lower.startsWith(prefix)) return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Repeated characters in the variable portion (e.g. "AKIA" + "X" x 16)
|
|
97
|
+
// Strip known prefixes to isolate the variable part
|
|
98
|
+
const variablePart = value
|
|
99
|
+
.replace(
|
|
100
|
+
/^(?:AKIA|gh[pousr]_|github_pat_|glpat-|sk_live_|rk_live_|xoxb-|xoxp-|xapp-|sk-ant-|sk-proj-|sk-or-v1-|AIza|GOCSPX-|SK|SG\.|npm_|pypi-|key-|lin_api_|ntn_|fw_|pplx-|-----BEGIN [A-Z ]*PRIVATE KEY-----)/,
|
|
101
|
+
"",
|
|
102
|
+
)
|
|
103
|
+
.replace(/[^A-Za-z0-9]/g, "");
|
|
104
|
+
if (variablePart.length >= 8) {
|
|
105
|
+
const firstChar = variablePart[0];
|
|
106
|
+
if (variablePart.split("").every((c) => c === firstChar)) return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// Public API
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Check user message content for high-confidence secret patterns.
|
|
118
|
+
*
|
|
119
|
+
* Returns `{ blocked: true, detectedTypes, userNotice }` if secrets are
|
|
120
|
+
* found and blocking is enabled, otherwise `{ blocked: false }`.
|
|
121
|
+
*/
|
|
122
|
+
export function checkIngressForSecrets(content: string): IngressCheckResult {
|
|
123
|
+
const config = getConfig();
|
|
124
|
+
const secretDetection = config?.secretDetection;
|
|
125
|
+
|
|
126
|
+
// Bail if secret detection config is missing or entirely disabled
|
|
127
|
+
if (!secretDetection?.enabled) {
|
|
128
|
+
return { blocked: false, detectedTypes: [] };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Bail if ingress blocking is disabled
|
|
132
|
+
if (!secretDetection.blockIngress) {
|
|
133
|
+
return { blocked: false, detectedTypes: [] };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const detectedTypes: string[] = [];
|
|
137
|
+
|
|
138
|
+
for (const { label, regex } of PREFIX_PATTERNS) {
|
|
139
|
+
// Use a global version to find all matches
|
|
140
|
+
const globalRegex = new RegExp(regex.source, "g");
|
|
141
|
+
let match: RegExpExecArray | null;
|
|
142
|
+
|
|
143
|
+
while ((match = globalRegex.exec(content)) !== null) {
|
|
144
|
+
const value = match[0];
|
|
145
|
+
|
|
146
|
+
// Skip placeholders and test values (check both the match and
|
|
147
|
+
// a small window before it for placeholder prefixes like "fake_")
|
|
148
|
+
const contextStart = Math.max(0, match.index - 10);
|
|
149
|
+
const preContext = content.slice(contextStart, match.index);
|
|
150
|
+
if (isPlaceholder(value) || isPlaceholderContext(preContext)) continue;
|
|
151
|
+
|
|
152
|
+
// Skip user-allowlisted values
|
|
153
|
+
if (isAllowlisted(value)) continue;
|
|
154
|
+
|
|
155
|
+
if (!detectedTypes.includes(label)) {
|
|
156
|
+
detectedTypes.push(label);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (detectedTypes.length === 0) {
|
|
162
|
+
return { blocked: false, detectedTypes: [] };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
blocked: true,
|
|
167
|
+
detectedTypes,
|
|
168
|
+
userNotice:
|
|
169
|
+
`Message blocked: detected ` +
|
|
170
|
+
`${detectedTypes.length === 1 ? "a potential credential" : "potential credentials"} ` +
|
|
171
|
+
`(${detectedTypes.join(", ")}). ` +
|
|
172
|
+
`Use the secure credential prompt to provide sensitive values safely.`,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared prefix-based secret patterns — the single source of truth.
|
|
3
|
+
*
|
|
4
|
+
* Ingress blocking, tool output scanning, and log redaction all consume
|
|
5
|
+
* this list. When adding a new integration, add its API key pattern here.
|
|
6
|
+
*
|
|
7
|
+
* This module is intentionally data-only: no imports, no entropy logic,
|
|
8
|
+
* no config — safe for hot-path consumers like log serializers.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Types
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
export interface SecretPrefixPattern {
|
|
16
|
+
/** Human-readable label shown in block notices and redaction tags. */
|
|
17
|
+
label: string;
|
|
18
|
+
/**
|
|
19
|
+
* Regex that matches the token value. Must NOT include the `g` flag or
|
|
20
|
+
* capture groups — consumers add those as needed.
|
|
21
|
+
*/
|
|
22
|
+
regex: RegExp;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Prefix patterns
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* High-confidence, prefix-based secret patterns.
|
|
31
|
+
*
|
|
32
|
+
* Each entry matches a known API key / token format by its distinctive
|
|
33
|
+
* prefix. Patterns that require surrounding context (entropy analysis,
|
|
34
|
+
* keyword proximity, URL structure) do NOT belong here — they stay in
|
|
35
|
+
* `secret-scanner.ts` as scanner-only patterns.
|
|
36
|
+
*
|
|
37
|
+
* **When adding a new third-party integration, add its API key pattern
|
|
38
|
+
* here.** If the service uses only opaque OAuth access tokens (no fixed
|
|
39
|
+
* prefix), no pattern is needed.
|
|
40
|
+
*/
|
|
41
|
+
export const PREFIX_PATTERNS: SecretPrefixPattern[] = [
|
|
42
|
+
// -- AWS --
|
|
43
|
+
{ label: "AWS Access Key", regex: /AKIA[0-9A-Z]{16}/ },
|
|
44
|
+
|
|
45
|
+
// -- GitHub --
|
|
46
|
+
{ label: "GitHub Token", regex: /gh[pousr]_[A-Za-z0-9_]{36,}/ },
|
|
47
|
+
{ label: "GitHub Fine-Grained PAT", regex: /github_pat_[A-Za-z0-9_]{22,}/ },
|
|
48
|
+
|
|
49
|
+
// -- GitLab --
|
|
50
|
+
{ label: "GitLab Token", regex: /glpat-[A-Za-z0-9\-_]{20,}/ },
|
|
51
|
+
|
|
52
|
+
// -- Stripe --
|
|
53
|
+
{ label: "Stripe Secret Key", regex: /sk_live_[A-Za-z0-9]{24,}/ },
|
|
54
|
+
{ label: "Stripe Restricted Key", regex: /rk_live_[A-Za-z0-9]{24,}/ },
|
|
55
|
+
|
|
56
|
+
// -- Slack --
|
|
57
|
+
{
|
|
58
|
+
label: "Slack Bot Token",
|
|
59
|
+
regex: /xoxb-[0-9]{10,}-[0-9]{10,}-[A-Za-z0-9]{24,}/,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
label: "Slack User Token",
|
|
63
|
+
regex: /xoxp-[0-9]{10,}-[0-9]{10,}-[0-9]{10,}-[a-f0-9]{32}/,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
label: "Slack App Token",
|
|
67
|
+
regex: /xapp-[0-9]+-[A-Za-z0-9]+-[0-9]+-[A-Za-z0-9]+/,
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// -- Telegram --
|
|
71
|
+
{
|
|
72
|
+
label: "Telegram Bot Token",
|
|
73
|
+
// Format: <bot_id>:<secret> where bot_id is 8–10 digits, secret is 35 chars
|
|
74
|
+
regex: /[0-9]{8,10}:[A-Za-z0-9_-]{35}/,
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// -- Anthropic --
|
|
78
|
+
{ label: "Anthropic API Key", regex: /sk-ant-[A-Za-z0-9\-_]{80,}/ },
|
|
79
|
+
|
|
80
|
+
// -- OpenAI --
|
|
81
|
+
{
|
|
82
|
+
label: "OpenAI API Key",
|
|
83
|
+
regex: /sk-[A-Za-z0-9]{20}T3BlbkFJ[A-Za-z0-9]{20}/,
|
|
84
|
+
},
|
|
85
|
+
{ label: "OpenAI Project Key", regex: /sk-proj-[A-Za-z0-9\-_]{40,}/ },
|
|
86
|
+
|
|
87
|
+
// -- Google --
|
|
88
|
+
{ label: "Google API Key", regex: /AIza[A-Za-z0-9\-_]{35}/ },
|
|
89
|
+
{
|
|
90
|
+
label: "Google OAuth Client Secret",
|
|
91
|
+
regex: /GOCSPX-[A-Za-z0-9\-_]{28}/,
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
// -- Twilio --
|
|
95
|
+
{ label: "Twilio API Key", regex: /SK[0-9a-f]{32}/ },
|
|
96
|
+
|
|
97
|
+
// -- SendGrid --
|
|
98
|
+
{
|
|
99
|
+
label: "SendGrid API Key",
|
|
100
|
+
regex: /SG\.[A-Za-z0-9\-_]{22}\.[A-Za-z0-9\-_]{43}/,
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
// -- Mailgun --
|
|
104
|
+
{ label: "Mailgun API Key", regex: /key-[A-Za-z0-9]{32}/ },
|
|
105
|
+
|
|
106
|
+
// -- npm --
|
|
107
|
+
{ label: "npm Token", regex: /npm_[A-Za-z0-9]{36}/ },
|
|
108
|
+
|
|
109
|
+
// -- PyPI --
|
|
110
|
+
{ label: "PyPI API Token", regex: /pypi-[A-Za-z0-9\-_]{50,}/ },
|
|
111
|
+
|
|
112
|
+
// -- Private keys --
|
|
113
|
+
{
|
|
114
|
+
label: "Private Key",
|
|
115
|
+
regex:
|
|
116
|
+
/-----BEGIN (?:RSA |DSA |EC |OPENSSH |PGP )?PRIVATE KEY(?:\s+BLOCK)?-----/,
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
// -- Linear --
|
|
120
|
+
{ label: "Linear API Key", regex: /lin_api_[A-Za-z0-9]{32,}/ },
|
|
121
|
+
|
|
122
|
+
// -- Notion --
|
|
123
|
+
{ label: "Notion Integration Token", regex: /ntn_[A-Za-z0-9]{40,}/ },
|
|
124
|
+
|
|
125
|
+
// -- OpenRouter --
|
|
126
|
+
{ label: "OpenRouter API Key", regex: /sk-or-v1-[A-Za-z0-9\-_]{40,}/ },
|
|
127
|
+
|
|
128
|
+
// -- Fireworks --
|
|
129
|
+
{ label: "Fireworks API Key", regex: /fw_[A-Za-z0-9]{32,}/ },
|
|
130
|
+
|
|
131
|
+
// -- Perplexity --
|
|
132
|
+
{ label: "Perplexity API Key", regex: /pplx-[A-Za-z0-9]{40,}/ },
|
|
133
|
+
];
|