pushary 1.8.0

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.
Files changed (186) hide show
  1. package/CHANGELOG.md +1943 -0
  2. package/LICENSE +21 -0
  3. package/README.md +330 -0
  4. package/data/SKILL.md +591 -0
  5. package/data/cowork/SKILL.md +77 -0
  6. package/data/cursor-plugin/.cursor-plugin/plugin.json +25 -0
  7. package/data/cursor-plugin/CHANGELOG.md +70 -0
  8. package/data/cursor-plugin/CONTRIBUTING.md +40 -0
  9. package/data/cursor-plugin/LICENSE +21 -0
  10. package/data/cursor-plugin/README.md +113 -0
  11. package/data/cursor-plugin/SECURITY.md +33 -0
  12. package/data/cursor-plugin/assets/logo.png +0 -0
  13. package/data/cursor-plugin/commands/notify-when-done.md +14 -0
  14. package/data/cursor-plugin/commands/pushary-test.md +13 -0
  15. package/data/cursor-plugin/hooks/hooks.json +75 -0
  16. package/data/cursor-plugin/mcp.json +11 -0
  17. package/data/cursor-plugin/rules/pushary.mdc +40 -0
  18. package/data/cursor-plugin/scripts/pushary-gate.mjs +724 -0
  19. package/data/cursor-plugin/scripts/pushary-gate.test.mjs +137 -0
  20. package/data/cursor-plugin/scripts/redaction.mjs +51 -0
  21. package/data/cursor-plugin/skills/pushary/SKILL.md +584 -0
  22. package/data/vscode-plugin/.claude-plugin/plugin.json +28 -0
  23. package/data/vscode-plugin/.mcp.json +11 -0
  24. package/data/vscode-plugin/CHANGELOG.md +49 -0
  25. package/data/vscode-plugin/CONTRIBUTING.md +40 -0
  26. package/data/vscode-plugin/LICENSE +21 -0
  27. package/data/vscode-plugin/README.md +128 -0
  28. package/data/vscode-plugin/SECURITY.md +56 -0
  29. package/data/vscode-plugin/assets/logo.png +0 -0
  30. package/data/vscode-plugin/commands/notify-when-done.md +14 -0
  31. package/data/vscode-plugin/commands/pushary-test.md +13 -0
  32. package/data/vscode-plugin/hooks/hooks.json +60 -0
  33. package/data/vscode-plugin/scripts/pushary-gate.mjs +762 -0
  34. package/data/vscode-plugin/scripts/redaction.mjs +51 -0
  35. package/data/vscode-plugin/skills/pushary/SKILL.md +584 -0
  36. package/dist/bin/pushary-bell-hook.d.ts +1 -0
  37. package/dist/bin/pushary-bell-hook.js +46 -0
  38. package/dist/bin/pushary-bell.d.ts +1 -0
  39. package/dist/bin/pushary-bell.js +146 -0
  40. package/dist/bin/pushary-claude.d.ts +1 -0
  41. package/dist/bin/pushary-claude.js +1916 -0
  42. package/dist/bin/pushary-clean.d.ts +1 -0
  43. package/dist/bin/pushary-clean.js +1300 -0
  44. package/dist/bin/pushary-codex-bridge.d.ts +1 -0
  45. package/dist/bin/pushary-codex-bridge.js +599 -0
  46. package/dist/bin/pushary-codex-hook.d.ts +1 -0
  47. package/dist/bin/pushary-codex-hook.js +886 -0
  48. package/dist/bin/pushary-codex.d.ts +1 -0
  49. package/dist/bin/pushary-codex.js +125 -0
  50. package/dist/bin/pushary-connect.d.ts +1 -0
  51. package/dist/bin/pushary-connect.js +100 -0
  52. package/dist/bin/pushary-cowork.d.ts +1 -0
  53. package/dist/bin/pushary-cowork.js +36 -0
  54. package/dist/bin/pushary-daemon-supervisor.d.ts +1 -0
  55. package/dist/bin/pushary-daemon-supervisor.js +27 -0
  56. package/dist/bin/pushary-daemon.d.ts +1 -0
  57. package/dist/bin/pushary-daemon.js +878 -0
  58. package/dist/bin/pushary-disconnect.d.ts +1 -0
  59. package/dist/bin/pushary-disconnect.js +264 -0
  60. package/dist/bin/pushary-doctor.d.ts +1 -0
  61. package/dist/bin/pushary-doctor.js +1433 -0
  62. package/dist/bin/pushary-elicitation-hook.d.ts +1 -0
  63. package/dist/bin/pushary-elicitation-hook.js +149 -0
  64. package/dist/bin/pushary-gemini-bridge.d.ts +1 -0
  65. package/dist/bin/pushary-gemini-bridge.js +339 -0
  66. package/dist/bin/pushary-gemini-hook.d.ts +1 -0
  67. package/dist/bin/pushary-gemini-hook.js +381 -0
  68. package/dist/bin/pushary-hook.d.ts +1 -0
  69. package/dist/bin/pushary-hook.js +95 -0
  70. package/dist/bin/pushary-login.d.ts +1 -0
  71. package/dist/bin/pushary-login.js +198 -0
  72. package/dist/bin/pushary-logout.d.ts +1 -0
  73. package/dist/bin/pushary-logout.js +147 -0
  74. package/dist/bin/pushary-mcp.d.ts +1 -0
  75. package/dist/bin/pushary-mcp.js +114 -0
  76. package/dist/bin/pushary-mode.d.ts +1 -0
  77. package/dist/bin/pushary-mode.js +130 -0
  78. package/dist/bin/pushary-notification-hook.d.ts +1 -0
  79. package/dist/bin/pushary-notification-hook.js +56 -0
  80. package/dist/bin/pushary-opencode-hook.d.ts +1 -0
  81. package/dist/bin/pushary-opencode-hook.js +338 -0
  82. package/dist/bin/pushary-permission-denied-hook.d.ts +1 -0
  83. package/dist/bin/pushary-permission-denied-hook.js +60 -0
  84. package/dist/bin/pushary-permission-hook.d.ts +1 -0
  85. package/dist/bin/pushary-permission-hook.js +65 -0
  86. package/dist/bin/pushary-post-hook.d.ts +1 -0
  87. package/dist/bin/pushary-post-hook.js +70 -0
  88. package/dist/bin/pushary-prompt-hook.d.ts +1 -0
  89. package/dist/bin/pushary-prompt-hook.js +61 -0
  90. package/dist/bin/pushary-session-end-hook.d.ts +1 -0
  91. package/dist/bin/pushary-session-end-hook.js +59 -0
  92. package/dist/bin/pushary-session-start-hook.d.ts +1 -0
  93. package/dist/bin/pushary-session-start-hook.js +72 -0
  94. package/dist/bin/pushary-setup.d.ts +1 -0
  95. package/dist/bin/pushary-setup.js +2660 -0
  96. package/dist/bin/pushary-stats.d.ts +1 -0
  97. package/dist/bin/pushary-stats.js +44 -0
  98. package/dist/bin/pushary-status.d.ts +1 -0
  99. package/dist/bin/pushary-status.js +262 -0
  100. package/dist/bin/pushary-stop-hook.d.ts +1 -0
  101. package/dist/bin/pushary-stop-hook.js +63 -0
  102. package/dist/bin/pushary-stopfailure-hook.d.ts +1 -0
  103. package/dist/bin/pushary-stopfailure-hook.js +56 -0
  104. package/dist/bin/pushary-suggestions.d.ts +1 -0
  105. package/dist/bin/pushary-suggestions.js +100 -0
  106. package/dist/bin/pushary-transcript-register.d.ts +1 -0
  107. package/dist/bin/pushary-transcript-register.js +40 -0
  108. package/dist/bin/pushary-transcripts.d.ts +1 -0
  109. package/dist/bin/pushary-transcripts.js +77 -0
  110. package/dist/bin/pushary-upgrade.d.ts +1 -0
  111. package/dist/bin/pushary-upgrade.js +599 -0
  112. package/dist/bin/pushary-wait.d.ts +1 -0
  113. package/dist/bin/pushary-wait.js +122 -0
  114. package/dist/bin/pushary.d.ts +1 -0
  115. package/dist/bin/pushary.js +74 -0
  116. package/dist/chunk-2ABTSGFT.js +173 -0
  117. package/dist/chunk-2OY3ZZ5N.js +124 -0
  118. package/dist/chunk-3EGEA4KH.js +44 -0
  119. package/dist/chunk-3EVPNIBE.js +185 -0
  120. package/dist/chunk-5OP5MQI7.js +45 -0
  121. package/dist/chunk-6J2JC2RT.js +149 -0
  122. package/dist/chunk-7QLSKOSU.js +19 -0
  123. package/dist/chunk-7Z7Q4GGS.js +88 -0
  124. package/dist/chunk-A2A2YTMG.js +835 -0
  125. package/dist/chunk-AHV4LNB5.js +377 -0
  126. package/dist/chunk-AXPCESYO.js +197 -0
  127. package/dist/chunk-C2WCPBF7.js +86 -0
  128. package/dist/chunk-CJVVKOSR.js +73 -0
  129. package/dist/chunk-CULUZTWQ.js +2117 -0
  130. package/dist/chunk-CVQYGMSR.js +142 -0
  131. package/dist/chunk-CVWG2N3Y.js +16 -0
  132. package/dist/chunk-D2FX3EPW.js +15 -0
  133. package/dist/chunk-DB3ONZB4.js +44 -0
  134. package/dist/chunk-DE4Y6TCC.js +160 -0
  135. package/dist/chunk-E4FJTUH4.js +249 -0
  136. package/dist/chunk-EPCXUP3P.js +41 -0
  137. package/dist/chunk-EX3GAPA4.js +44 -0
  138. package/dist/chunk-EYK3GSRH.js +143 -0
  139. package/dist/chunk-GMXKITVA.js +70 -0
  140. package/dist/chunk-GPEGOGRJ.js +49 -0
  141. package/dist/chunk-GU3EJCVV.js +43 -0
  142. package/dist/chunk-HQ6G3B5R.js +59 -0
  143. package/dist/chunk-HZVVNGEW.js +22 -0
  144. package/dist/chunk-IPVKH2ST.js +231 -0
  145. package/dist/chunk-J5TIV3J6.js +238 -0
  146. package/dist/chunk-JU6W3XAU.js +64 -0
  147. package/dist/chunk-JYG4B33G.js +227 -0
  148. package/dist/chunk-JZTHGAPA.js +503 -0
  149. package/dist/chunk-KGDWDSNL.js +102 -0
  150. package/dist/chunk-KVQBWI5T.js +99 -0
  151. package/dist/chunk-KZERVKTD.js +16 -0
  152. package/dist/chunk-LXQ5FBBD.js +47 -0
  153. package/dist/chunk-M5ICYGHT.js +138 -0
  154. package/dist/chunk-M5JDZ45W.js +943 -0
  155. package/dist/chunk-MDEPU45E.js +1226 -0
  156. package/dist/chunk-MPWXGONV.js +157 -0
  157. package/dist/chunk-N6IOSZOE.js +185 -0
  158. package/dist/chunk-NGDD6TXY.js +192 -0
  159. package/dist/chunk-NQTHFF4W.js +2830 -0
  160. package/dist/chunk-OKXS7WDZ.js +68 -0
  161. package/dist/chunk-OLQRRFBX.js +21 -0
  162. package/dist/chunk-P7WQEVWA.js +307 -0
  163. package/dist/chunk-POFBE6ZY.js +12 -0
  164. package/dist/chunk-PQ4K74WL.js +30 -0
  165. package/dist/chunk-PUZZELE6.js +37 -0
  166. package/dist/chunk-Q7E4I6UA.js +767 -0
  167. package/dist/chunk-QCGNGEGE.js +15 -0
  168. package/dist/chunk-R7437YI3.js +151 -0
  169. package/dist/chunk-RHR6NARM.js +305 -0
  170. package/dist/chunk-SAXBC4AZ.js +60 -0
  171. package/dist/chunk-SGZJ5LYH.js +76 -0
  172. package/dist/chunk-SIFVFP6T.js +70 -0
  173. package/dist/chunk-SLFABHW3.js +150 -0
  174. package/dist/chunk-T7E75EKA.js +67 -0
  175. package/dist/chunk-TY4JT7W3.js +38 -0
  176. package/dist/chunk-U4TMAANR.js +111 -0
  177. package/dist/chunk-UI36QSBI.js +177 -0
  178. package/dist/chunk-VQKRG3AC.js +339 -0
  179. package/dist/chunk-WE2J62NC.js +1131 -0
  180. package/dist/chunk-XHKBHWLX.js +14 -0
  181. package/dist/chunk-ZSZSSJCV.js +275 -0
  182. package/dist/chunk-ZVSKMPBZ.js +135 -0
  183. package/dist/reapply-CW3MA66V.js +34 -0
  184. package/dist/src/index.d.ts +204 -0
  185. package/dist/src/index.js +64 -0
  186. package/package.json +108 -0
