-
Notifications
You must be signed in to change notification settings - Fork 70
Expand file tree
/
Copy pathutils.ts
More file actions
108 lines (97 loc) · 2.65 KB
/
Copy pathutils.ts
File metadata and controls
108 lines (97 loc) · 2.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { getPublicErrorMessage } from '@/core/shared/errors'
type ActionErrorOptions = {
cause?: unknown
expected?: boolean
}
export class ActionError extends Error {
public expected: boolean
public override cause?: unknown
constructor(message: string, options: ActionErrorOptions = {}) {
super(message)
this.name = 'ActionError'
this.expected = options.expected ?? true
this.cause = options.cause
}
}
export const returnServerError = (
message: string,
options?: ActionErrorOptions
) => {
throw new ActionError(message, options)
}
export function handleDefaultInfraError(
status: number,
cause?: unknown
): never {
return returnServerError(getPublicErrorMessage({ status }), {
cause,
expected: status < 500,
})
}
export const flattenClientInputValue = (
clientInput: unknown,
key: string
): string | undefined => {
if (typeof clientInput === 'object' && clientInput && key in clientInput) {
return clientInput[key as keyof typeof clientInput]
}
return undefined
}
const SAFE_INPUT_KEYS = new Set<string>([
'teamSlug',
'teamId',
'templateId',
'sandboxId',
'userId',
'webhookId',
'organizationId',
'page',
'pageSize',
'limit',
'offset',
'sortBy',
'sortOrder',
'mode',
'kind',
'type',
])
function describeValue(value: unknown): string {
if (value === null) return 'null'
if (value === undefined) return 'undefined'
if (Array.isArray(value)) return `array(${value.length})`
const t = typeof value
if (t === 'string') return `string(${(value as string).length})`
if (t === 'object') return 'object'
return t
}
/**
* Sanitize action `clientInput` for safe logging (e.g. telemetry summaries).
*
* - Allowlisted scalar keys are inlined as-is.
* - Everything else is replaced with `_<key>: <type-hint>` so shape and
* length are visible without leaking values.
*
* Allowlist-based sanitization is the inverse of the old blocklist-via-pino-
* redaction approach: new sensitive fields are safe by default and only become
* loggable when explicitly added to {@link SAFE_INPUT_KEYS}.
*/
export function sanitizeClientInput(input: unknown): Record<string, unknown> {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
return { _shape: describeValue(input) }
}
const out: Record<string, unknown> = {}
for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
const valueType = typeof value
if (
SAFE_INPUT_KEYS.has(key) &&
(valueType === 'string' ||
valueType === 'number' ||
valueType === 'boolean')
) {
out[key] = value
} else {
out[`_${key}`] = describeValue(value)
}
}
return out
}