@indigoai-us/hq-cli 5.201.4 → 5.202.1
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/CHANGELOG.md +14 -0
- package/dist/commands/core-ontology.js +12 -4
- package/dist/commands/integrations-connect.d.ts +38 -0
- package/dist/commands/integrations-connect.js +39 -38
- package/dist/commands/integrations-core.d.ts +4 -6
- package/dist/commands/integrations-core.js +15 -12
- package/dist/commands/integrations-import.js +8 -6
- package/dist/commands/integrations-manage.js +8 -6
- package/dist/commands/integrations.js +9 -5
- package/dist/lib/checkpoint-ontology/apply.d.ts +3 -0
- package/dist/lib/checkpoint-ontology/apply.js +5 -0
- package/dist/lib/checkpoint-ontology/company-brief.d.ts +18 -0
- package/dist/lib/checkpoint-ontology/company-brief.js +337 -0
- package/dist/lib/checkpoint-ontology/plan.d.ts +9 -0
- package/dist/lib/checkpoint-ontology/plan.js +16 -2
- package/dist/lib/doctor/checks/integrations.js +11 -0
- package/dist/utils/redact-error-text.js +2 -1
- package/dist/utils/redact-url.d.ts +14 -0
- package/dist/utils/redact-url.js +218 -0
- package/package.json +1 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/** Marker used when a value claims to be a URL but cannot be parsed safely. */
|
|
2
|
+
export const REDACTED_URL = "[REDACTED]";
|
|
3
|
+
const EXACT_SECRET_PARAMETER_NAMES = new Set([
|
|
4
|
+
"key",
|
|
5
|
+
"apikey",
|
|
6
|
+
"api_key",
|
|
7
|
+
"x-api-key",
|
|
8
|
+
"xmcpkey",
|
|
9
|
+
"token",
|
|
10
|
+
"access_token",
|
|
11
|
+
"refresh_token",
|
|
12
|
+
"secret",
|
|
13
|
+
"client_secret",
|
|
14
|
+
"password",
|
|
15
|
+
"pass",
|
|
16
|
+
"pwd",
|
|
17
|
+
"auth",
|
|
18
|
+
"authorization",
|
|
19
|
+
"sig",
|
|
20
|
+
"signature",
|
|
21
|
+
"session",
|
|
22
|
+
"code",
|
|
23
|
+
"credential",
|
|
24
|
+
"credentials",
|
|
25
|
+
"authcode",
|
|
26
|
+
"authorizationcode",
|
|
27
|
+
"oauthcode",
|
|
28
|
+
"clientcode",
|
|
29
|
+
"verificationcode",
|
|
30
|
+
"confirmationcode",
|
|
31
|
+
"resetcode",
|
|
32
|
+
"activationcode",
|
|
33
|
+
"invitecode",
|
|
34
|
+
"devicecode",
|
|
35
|
+
"pairingcode",
|
|
36
|
+
"onetimecode",
|
|
37
|
+
"otpcode",
|
|
38
|
+
"auth_code",
|
|
39
|
+
"authorization_code",
|
|
40
|
+
"oauth_code",
|
|
41
|
+
"client_code",
|
|
42
|
+
"verification_code",
|
|
43
|
+
"confirmation_code",
|
|
44
|
+
"reset_code",
|
|
45
|
+
"activation_code",
|
|
46
|
+
"invite_code",
|
|
47
|
+
"device_code",
|
|
48
|
+
"pairing_code",
|
|
49
|
+
"one_time_code",
|
|
50
|
+
"otp_code",
|
|
51
|
+
]);
|
|
52
|
+
const UNAMBIGUOUS_SECRET_PARAMETER_SUFFIXES = [
|
|
53
|
+
"key",
|
|
54
|
+
"token",
|
|
55
|
+
"secret",
|
|
56
|
+
"password",
|
|
57
|
+
"signature",
|
|
58
|
+
"credential",
|
|
59
|
+
"credentials",
|
|
60
|
+
];
|
|
61
|
+
const AMBIGUOUS_SECRET_PARAMETER_SUFFIXES = ["pass", "pwd", "sig", "auth", "session"];
|
|
62
|
+
const SECRET_PATH_LABEL = /^(?:access[_-]?token|refresh[_-]?token|id[_-]?token|api[_-]?key|x?mcpkey|client[_-]?secret|token|key|secret|password|pass|pwd|auth|authorization|sig|signature|credential|credentials|session)[=_-].+$/i;
|
|
63
|
+
function hasParameterBoundaryBeforeSuffix(name, suffix) {
|
|
64
|
+
const suffixStart = name.length - suffix.length;
|
|
65
|
+
if (suffixStart <= 0)
|
|
66
|
+
return true;
|
|
67
|
+
return /[-_.]/.test(name[suffixStart - 1]) || /[A-Z]/.test(name[suffixStart]);
|
|
68
|
+
}
|
|
69
|
+
function isSecretParameterName(name) {
|
|
70
|
+
const normalized = name.toLowerCase();
|
|
71
|
+
return (EXACT_SECRET_PARAMETER_NAMES.has(normalized) ||
|
|
72
|
+
UNAMBIGUOUS_SECRET_PARAMETER_SUFFIXES.some((suffix) => normalized.endsWith(suffix)) ||
|
|
73
|
+
AMBIGUOUS_SECRET_PARAMETER_SUFFIXES.some((suffix) => normalized.endsWith(suffix) && hasParameterBoundaryBeforeSuffix(name, suffix)));
|
|
74
|
+
}
|
|
75
|
+
function isOpaqueCapabilitySegment(segment) {
|
|
76
|
+
if (SECRET_PATH_LABEL.test(segment))
|
|
77
|
+
return true;
|
|
78
|
+
const length = segment.length;
|
|
79
|
+
const hasLetter = /[A-Za-z]/.test(segment);
|
|
80
|
+
const hasDigit = /\d/.test(segment);
|
|
81
|
+
const isLongHex = length >= 24 && /^[A-Fa-f0-9]+$/.test(segment);
|
|
82
|
+
const isLongBase64Url = length >= 32 &&
|
|
83
|
+
/^[A-Za-z0-9_-]+$/.test(segment) &&
|
|
84
|
+
hasLetter &&
|
|
85
|
+
(hasDigit || /[A-Z_-]/.test(segment));
|
|
86
|
+
return (length >= 20 && hasLetter && hasDigit) || isLongHex || isLongBase64Url;
|
|
87
|
+
}
|
|
88
|
+
/** Mask opaque credential-like path segments while keeping ordinary routes. */
|
|
89
|
+
function redactPathSegments(pathname) {
|
|
90
|
+
const segments = pathname.split("/");
|
|
91
|
+
const redacted = segments.map((segment) => {
|
|
92
|
+
let decoded;
|
|
93
|
+
try {
|
|
94
|
+
decoded = decodeURIComponent(segment);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (error instanceof URIError)
|
|
98
|
+
return null;
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
return isOpaqueCapabilitySegment(decoded) ? "REDACTED" : segment;
|
|
102
|
+
});
|
|
103
|
+
return redacted.some((segment) => segment === null) ? null : redacted.join("/");
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Redact the values of secret-looking URL parameters while retaining URL
|
|
107
|
+
* structure and safe query values. An invalid URL or malformed encoded
|
|
108
|
+
* parameter name is replaced in full because its secret boundaries are
|
|
109
|
+
* unknowable.
|
|
110
|
+
*/
|
|
111
|
+
export function redactSensitiveUrl(value) {
|
|
112
|
+
let url;
|
|
113
|
+
try {
|
|
114
|
+
url = new URL(value);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (error instanceof TypeError)
|
|
118
|
+
return REDACTED_URL;
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
const hasUserinfo = url.username !== "" || url.password !== "";
|
|
122
|
+
url.username = "";
|
|
123
|
+
url.password = "";
|
|
124
|
+
const pathname = redactPathSegments(url.pathname);
|
|
125
|
+
if (pathname === null)
|
|
126
|
+
return REDACTED_URL;
|
|
127
|
+
url.pathname = pathname;
|
|
128
|
+
const query = redactParameterList(url.search.slice(1));
|
|
129
|
+
if (query === null)
|
|
130
|
+
return REDACTED_URL;
|
|
131
|
+
url.search = query === "" ? "" : `?${query}`;
|
|
132
|
+
const fragment = redactFragment(url.hash.slice(1));
|
|
133
|
+
if (fragment === null)
|
|
134
|
+
return REDACTED_URL;
|
|
135
|
+
url.hash = fragment === "" ? "" : `#${fragment}`;
|
|
136
|
+
const serialized = url.toString();
|
|
137
|
+
if (!hasUserinfo)
|
|
138
|
+
return serialized;
|
|
139
|
+
const authorityStart = serialized.indexOf("://");
|
|
140
|
+
if (authorityStart === -1)
|
|
141
|
+
return serialized;
|
|
142
|
+
const hostStart = authorityStart + 3;
|
|
143
|
+
return `${serialized.slice(0, hostStart)}***@${serialized.slice(hostStart)}`;
|
|
144
|
+
}
|
|
145
|
+
/** Redact secret parameters in an ampersand-separated query or fragment. */
|
|
146
|
+
function redactParameterList(raw) {
|
|
147
|
+
if (raw === "")
|
|
148
|
+
return "";
|
|
149
|
+
const parts = raw.split("&");
|
|
150
|
+
const redacted = [];
|
|
151
|
+
for (const part of parts) {
|
|
152
|
+
const equalsAt = part.indexOf("=");
|
|
153
|
+
const encodedName = equalsAt === -1 ? part : part.slice(0, equalsAt);
|
|
154
|
+
let name;
|
|
155
|
+
try {
|
|
156
|
+
name = decodeURIComponent(encodedName.replace(/\+/g, " "));
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (error instanceof URIError)
|
|
160
|
+
return null;
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
if (isSecretParameterName(name)) {
|
|
164
|
+
redacted.push(`${encodedName}=REDACTED`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
redacted.push(part);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return redacted.join("&");
|
|
171
|
+
}
|
|
172
|
+
/** Redact query-like fields in both `#access_token=...` and `#/route?...`. */
|
|
173
|
+
function redactFragment(fragment) {
|
|
174
|
+
if (fragment === "")
|
|
175
|
+
return "";
|
|
176
|
+
const queryStart = fragment.indexOf("?");
|
|
177
|
+
if (queryStart !== -1) {
|
|
178
|
+
const query = redactParameterList(fragment.slice(queryStart + 1));
|
|
179
|
+
return query === null ? null : `${fragment.slice(0, queryStart + 1)}${query}`;
|
|
180
|
+
}
|
|
181
|
+
if (fragment.includes("="))
|
|
182
|
+
return redactParameterList(fragment);
|
|
183
|
+
return fragment;
|
|
184
|
+
}
|
|
185
|
+
const URL_IN_TEXT = /\b[a-z][a-z\d+.-]*:\/\/[^\s<>"'`]+/gi;
|
|
186
|
+
const TRAILING_SENTENCE_PUNCTUATION = /[),.;!?]+$/;
|
|
187
|
+
/** Redact URLs embedded in an error or human-readable sentence. */
|
|
188
|
+
export function redactUrlsInText(text) {
|
|
189
|
+
return text.replace(URL_IN_TEXT, (candidate) => {
|
|
190
|
+
const punctuation = TRAILING_SENTENCE_PUNCTUATION.exec(candidate)?.[0] ?? "";
|
|
191
|
+
const url = punctuation ? candidate.slice(0, -punctuation.length) : candidate;
|
|
192
|
+
return `${redactSensitiveUrl(url)}${punctuation}`;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
const URL_PROPERTY = /(?:^|[-_.])(?:url|uri|endpoint)$/i;
|
|
196
|
+
const CAMEL_URL_PROPERTY = /(?:Url|Uri|Endpoint)$/;
|
|
197
|
+
const ABSOLUTE_URL = /^[a-z][a-z\d+.-]*:\/\//i;
|
|
198
|
+
function isUrlProperty(key) {
|
|
199
|
+
return URL_PROPERTY.test(key) || CAMEL_URL_PROPERTY.test(key);
|
|
200
|
+
}
|
|
201
|
+
/** Clone a JSON-like value with all URL-valued fields and embedded URLs safe. */
|
|
202
|
+
export function redactSensitiveUrls(value) {
|
|
203
|
+
if (typeof value === "string")
|
|
204
|
+
return redactUrlsInText(value);
|
|
205
|
+
if (Array.isArray(value))
|
|
206
|
+
return value.map((item) => redactSensitiveUrls(item));
|
|
207
|
+
if (!value || typeof value !== "object")
|
|
208
|
+
return value;
|
|
209
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
210
|
+
key,
|
|
211
|
+
typeof item === "string" && isUrlProperty(key)
|
|
212
|
+
? ABSOLUTE_URL.test(item)
|
|
213
|
+
? redactSensitiveUrl(item)
|
|
214
|
+
: redactUrlsInText(item)
|
|
215
|
+
: redactSensitiveUrls(item),
|
|
216
|
+
]));
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=redact-url.js.map
|