@@ -0,0 +1,137 @@
1
+ // What is left to test in the gate itself.
2
+ //
3
+ // This file used to cover the vendored policy engine: pattern matching, argument
4
+ // rules, the destructive ceiling and repo scoping. None of that lives here any
5
+ // more. The gate asks POST /api/agent/gate, which runs the same `resolveGate` as
6
+ // every other client, and those behaviours are tested once against the engine in
7
+ // packages/contracts/src/gate.test.ts rather than once per copy.
8
+ //
9
+ // What remains is the one thing a server cannot answer: which repository this
10
+ // checkout is in. Deriving it means walking parent directories for a `.git` and
11
+ // reading its config, so the gate still does it and sends the result.
12
+ //
13
+ // Run: node --test scripts/pushary-gate.test.mjs
14
+
15
+ import assert from 'node:assert/strict'
16
+ import { describe, it } from 'node:test'
17
+ import { describeRequest, normalizeRepoRemote, redactSecrets } from './pushary-gate.mjs'
18
+
19
+ describe('repo identity', () => {
20
+ it('collapses the forms of one remote', () => {
21
+ for (const r of ['https://github.com/acme/api.git', 'git@github.com:acme/api.git', 'ssh://git@github.com:22/acme/api.git']) {
22
+ assert.equal(normalizeRepoRemote(r), 'github.com/acme/api', r)
23
+ }
24
+ })
25
+
26
+ it('never lets a credential survive', () => {
27
+ const key = normalizeRepoRemote('https://user:ghp_SECRET@github.com/acme/api.git')
28
+ assert.equal(key, 'github.com/acme/api')
29
+ assert.ok(!key.includes('ghp_') && !key.includes('@'))
30
+ })
31
+
32
+ it('returns undefined without a stable identity', () => {
33
+ for (const r of ['', '../rel', 'file:///Users/dev/repo']) assert.equal(normalizeRepoRemote(r), undefined, r)
34
+ })
35
+ })
36
+
37
+ // The gate answers two Cursor events now, and they arrive on the same stdin with
38
+ // different fields. What each one turns into is the only thing standing between
39
+ // an MCP call and being gated as if it were a shell command.
40
+ describe('what the gate was asked about', () => {
41
+ it('names an MCP call the way every other agent names one', () => {
42
+ const request = describeRequest({
43
+ hook_event_name: 'beforeMCPExecution',
44
+ tool_name: 'create_issue',
45
+ mcp_server_name: 'github',
46
+ tool_input: '{"title":"x"}',
47
+ })
48
+
49
+ // `mcp__<server>__<tool>` is what `validateToolPattern` accepts and what
50
+ // Claude Code sends, so one policy rule covers the tool on both agents. A
51
+ // Cursor-only spelling would silently miss every rule a user already wrote.
52
+ assert.equal(request.toolName, 'mcp__github__create_issue')
53
+ assert.deepEqual(request.toolInputs, [{ tool: 'mcp__github__create_issue', params: '{"title":"x"}' }])
54
+ assert.match(request.display, /create_issue/)
55
+ })
56
+
57
+ it('still reads a shell command, including from a payload with no event name', () => {
58
+ const named = describeRequest({ hook_event_name: 'beforeShellExecution', command: ' rm -rf /tmp/x ' })
59
+ assert.equal(named.toolName, 'Bash')
60
+ assert.equal(named.toolTarget, 'rm -rf')
61
+
62
+ // An older Cursor that omits `hook_event_name` must keep working exactly as
63
+ // it did when shell was the only registered event.
64
+ assert.equal(describeRequest({ command: 'git push' }).toolName, 'Bash')
65
+ })
66
+
67
+ /**
68
+ * `beforeMCPExecution` is registered with NO matcher, so every MCP call in the
69
+ * editor reaches this gate, ours included. Gating our own tools deadlocks: the
70
+ * approval for `ask_user` cannot reach the phone until the `ask_user` call it
71
+ * is gating goes through. With `failClosed: true` on that entry it is worse
72
+ * than a hang, because a timeout turns into a denial of the user's own
73
+ * question.
74
+ *
75
+ * The Claude hook carries this guard three times over and calls it a
76
+ * precaution, because its matcher does not route these there. Here it is the
77
+ * only thing standing between the two.
78
+ */
79
+ it('never gates Pushary\'s own MCP tools', () => {
80
+ for (const tool of ['ask_user', 'wait_for_answer', 'send_notification', 'propose_scope']) {
81
+ assert.equal(
82
+ describeRequest({
83
+ hook_event_name: 'beforeMCPExecution',
84
+ tool_name: tool,
85
+ mcp_server_name: 'pushary',
86
+ tool_input: '{}',
87
+ }),
88
+ null,
89
+ `mcp__pushary__${tool} must reach Cursor's own prompt, not ours`,
90
+ )
91
+ }
92
+
93
+ // A neighbour whose name merely starts the same way is still gated. The
94
+ // guard is on the `mcp__pushary__` prefix, not on "contains pushary".
95
+ assert.equal(
96
+ describeRequest({
97
+ hook_event_name: 'beforeMCPExecution',
98
+ tool_name: 'run',
99
+ mcp_server_name: 'pushary-clone',
100
+ tool_input: '{}',
101
+ }).toolName,
102
+ 'mcp__pushary-clone__run',
103
+ )
104
+ })
105
+
106
+ it('declines an event it does not gate rather than calling it Bash', () => {
107
+ // beforeReadFile is registered by nobody here on purpose: its response
108
+ // schema has no `ask`, so the no-opinion path this gate takes on every error
109
+ // has nothing to return. If one ever arrives, it must not be mistaken for a
110
+ // shell command carrying no command.
111
+ assert.equal(describeRequest({ hook_event_name: 'beforeReadFile', file_path: '/etc/passwd' }), null)
112
+ assert.equal(describeRequest({ hook_event_name: 'beforeMCPExecution' }), null)
113
+ assert.equal(describeRequest({}), null)
114
+ })
115
+ })
116
+
117
+ describe('approval text redaction', () => {
118
+ it('shows a command whole when a credential name only sits next to shell syntax', () => {
119
+ for (const command of [
120
+ 'echo "password=" && rm -rf ~ && echo "x"',
121
+ 'find / -name "token:" -o -delete -o -name "x"',
122
+ "grep -rl foo'password=' . | xargs rm -f 'important file'",
123
+ 'grep "authorization:";rm important-file',
124
+ 'echo "-----BEGIN PRIVATE KEY-----" && rm -rf ~ && echo "-----END PRIVATE KEY-----"',
125
+ 'password= reboot',
126
+ ]) {
127
+ assert.equal(redactSecrets(command), command)
128
+ }
129
+ })
130
+
131
+ it('stops a hidden value at the first space, quote or piece of shell syntax', () => {
132
+ assert.equal(redactSecrets('eval TOKEN="x; rm -rf ~"'), 'eval TOKEN="[redacted]; rm -rf ~"')
133
+ assert.equal(redactSecrets('TOKEN=abc;rm file'), 'TOKEN=[redacted];rm file')
134
+ assert.equal(redactSecrets('rm -rf {password=x,/}'), 'rm -rf {password=[redacted],/}')
135
+ assert.equal(redactSecrets('export API_KEY="abc123" && rm -rf build'), 'export API_KEY="[redacted]" && rm -rf build')
136
+ })
137
+ })
@@ -0,0 +1,51 @@
1
+ // Generated by scripts/generate-editor-redaction.mjs.
2
+ const CREDENTIAL_NAME = String.raw `(?:authorization|secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?`;
3
+ const CREDENTIAL_KEY = String.raw `${CREDENTIAL_NAME}\s*[=:]\s*`;
4
+ const DISPLAYED_CREDENTIAL_KEY = String.raw `${CREDENTIAL_NAME}(?:[ \t]*:[ \t]*|[ \t]+=[ \t]*|=)`;
5
+ const SHELL_INERT_UNIT = String.raw `(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])`;
6
+ const SHELL_INERT_SINGLE_QUOTED_UNIT = String.raw `[A-Za-z0-9_\-./+=:@%^!#\\]`;
7
+ const SHELL_INERT_URL_PASSWORD_UNIT = String.raw `(?:[A-Za-z0-9_\-.+=:%^!#]|\\[^\s'"@/])`;
8
+ const PEM_LINE_BREAK = String.raw `(?:\r?\n|(?:\\r)?\\n)`;
9
+ const credentialAssignmentRule = (key, doubleQuoted, singleQuoted, bare) => ({
10
+ pattern: new RegExp(String.raw `(${key})(?:(")${doubleQuoted}|(')${singleQuoted}|(["']?)${bare})`, 'gi'),
11
+ replacement: '$1$2$3$4[redacted]$2$3',
12
+ });
13
+ const DISPLAYED_SECRET_SHAPES = {
14
+ privateKeyBody: String.raw `${PEM_LINE_BREAK}?(?:(?:Proc-Type|DEK-Info): [A-Za-z0-9,-]+${PEM_LINE_BREAK})*(?:[A-Za-z0-9+/=\r\n]|\\[rn])*?`,
15
+ urlPassword: `${SHELL_INERT_URL_PASSWORD_UNIT}+`,
16
+ authorizationValue: `${SHELL_INERT_UNIT}+`,
17
+ credentialAssignment: credentialAssignmentRule(DISPLAYED_CREDENTIAL_KEY, `${SHELL_INERT_UNIT}*"`, `${SHELL_INERT_SINGLE_QUOTED_UNIT}*'`, `${SHELL_INERT_UNIT}+`),
18
+ };
19
+ const CUT_OFF_SECRET_SHAPES = {
20
+ privateKeyBody: String.raw `[\s\S]*?`,
21
+ urlPassword: String.raw `[^\s@/]+`,
22
+ authorizationValue: String.raw `\S+`,
23
+ credentialAssignment: credentialAssignmentRule(CREDENTIAL_KEY, String.raw `(?:\\[\s\S]|[^"\\])*(?:"|\\?$)`, "[^']*(?:'|$)", String.raw `\S+`),
24
+ };
25
+ const secretRedactionRules = (shapes) => [
26
+ { pattern: /\bpk_[A-Za-z0-9_]+\.[A-Za-z0-9_]+/g, replacement: '[redacted]' },
27
+ { pattern: new RegExp(String.raw `-----BEGIN[A-Z0-9 ]*PRIVATE KEY-----${shapes.privateKeyBody}-----END[A-Z0-9 ]*PRIVATE KEY-----`, 'g'), replacement: '[redacted key]' },
28
+ { pattern: /\bsk-[A-Za-z0-9_-]{16,}\b/g, replacement: '[redacted]' },
29
+ { pattern: /\b[spr]k_(?:live|test)_[A-Za-z0-9]{8,}\b/g, replacement: '[redacted]' },
30
+ { pattern: /\bwhsec_[A-Za-z0-9]{16,}\b/g, replacement: '[redacted]' },
31
+ { pattern: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/g, replacement: '[redacted]' },
32
+ { pattern: /\bgithub_pat_[A-Za-z0-9_]{22,}\b/g, replacement: '[redacted]' },
33
+ { pattern: /\bglpat-[A-Za-z0-9_-]{20,}\b/g, replacement: '[redacted]' },
34
+ { pattern: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, replacement: '[redacted]' },
35
+ { pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g, replacement: '[redacted]' },
36
+ { pattern: /\bAKIA[0-9A-Z]{16}\b/g, replacement: '[redacted]' },
37
+ { pattern: /\bnpm_[A-Za-z0-9]{36}\b/g, replacement: '[redacted]' },
38
+ { pattern: /\bxai-[A-Za-z0-9]{16,}\b/g, replacement: '[redacted]' },
39
+ { pattern: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, replacement: '[redacted]' },
40
+ { pattern: new RegExp(String.raw `\b([a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:)${shapes.urlPassword}@`, 'gi'), replacement: '$1[redacted]@' },
41
+ { pattern: /\bbearer\s+[A-Za-z0-9._~+/=-]+/gi, replacement: 'bearer [redacted]' },
42
+ { pattern: new RegExp(String.raw `\bauthorization:\s*${shapes.authorizationValue}`, 'gi'), replacement: 'authorization: [redacted]' },
43
+ shapes.credentialAssignment,
44
+ ];
45
+ export const SECRET_REDACTION_RULES = secretRedactionRules(DISPLAYED_SECRET_SHAPES);
46
+ const CUT_OFF_TEXT_REDACTION_RULES = secretRedactionRules(CUT_OFF_SECRET_SHAPES);
47
+ const HIGH_ENTROPY_RULE = { pattern: /[A-Za-z0-9+/]{40,}={0,2}/g, replacement: '[redacted]' };
48
+ const applyRedactionRules = (rules, text) => rules.reduce((acc, rule) => acc.replace(rule.pattern, rule.replacement), text);
49
+ export const redactSecrets = (text) => applyRedactionRules(SECRET_REDACTION_RULES, text);
50
+ export const redactSecretsFromContent = (text) => applyRedactionRules(CUT_OFF_TEXT_REDACTION_RULES, text);
51
+ export const redactSecretsDeep = (text) => redactSecrets(text).replace(HIGH_ENTROPY_RULE.pattern, HIGH_ENTROPY_RULE.replacement);