veryfront 0.1.636 → 0.1.638
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/esm/deno.js +1 -1
- package/esm/src/errors/logging.d.ts.map +1 -1
- package/esm/src/errors/logging.js +7 -3
- package/esm/src/oauth/index.d.ts +1 -0
- package/esm/src/oauth/index.d.ts.map +1 -1
- package/esm/src/oauth/token-store/index.d.ts +1 -0
- package/esm/src/oauth/token-store/index.d.ts.map +1 -1
- package/esm/src/oauth/token-store/memory.d.ts +26 -4
- package/esm/src/oauth/token-store/memory.d.ts.map +1 -1
- package/esm/src/oauth/token-store/memory.js +42 -5
- package/esm/src/observability/log-buffer.d.ts.map +1 -1
- package/esm/src/observability/log-buffer.js +7 -1
- package/esm/src/platform/adapters/redis/modules.d.ts.map +1 -1
- package/esm/src/platform/adapters/redis/modules.js +3 -10
- package/esm/src/server/handlers/request/project-run-execute.handler.d.ts +5 -3
- package/esm/src/server/handlers/request/project-run-execute.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/project-run-execute.handler.js +1 -0
- package/esm/src/utils/logger/logger.d.ts.map +1 -1
- package/esm/src/utils/logger/logger.js +15 -5
- package/esm/src/utils/logger/redact.d.ts +64 -0
- package/esm/src/utils/logger/redact.d.ts.map +1 -0
- package/esm/src/utils/logger/redact.js +235 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/esm/src/workflow/executor/workflow-executor.d.ts +2 -0
- package/esm/src/workflow/executor/workflow-executor.d.ts.map +1 -1
- package/esm/src/workflow/executor/workflow-executor.js +4 -3
- package/package.json +2 -1
package/esm/deno.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../src/src/errors/logging.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../src/src/errors/logging.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAoBD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAoCN;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAMN"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { isProduction } from "../platform/environment.js";
|
|
8
8
|
import { serverLogger } from "../utils/logger/logger.js";
|
|
9
|
+
import { redactSensitive } from "../utils/logger/redact.js";
|
|
9
10
|
function toContextRecord(value) {
|
|
10
11
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
11
12
|
? value
|
|
@@ -30,6 +31,9 @@ function mergeContext(errorContext, extraContext) {
|
|
|
30
31
|
*/
|
|
31
32
|
export function logError(error, context) {
|
|
32
33
|
const mergedContext = mergeContext(error.context, context);
|
|
34
|
+
// Redact once and reuse for both the production JSON entry and the dev-mode
|
|
35
|
+
// human-readable dump, so neither path can emit unredacted credentials.
|
|
36
|
+
const safeContext = redactSensitive(mergedContext);
|
|
33
37
|
const entry = {
|
|
34
38
|
level: "error",
|
|
35
39
|
slug: error.slug,
|
|
@@ -40,7 +44,7 @@ export function logError(error, context) {
|
|
|
40
44
|
status: error.status,
|
|
41
45
|
docs: error.getDocsUrl(),
|
|
42
46
|
timestamp: new Date().toISOString(),
|
|
43
|
-
context:
|
|
47
|
+
context: safeContext,
|
|
44
48
|
};
|
|
45
49
|
if (isProduction()) {
|
|
46
50
|
// Direct JSON output — this module owns its own structured format
|
|
@@ -57,8 +61,8 @@ export function logError(error, context) {
|
|
|
57
61
|
serverLogger.error(` 💡 Suggestion: ${error.suggestion}`);
|
|
58
62
|
}
|
|
59
63
|
serverLogger.error(` 📚 Docs: ${entry.docs}`);
|
|
60
|
-
if (
|
|
61
|
-
serverLogger.error(` Context: ${JSON.stringify(
|
|
64
|
+
if (safeContext) {
|
|
65
|
+
serverLogger.error(` Context: ${JSON.stringify(safeContext, null, 2)}`);
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
}
|
package/esm/src/oauth/index.d.ts
CHANGED
|
@@ -24,5 +24,6 @@ export type { AuthorizationUrlOptions, OAuthProviderConfig, OAuthServiceConfig,
|
|
|
24
24
|
export { OAuthProvider, OAuthService } from "./providers/base.js";
|
|
25
25
|
export { airtableConfig, asanaConfig, bitbucketConfig, boxConfig, calendarConfig, clickupConfig, confluenceConfig, driveConfig, figmaConfig, freshdeskConfig, githubConfig, gitlabConfig, gmailConfig, hubspotConfig, intercomConfig, jiraConfig, linearConfig, mailchimpConfig, mondayConfig, notionConfig, oneDriveConfig, outlookConfig, pipedriveConfig, quickbooksConfig, salesforceConfig, sharePointConfig, sheetsConfig, shopifyConfig, slackConfig, teamsConfig, trelloConfig, twitterConfig, webexConfig, xeroConfig, zoomConfig, } from "./providers/index.js";
|
|
26
26
|
export { MemoryTokenStore } from "./token-store/index.js";
|
|
27
|
+
export type { MemoryTokenStoreOptions } from "./token-store/index.js";
|
|
27
28
|
export { createOAuthCallbackHandler, createOAuthDisconnectHandler, createOAuthInitHandler, createOAuthStatusHandler, type OAuthCallbackHandlerOptions, type OAuthInitHandlerOptions, } from "./handlers/index.js";
|
|
28
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/oauth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,yBAAyB,CAAC;AAGjC,YAAY,EACV,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,EACL,cAAc,EACd,WAAW,EACX,eAAe,EACf,SAAS,EACT,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,aAAa,EACb,cAAc,EACd,UAAU,EACV,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/oauth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,yBAAyB,CAAC;AAGjC,YAAY,EACV,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,EACL,cAAc,EACd,WAAW,EACX,eAAe,EACf,SAAS,EACT,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,aAAa,EACb,cAAc,EACd,UAAU,EACV,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,EACL,0BAA0B,EAC1B,4BAA4B,EAC5B,sBAAsB,EACtB,wBAAwB,EACxB,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC"}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
* @module oauth/token-store
|
|
5
5
|
*/
|
|
6
6
|
export { MemoryTokenStore, memoryTokenStore } from "./memory.js";
|
|
7
|
+
export type { MemoryTokenStoreOptions } from "./memory.js";
|
|
7
8
|
export type { OAuthState, OAuthTokens, StoredOAuthState, TokenStore } from "../types.js";
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -1,17 +1,39 @@
|
|
|
1
1
|
import type { OAuthTokens, StoredOAuthState, TokenStore } from "../types.js";
|
|
2
|
+
/** Options for {@link MemoryTokenStore}. */
|
|
3
|
+
export interface MemoryTokenStoreOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Maximum number of `(serviceId, userId)` token slots to retain before
|
|
6
|
+
* least-recently-used eviction kicks in. Defaults to
|
|
7
|
+
* {@link DEFAULT_MAX_TOKEN_ENTRIES}.
|
|
8
|
+
*/
|
|
9
|
+
maxEntries?: number;
|
|
10
|
+
}
|
|
2
11
|
/**
|
|
3
12
|
* In-memory TokenStore keyed by `(serviceId, userId)`.
|
|
4
13
|
*
|
|
5
|
-
* Suitable for development and tests.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
14
|
+
* Suitable for development and tests ONLY. It is process-local and not
|
|
15
|
+
* durable: tokens are lost on restart and not shared across instances or
|
|
16
|
+
* workers, and the exported {@link memoryTokenStore} singleton shares one
|
|
17
|
+
* keyspace process-wide. For production inject a persistent, scoped store
|
|
18
|
+
* (Redis, Postgres, ...) keyed the same way.
|
|
19
|
+
*
|
|
20
|
+
* The token map is bounded (see {@link MemoryTokenStoreOptions.maxEntries}) so
|
|
21
|
+
* it cannot grow without limit. Never share a single slot per service across
|
|
22
|
+
* users — see VULN-AUTH-2.
|
|
8
23
|
*/
|
|
9
24
|
export declare class MemoryTokenStore implements TokenStore {
|
|
10
25
|
private tokens;
|
|
11
26
|
private states;
|
|
12
27
|
private projectId;
|
|
13
|
-
|
|
28
|
+
private warnedProductionUse;
|
|
29
|
+
constructor(projectId?: string, options?: MemoryTokenStoreOptions);
|
|
14
30
|
private scopedKey;
|
|
31
|
+
/**
|
|
32
|
+
* Warn once if this non-durable store is used to persist tokens in
|
|
33
|
+
* production — almost always a misconfiguration (a persistent TokenStore
|
|
34
|
+
* should have been injected).
|
|
35
|
+
*/
|
|
36
|
+
private warnIfProductionUse;
|
|
15
37
|
getTokens(serviceId: string, userId: string): Promise<OAuthTokens | null>;
|
|
16
38
|
setTokens(serviceId: string, userId: string, tokens: OAuthTokens): Promise<void>;
|
|
17
39
|
clearTokens(serviceId: string, userId: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/memory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/memory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAgB7E,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,mBAAmB,CAAS;gBAExB,SAAS,SAAY,EAAE,OAAO,GAAE,uBAA4B;IAOxE,OAAO,CAAC,SAAS;IAIjB;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAW3B,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAMzE,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhF,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9D;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAU7D,OAAO,CAAC,oBAAoB;IAS5B,iFAAiF;IACjF,oBAAoB,IAAI,MAAM,EAAE;IAOhC,4DAA4D;IAC5D,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAQvD,QAAQ,IAAI,IAAI;CAIjB;AAED,eAAO,MAAM,gBAAgB,EAAE,UAAmC,CAAC"}
|
|
@@ -1,26 +1,63 @@
|
|
|
1
|
+
import { logger as baseLogger } from "../../utils/index.js";
|
|
2
|
+
import { isProduction } from "../../platform/environment.js";
|
|
3
|
+
import { LRUCacheAdapter } from "../../utils/cache/stores/memory/lru-cache-adapter.js";
|
|
4
|
+
const logger = baseLogger.component("o-auth");
|
|
1
5
|
/** State expiry window: reject any state older than this (10 minutes). */
|
|
2
6
|
const STATE_EXPIRY_MS = 10 * 60 * 1_000;
|
|
7
|
+
/**
|
|
8
|
+
* Default cap on stored token slots. Bounds memory in long-lived processes;
|
|
9
|
+
* past this, the least-recently-used `(serviceId, userId)` slot is evicted
|
|
10
|
+
* (the affected user simply re-authenticates). Tokens are NOT given a TTL —
|
|
11
|
+
* an expired access token may still be refreshable via its refresh token, so
|
|
12
|
+
* eviction is by capacity/recency only.
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_MAX_TOKEN_ENTRIES = 10_000;
|
|
3
15
|
/**
|
|
4
16
|
* In-memory TokenStore keyed by `(serviceId, userId)`.
|
|
5
17
|
*
|
|
6
|
-
* Suitable for development and tests.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
18
|
+
* Suitable for development and tests ONLY. It is process-local and not
|
|
19
|
+
* durable: tokens are lost on restart and not shared across instances or
|
|
20
|
+
* workers, and the exported {@link memoryTokenStore} singleton shares one
|
|
21
|
+
* keyspace process-wide. For production inject a persistent, scoped store
|
|
22
|
+
* (Redis, Postgres, ...) keyed the same way.
|
|
23
|
+
*
|
|
24
|
+
* The token map is bounded (see {@link MemoryTokenStoreOptions.maxEntries}) so
|
|
25
|
+
* it cannot grow without limit. Never share a single slot per service across
|
|
26
|
+
* users — see VULN-AUTH-2.
|
|
9
27
|
*/
|
|
10
28
|
export class MemoryTokenStore {
|
|
11
|
-
tokens
|
|
29
|
+
tokens;
|
|
12
30
|
states = new Map();
|
|
13
31
|
projectId;
|
|
14
|
-
|
|
32
|
+
warnedProductionUse = false;
|
|
33
|
+
constructor(projectId = "default", options = {}) {
|
|
15
34
|
this.projectId = projectId;
|
|
35
|
+
this.tokens = new LRUCacheAdapter({
|
|
36
|
+
maxEntries: options.maxEntries ?? DEFAULT_MAX_TOKEN_ENTRIES,
|
|
37
|
+
});
|
|
16
38
|
}
|
|
17
39
|
scopedKey(serviceId, userId) {
|
|
18
40
|
return `${this.projectId}:${serviceId}:${userId}`;
|
|
19
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Warn once if this non-durable store is used to persist tokens in
|
|
44
|
+
* production — almost always a misconfiguration (a persistent TokenStore
|
|
45
|
+
* should have been injected).
|
|
46
|
+
*/
|
|
47
|
+
warnIfProductionUse() {
|
|
48
|
+
if (this.warnedProductionUse || !isProduction())
|
|
49
|
+
return;
|
|
50
|
+
this.warnedProductionUse = true;
|
|
51
|
+
logger.warn("MemoryTokenStore is persisting OAuth tokens in production. It is " +
|
|
52
|
+
"process-local and not durable (tokens are lost on restart and not " +
|
|
53
|
+
"shared across instances). Inject a persistent, scoped TokenStore " +
|
|
54
|
+
"(Redis/Postgres/...) instead.");
|
|
55
|
+
}
|
|
20
56
|
getTokens(serviceId, userId) {
|
|
21
57
|
return Promise.resolve(this.tokens.get(this.scopedKey(serviceId, userId)) ?? null);
|
|
22
58
|
}
|
|
23
59
|
setTokens(serviceId, userId, tokens) {
|
|
60
|
+
this.warnIfProductionUse();
|
|
24
61
|
this.tokens.set(this.scopedKey(serviceId, userId), tokens);
|
|
25
62
|
return Promise.resolve();
|
|
26
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-buffer.d.ts","sourceRoot":"","sources":["../../../src/src/observability/log-buffer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"log-buffer.d.ts","sourceRoot":"","sources":["../../../src/src/observability/log-buffer.ts"],"names":[],"mappings":"AAEA,yCAAyC;AACzC,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,2BAA2B;AAC3B,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,uDAAuD;AACvD,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,8CAA8C;AAC9C,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;AAEtD,4BAA4B;AAC5B,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IAI9C,OAAO,CAAC,UAAU;IAIlB,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,QAAQ;IA2B3D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAInF,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAIlF,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAIlF,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAInF,KAAK,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,EAAE;IAqCrC,IAAI,CAAC,KAAK,SAAK,GAAG,QAAQ,EAAE;IAI5B,MAAM,IAAI,QAAQ,EAAE;IAIpB,KAAK,IAAI,IAAI;IAIb,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,YAAY,IAAI,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC;IAUxC,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI;IAK9C,MAAM,IAAI,QAAQ,EAAE;IAIpB,MAAM,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM;CAYrC;AAID,yBAAyB;AACzB,wBAAgB,YAAY,IAAI,SAAS,CAGxC;AAED,sCAAsC;AACtC,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAED,gDAAgD;AAChD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,SAAY,GAAG,MAAM,IAAI,CA6ClF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { redactSensitive } from "../utils/logger/redact.js";
|
|
1
2
|
/** Implement log buffer. */
|
|
2
3
|
export class LogBuffer {
|
|
3
4
|
entries = [];
|
|
@@ -13,6 +14,9 @@ export class LogBuffer {
|
|
|
13
14
|
append(entry) {
|
|
14
15
|
const fullEntry = {
|
|
15
16
|
...entry,
|
|
17
|
+
// Redact credential-like keys before the entry is buffered, surfaced to
|
|
18
|
+
// subscribers, or written to disk by the file subscriber (#1989).
|
|
19
|
+
data: entry.data ? redactSensitive(entry.data) : entry.data,
|
|
16
20
|
id: this.generateId(),
|
|
17
21
|
timestamp: Date.now(),
|
|
18
22
|
};
|
|
@@ -136,7 +140,9 @@ export function interceptConsole(buffer, source = "console") {
|
|
|
136
140
|
if (typeof a === "string")
|
|
137
141
|
return a;
|
|
138
142
|
try {
|
|
139
|
-
|
|
143
|
+
// Redact object args before they are folded into the message string,
|
|
144
|
+
// where the per-entry data redaction can no longer reach them (#1989).
|
|
145
|
+
return JSON.stringify(redactSensitive(a));
|
|
140
146
|
}
|
|
141
147
|
catch (_) {
|
|
142
148
|
/* expected: circular references or non-serializable values */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../../../../src/src/platform/adapters/redis/modules.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKnE,wBAAgB,cAAc,IAAI,OAAO,CAAC;IACxC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;CACnC,CAAC,
|
|
1
|
+
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../../../../src/src/platform/adapters/redis/modules.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKnE,wBAAgB,cAAc,IAAI,OAAO,CAAC;IACxC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;CACnC,CAAC,CA6BD;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
|
|
@@ -10,9 +10,7 @@ export function getRedisModule() {
|
|
|
10
10
|
return withSpan("platform.redis.getModule", async () => {
|
|
11
11
|
try {
|
|
12
12
|
if (isDeno) {
|
|
13
|
-
|
|
14
|
-
// @ts-ignore - Deno global
|
|
15
|
-
DenoRedis = await import(denoRedisUrl);
|
|
13
|
+
NodeRedis = (await import("redis"));
|
|
16
14
|
}
|
|
17
15
|
else {
|
|
18
16
|
NodeRedis = (await import("redis"));
|
|
@@ -20,14 +18,9 @@ export function getRedisModule() {
|
|
|
20
18
|
}
|
|
21
19
|
catch (error) {
|
|
22
20
|
const message = error instanceof Error ? error.message : String(error);
|
|
23
|
-
|
|
24
|
-
throw INITIALIZATION_ERROR.create({
|
|
25
|
-
detail: `Failed to load Deno Redis module. Error: ${message}`,
|
|
26
|
-
cause: error instanceof Error ? error : undefined,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
21
|
+
const packageName = isDeno ? "npm:redis@5.11.0" : "redis";
|
|
29
22
|
throw INITIALIZATION_ERROR.create({
|
|
30
|
-
detail: `Failed to load '
|
|
23
|
+
detail: `Failed to load '${packageName}' package. Please install it with: npm install redis\nError: ${message}`,
|
|
31
24
|
cause: error instanceof Error ? error : undefined,
|
|
32
25
|
});
|
|
33
26
|
}
|
|
@@ -28,14 +28,16 @@ interface WorkflowRunView {
|
|
|
28
28
|
message?: string;
|
|
29
29
|
} | null;
|
|
30
30
|
}
|
|
31
|
+
interface WorkflowStartHandle {
|
|
32
|
+
runId: string;
|
|
33
|
+
settled?(): Promise<void>;
|
|
34
|
+
}
|
|
31
35
|
interface WorkflowClientView {
|
|
32
36
|
readonly statePersistence?: "durable" | "ephemeral";
|
|
33
37
|
register(workflow: unknown): void;
|
|
34
38
|
start(workflowId: string, input: unknown, options?: {
|
|
35
39
|
runId?: string;
|
|
36
|
-
}): Promise<
|
|
37
|
-
runId: string;
|
|
38
|
-
}>;
|
|
40
|
+
}): Promise<WorkflowStartHandle>;
|
|
39
41
|
getRun(runId: string): Promise<WorkflowRunView | null>;
|
|
40
42
|
destroy(): Promise<void>;
|
|
41
43
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-run-execute.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/project-run-execute.handler.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,KAAK,cAAc,EAAgB,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EAAW,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE3F,OAAO,EAAE,KAAK,kBAAkB,EAAoB,MAAM,sCAAsC,CAAC;AAEjG,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASlD,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;CACvB;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACrC;AAED,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;IACpD,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,KAAK,CACH,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3B,OAAO,CAAC
|
|
1
|
+
{"version":3,"file":"project-run-execute.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/project-run-execute.handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -160,6 +160,7 @@ async function executeWorkflowRun(request, ctx, deps) {
|
|
|
160
160
|
client.register(workflow.definition);
|
|
161
161
|
const handle = await client.start(workflow.id, request.input ?? {}, { runId: request.runId });
|
|
162
162
|
const run = await waitForWorkflowResult(client, handle.runId, deps);
|
|
163
|
+
await handle.settled?.();
|
|
163
164
|
const durationMs = Math.max(0, deps.now() - startedAt);
|
|
164
165
|
if (run.status === "waiting") {
|
|
165
166
|
if (client.statePersistence !== "durable") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/logger/logger.ts"],"names":[],"mappings":"AAEA,OAAO,EAOL,KAAK,YAAY,EAEjB,KAAK,eAAe,EAErB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/logger/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getEnv, isStdoutTTY } from "../../platform/compat/process.js";
|
|
2
2
|
import { RUNTIME_VERSION } from "../version.js";
|
|
3
3
|
import { ANSI, colorize, formatContextText, formatTimestamp, LEVEL_COLORS, LEVEL_GLYPHS, padTag, serializeError, } from "./core.js";
|
|
4
|
+
import { redactSensitive, sanitizeSerializedError, sanitizeUrlCredentials } from "./redact.js";
|
|
4
5
|
export var LogLevel;
|
|
5
6
|
(function (LogLevel) {
|
|
6
7
|
LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
|
|
@@ -181,8 +182,11 @@ class ConsoleLogger {
|
|
|
181
182
|
extractToEntryField(entry, mergedContext, "trace_id", (v) => String(v));
|
|
182
183
|
extractToEntryField(entry, mergedContext, "span_id", (v) => String(v));
|
|
183
184
|
extractToEntryField(entry, mergedContext, "project_slug", (v) => String(v));
|
|
184
|
-
|
|
185
|
-
|
|
185
|
+
// request_url / domain are URL-shaped and lifted out of mergedContext
|
|
186
|
+
// *before* redactSensitive runs, so they bypass the key-based redactor.
|
|
187
|
+
// Scrub embedded credentials (userinfo, ?access_token=, …) here (#1989).
|
|
188
|
+
extractToEntryField(entry, mergedContext, "request_url", (v) => sanitizeUrlCredentials(String(v)));
|
|
189
|
+
extractToEntryField(entry, mergedContext, "domain", (v) => sanitizeUrlCredentials(String(v)));
|
|
186
190
|
extractToEntryField(entry, mergedContext, "project_id", (v) => String(v));
|
|
187
191
|
extractToEntryField(entry, mergedContext, "release_id", (v) => String(v));
|
|
188
192
|
extractToEntryField(entry, mergedContext, "branch_id", (v) => String(v));
|
|
@@ -215,10 +219,16 @@ class ConsoleLogger {
|
|
|
215
219
|
if (entry.conversationId && !entry.conversation_id) {
|
|
216
220
|
entry.conversation_id = entry.conversationId;
|
|
217
221
|
}
|
|
222
|
+
// Redact credential-like keys from the free-form context bag before
|
|
223
|
+
// serialization (the deliberate top-level fields above are already
|
|
224
|
+
// extracted out of mergedContext, so they are unaffected).
|
|
218
225
|
if (Object.keys(mergedContext).length > 0)
|
|
219
|
-
entry.context = mergedContext;
|
|
226
|
+
entry.context = redactSensitive(mergedContext);
|
|
227
|
+
// The serialized error (name/message/stack) bypasses the key-based
|
|
228
|
+
// redactor; scrub credentials embedded in its message/stack (DSNs, Mongo
|
|
229
|
+
// URIs, ?access_token= URLs, userinfo) before emission (#1989).
|
|
220
230
|
if (error)
|
|
221
|
-
entry.error = error;
|
|
231
|
+
entry.error = sanitizeSerializedError(error);
|
|
222
232
|
return JSON.stringify(entry);
|
|
223
233
|
}
|
|
224
234
|
formatTextLine(level, message, args) {
|
|
@@ -231,7 +241,7 @@ class ConsoleLogger {
|
|
|
231
241
|
const componentTag = this.componentName
|
|
232
242
|
? ` ${colorize(`[${this.componentName}]`, ANSI.dim, enableColor)}`
|
|
233
243
|
: "";
|
|
234
|
-
const contextText = formatContextText(mergedContext, error, enableColor);
|
|
244
|
+
const contextText = formatContextText(redactSensitive(mergedContext), sanitizeSerializedError(error), enableColor);
|
|
235
245
|
return `${timestamp} ${tag} ${glyph}${componentTag} ${message}${contextText}`;
|
|
236
246
|
}
|
|
237
247
|
log(level, logLevel, consoleFn, message, args) {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret / credential redaction for structured log context.
|
|
3
|
+
*
|
|
4
|
+
* Defense-in-depth (#1989): the logger, the error-logging path, and the
|
|
5
|
+
* observability log buffer all accept arbitrary `context`/`data` objects from
|
|
6
|
+
* callers and serialize them to log sinks. There is no guarantee a caller
|
|
7
|
+
* never hands us a tokens object, an `Authorization` header bag, or a request
|
|
8
|
+
* body with a password field. This pass masks values whose *key* looks like a
|
|
9
|
+
* credential before serialization, so an accidental
|
|
10
|
+
* `logger.info("...", { authorization: token })` cannot leak the secret.
|
|
11
|
+
*
|
|
12
|
+
* Scope is intentionally key-based: we do not attempt to find secrets embedded
|
|
13
|
+
* in free-form message strings (too lossy). The deny-list errs toward
|
|
14
|
+
* over-redaction — masking a benign `tokenCount` is acceptable; leaking a real
|
|
15
|
+
* token is not. The traversal fails *closed*: on a cycle, depth overflow, or a
|
|
16
|
+
* throwing getter it returns {@link REDACTED} rather than risk emitting an
|
|
17
|
+
* unredacted object.
|
|
18
|
+
*/
|
|
19
|
+
/** Replacement value substituted for any sensitive field. */
|
|
20
|
+
export declare const REDACTED = "[REDACTED]";
|
|
21
|
+
/**
|
|
22
|
+
* Whether a context key names a credential and should have its value masked.
|
|
23
|
+
*
|
|
24
|
+
* Uses substring matching on a normalized key, so `clientSecret`,
|
|
25
|
+
* `x-api-key`, and `refresh_token` all match while benign words that merely
|
|
26
|
+
* *contain* a pattern as a separate token (e.g. `author`) do not — `author`
|
|
27
|
+
* normalizes to `author`, which contains none of the patterns.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isSensitiveKey(key: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Returns a redacted deep copy of `context`. Any property whose key is
|
|
32
|
+
* {@link isSensitiveKey} has its value replaced with {@link REDACTED}; nested
|
|
33
|
+
* plain objects, class instances, and arrays are traversed. The input is never
|
|
34
|
+
* mutated, and the pass fails closed (returns {@link REDACTED}) on cycles,
|
|
35
|
+
* depth overflow, or a throwing getter.
|
|
36
|
+
*/
|
|
37
|
+
export declare function redactSensitive<T>(context: T): T;
|
|
38
|
+
/**
|
|
39
|
+
* Strip credentials from URL-shaped strings so they can be safely emitted in
|
|
40
|
+
* free-form text (error messages, stacks, lifted `request_url` fields). Unlike
|
|
41
|
+
* {@link redactSensitive}, which is key-based, this scrubs secrets embedded in
|
|
42
|
+
* the *value* itself:
|
|
43
|
+
*
|
|
44
|
+
* - URL userinfo: `http://user:pass@host` → `http://user:[REDACTED]@host`
|
|
45
|
+
* - sensitive query params: `?access_token=abc` → `?access_token=[REDACTED]`
|
|
46
|
+
*
|
|
47
|
+
* It is intentionally tolerant: it operates on any string (a DSN, a Mongo URI,
|
|
48
|
+
* an axios error message containing a URL) via regex rather than requiring a
|
|
49
|
+
* parseable URL, so malformed or partial URLs in error text are still scrubbed.
|
|
50
|
+
* Non-URL strings pass through unchanged.
|
|
51
|
+
*/
|
|
52
|
+
export declare function sanitizeUrlCredentials(input: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Apply {@link sanitizeUrlCredentials} to the `message` and `stack` of a
|
|
55
|
+
* serialized-error-shaped object, returning a new object. Used by the logger's
|
|
56
|
+
* JSON and text paths so errors carrying DSNs, Mongo URIs, or
|
|
57
|
+
* `?access_token=`-bearing URLs do not leak credentials (the serialized error
|
|
58
|
+
* bypasses the key-based redactor). Returns the input unchanged when falsy.
|
|
59
|
+
*/
|
|
60
|
+
export declare function sanitizeSerializedError<T extends {
|
|
61
|
+
message?: unknown;
|
|
62
|
+
stack?: unknown;
|
|
63
|
+
} | undefined>(error: T): T;
|
|
64
|
+
//# sourceMappingURL=redact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/logger/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,6DAA6D;AAC7D,eAAO,MAAM,QAAQ,eAAe,CAAC;AA2CrC;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGnD;AA6ED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAEhD;AA2BD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA4B5D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,CAAC,SAAS;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,EAC5D,KAAK,EAAE,CAAC,GAAG,CAAC,CAMb"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret / credential redaction for structured log context.
|
|
3
|
+
*
|
|
4
|
+
* Defense-in-depth (#1989): the logger, the error-logging path, and the
|
|
5
|
+
* observability log buffer all accept arbitrary `context`/`data` objects from
|
|
6
|
+
* callers and serialize them to log sinks. There is no guarantee a caller
|
|
7
|
+
* never hands us a tokens object, an `Authorization` header bag, or a request
|
|
8
|
+
* body with a password field. This pass masks values whose *key* looks like a
|
|
9
|
+
* credential before serialization, so an accidental
|
|
10
|
+
* `logger.info("...", { authorization: token })` cannot leak the secret.
|
|
11
|
+
*
|
|
12
|
+
* Scope is intentionally key-based: we do not attempt to find secrets embedded
|
|
13
|
+
* in free-form message strings (too lossy). The deny-list errs toward
|
|
14
|
+
* over-redaction — masking a benign `tokenCount` is acceptable; leaking a real
|
|
15
|
+
* token is not. The traversal fails *closed*: on a cycle, depth overflow, or a
|
|
16
|
+
* throwing getter it returns {@link REDACTED} rather than risk emitting an
|
|
17
|
+
* unredacted object.
|
|
18
|
+
*/
|
|
19
|
+
import { isRecord } from "./core.js";
|
|
20
|
+
/** Replacement value substituted for any sensitive field. */
|
|
21
|
+
export const REDACTED = "[REDACTED]";
|
|
22
|
+
/**
|
|
23
|
+
* Normalized substrings that mark a key as sensitive. Matching is done against
|
|
24
|
+
* a lowercased, non-alphanumeric-stripped form of the key, so `API-Key`,
|
|
25
|
+
* `api_key`, and `apiKey` all collapse to `apikey` and match.
|
|
26
|
+
*
|
|
27
|
+
* Deliberately omitted to avoid false positives that swamp real logs:
|
|
28
|
+
* - bare `"auth"` (would mask `author`); `authorization`/`authToken` are still
|
|
29
|
+
* covered via `authorization`/`token`.
|
|
30
|
+
* - short tokens like `"dsn"`/`"sas"` (would mask `feedsNamespace`, etc.).
|
|
31
|
+
*/
|
|
32
|
+
const SENSITIVE_KEY_PATTERNS = [
|
|
33
|
+
"password",
|
|
34
|
+
"passwd",
|
|
35
|
+
"pwd",
|
|
36
|
+
"passphrase",
|
|
37
|
+
"secret",
|
|
38
|
+
"clientsecret",
|
|
39
|
+
"token",
|
|
40
|
+
"apikey",
|
|
41
|
+
"accesskey",
|
|
42
|
+
"privatekey",
|
|
43
|
+
"credential",
|
|
44
|
+
"authorization",
|
|
45
|
+
"cookie",
|
|
46
|
+
"bearer",
|
|
47
|
+
"jwt",
|
|
48
|
+
"connectionstring",
|
|
49
|
+
"signature",
|
|
50
|
+
"sessionid",
|
|
51
|
+
"sid",
|
|
52
|
+
"otp",
|
|
53
|
+
"mfa",
|
|
54
|
+
"pin",
|
|
55
|
+
"salt",
|
|
56
|
+
"xsrf",
|
|
57
|
+
"csrf",
|
|
58
|
+
];
|
|
59
|
+
/** Stop traversing past this depth to keep the pass cheap and stack-safe. */
|
|
60
|
+
const MAX_DEPTH = 16;
|
|
61
|
+
/**
|
|
62
|
+
* Whether a context key names a credential and should have its value masked.
|
|
63
|
+
*
|
|
64
|
+
* Uses substring matching on a normalized key, so `clientSecret`,
|
|
65
|
+
* `x-api-key`, and `refresh_token` all match while benign words that merely
|
|
66
|
+
* *contain* a pattern as a separate token (e.g. `author`) do not — `author`
|
|
67
|
+
* normalizes to `author`, which contains none of the patterns.
|
|
68
|
+
*/
|
|
69
|
+
export function isSensitiveKey(key) {
|
|
70
|
+
const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
71
|
+
return SENSITIVE_KEY_PATTERNS.some((pattern) => normalized.includes(pattern));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A non-null, non-array object. {@link isRecord} covers class instances too,
|
|
75
|
+
* whose enumerable fields `JSON.stringify` *would* serialize, so we must
|
|
76
|
+
* traverse them to catch secrets.
|
|
77
|
+
*/
|
|
78
|
+
function isTraversableRecord(value) {
|
|
79
|
+
return isRecord(value);
|
|
80
|
+
}
|
|
81
|
+
function hasToJson(value) {
|
|
82
|
+
return typeof value.toJSON === "function";
|
|
83
|
+
}
|
|
84
|
+
function redactValue(value, depth, seen) {
|
|
85
|
+
if (Array.isArray(value)) {
|
|
86
|
+
if (depth >= MAX_DEPTH || seen.has(value))
|
|
87
|
+
return REDACTED;
|
|
88
|
+
seen.add(value);
|
|
89
|
+
try {
|
|
90
|
+
return value.map((item) => redactValue(item, depth + 1, seen));
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
seen.delete(value);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Objects defining `toJSON` (Date, URL, custom serializers) are serialized
|
|
97
|
+
// by `JSON.stringify` via the *return value* of `toJSON`, not their own
|
|
98
|
+
// enumerable keys. A key-based pass over the object's own properties would
|
|
99
|
+
// therefore miss credentials smuggled through `toJSON`, e.g.
|
|
100
|
+
// `{ toJSON: () => ({ apiKey: "sk-..." }) }` (CODEX P2). When `toJSON`
|
|
101
|
+
// returns a non-scalar (an object/array that could carry credential keys),
|
|
102
|
+
// redact *that* — the thing actually emitted. When it returns a scalar
|
|
103
|
+
// (Date/URL → ISO string), the original object is left intact, preserving
|
|
104
|
+
// prior behavior and identity.
|
|
105
|
+
if (isRecord(value) && hasToJson(value)) {
|
|
106
|
+
if (depth >= MAX_DEPTH || seen.has(value))
|
|
107
|
+
return REDACTED;
|
|
108
|
+
seen.add(value);
|
|
109
|
+
try {
|
|
110
|
+
const serialized = value.toJSON();
|
|
111
|
+
if (isRecord(serialized) || Array.isArray(serialized)) {
|
|
112
|
+
return redactValue(serialized, depth + 1, seen);
|
|
113
|
+
}
|
|
114
|
+
// Scalar result (string/number/…): the object serializes safely as-is.
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// A throwing toJSON must never let the raw object (whose own keys we
|
|
119
|
+
// skipped) through: fail closed.
|
|
120
|
+
return REDACTED;
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
seen.delete(value);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (isTraversableRecord(value)) {
|
|
127
|
+
if (depth >= MAX_DEPTH || seen.has(value))
|
|
128
|
+
return REDACTED;
|
|
129
|
+
seen.add(value);
|
|
130
|
+
try {
|
|
131
|
+
const out = {};
|
|
132
|
+
for (const [key, child] of Object.entries(value)) {
|
|
133
|
+
out[key] = isSensitiveKey(key) ? REDACTED : redactValue(child, depth + 1, seen);
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// A throwing getter (or other access error) must never let an
|
|
139
|
+
// unredacted object through: fail closed.
|
|
140
|
+
return REDACTED;
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
seen.delete(value);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Primitives and scalar-serializing objects (Date, URL, …) are returned
|
|
147
|
+
// untouched: they are not key/value bags we can safely rewrite.
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Returns a redacted deep copy of `context`. Any property whose key is
|
|
152
|
+
* {@link isSensitiveKey} has its value replaced with {@link REDACTED}; nested
|
|
153
|
+
* plain objects, class instances, and arrays are traversed. The input is never
|
|
154
|
+
* mutated, and the pass fails closed (returns {@link REDACTED}) on cycles,
|
|
155
|
+
* depth overflow, or a throwing getter.
|
|
156
|
+
*/
|
|
157
|
+
export function redactSensitive(context) {
|
|
158
|
+
return redactValue(context, 0, new Set());
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Query-string parameter names that commonly carry credentials in URLs.
|
|
162
|
+
* Matched case-insensitively against the parameter name.
|
|
163
|
+
*/
|
|
164
|
+
const SENSITIVE_URL_PARAMS = [
|
|
165
|
+
"access_token",
|
|
166
|
+
"accesstoken",
|
|
167
|
+
"refresh_token",
|
|
168
|
+
"api_key",
|
|
169
|
+
"apikey",
|
|
170
|
+
"code",
|
|
171
|
+
"token",
|
|
172
|
+
"secret",
|
|
173
|
+
"client_secret",
|
|
174
|
+
"password",
|
|
175
|
+
"passwd",
|
|
176
|
+
"pwd",
|
|
177
|
+
"state",
|
|
178
|
+
"sig",
|
|
179
|
+
"signature",
|
|
180
|
+
"auth",
|
|
181
|
+
];
|
|
182
|
+
const URL_USERINFO_RE = /(\b[a-z][a-z0-9+.-]*:\/\/)([^/?#@\s]+)@/gi;
|
|
183
|
+
/**
|
|
184
|
+
* Strip credentials from URL-shaped strings so they can be safely emitted in
|
|
185
|
+
* free-form text (error messages, stacks, lifted `request_url` fields). Unlike
|
|
186
|
+
* {@link redactSensitive}, which is key-based, this scrubs secrets embedded in
|
|
187
|
+
* the *value* itself:
|
|
188
|
+
*
|
|
189
|
+
* - URL userinfo: `http://user:pass@host` → `http://user:[REDACTED]@host`
|
|
190
|
+
* - sensitive query params: `?access_token=abc` → `?access_token=[REDACTED]`
|
|
191
|
+
*
|
|
192
|
+
* It is intentionally tolerant: it operates on any string (a DSN, a Mongo URI,
|
|
193
|
+
* an axios error message containing a URL) via regex rather than requiring a
|
|
194
|
+
* parseable URL, so malformed or partial URLs in error text are still scrubbed.
|
|
195
|
+
* Non-URL strings pass through unchanged.
|
|
196
|
+
*/
|
|
197
|
+
export function sanitizeUrlCredentials(input) {
|
|
198
|
+
if (typeof input !== "string" || input.length === 0)
|
|
199
|
+
return input;
|
|
200
|
+
// 1) userinfo: scheme://user:pass@ → mask the password (and any bare creds).
|
|
201
|
+
let out = input.replace(URL_USERINFO_RE, (_match, scheme, userinfo) => {
|
|
202
|
+
const colon = userinfo.indexOf(":");
|
|
203
|
+
if (colon === -1) {
|
|
204
|
+
// `scheme://token@host` — the whole userinfo is credential-like.
|
|
205
|
+
return `${scheme}${REDACTED}@`;
|
|
206
|
+
}
|
|
207
|
+
const user = userinfo.slice(0, colon);
|
|
208
|
+
return `${scheme}${user}:${REDACTED}@`;
|
|
209
|
+
});
|
|
210
|
+
// 2) sensitive query/fragment params: `key=value` → `key=[REDACTED]`.
|
|
211
|
+
// Match `?key=`, `&key=`, `;key=` separators and stop at the next delimiter.
|
|
212
|
+
out = out.replace(/([?&;])([a-z0-9_.\-]+)=([^&#;\s]*)/gi, (match, sep, key, _val) => {
|
|
213
|
+
const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
214
|
+
const sensitive = SENSITIVE_URL_PARAMS.some((p) => normalized === p.replace(/[^a-z0-9]/g, ""));
|
|
215
|
+
return sensitive ? `${sep}${key}=${REDACTED}` : match;
|
|
216
|
+
});
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Apply {@link sanitizeUrlCredentials} to the `message` and `stack` of a
|
|
221
|
+
* serialized-error-shaped object, returning a new object. Used by the logger's
|
|
222
|
+
* JSON and text paths so errors carrying DSNs, Mongo URIs, or
|
|
223
|
+
* `?access_token=`-bearing URLs do not leak credentials (the serialized error
|
|
224
|
+
* bypasses the key-based redactor). Returns the input unchanged when falsy.
|
|
225
|
+
*/
|
|
226
|
+
export function sanitizeSerializedError(error) {
|
|
227
|
+
if (!error)
|
|
228
|
+
return error;
|
|
229
|
+
const out = { ...error };
|
|
230
|
+
if (typeof out.message === "string")
|
|
231
|
+
out.message = sanitizeUrlCredentials(out.message);
|
|
232
|
+
if (typeof out.stack === "string")
|
|
233
|
+
out.stack = sanitizeUrlCredentials(out.stack);
|
|
234
|
+
return out;
|
|
235
|
+
}
|
|
@@ -33,6 +33,8 @@ export interface WorkflowExecutorConfig {
|
|
|
33
33
|
export interface WorkflowHandle<TOutput = unknown> {
|
|
34
34
|
/** Run ID */
|
|
35
35
|
runId: string;
|
|
36
|
+
/** Wait for background workflow execution and cleanup to finish */
|
|
37
|
+
settled(): Promise<void>;
|
|
36
38
|
/** Get current status */
|
|
37
39
|
status(): Promise<WorkflowRun>;
|
|
38
40
|
/** Wait for completion and get result */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-executor.d.ts","sourceRoot":"","sources":["../../../../src/src/workflow/executor/workflow-executor.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAKV,kBAAkB,EAElB,WAAW,EACX,cAAc,EACf,MAAM,aAAa,CAAC;AAErB,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAM5E,OAAO,EAAuC,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAElG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAOpD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,OAAO,EAAE,eAAe,CAAC;IACzB,kCAAkC;IAClC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,kCAAkC;IAClC,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oCAAoC;IACpC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,CAAC;IACrC,uCAAuC;IACvC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,mCAAmC;IACnC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACnD,wCAAwC;IACxC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxD;AAED,yCAAyC;AACzC,MAAM,WAAW,cAAc,CAAC,OAAO,GAAG,OAAO;IAC/C,aAAa;IACb,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/B,yCAAyC;IACzC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3B,0BAA0B;IAC1B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,WAAW,CAAc;IAEjC,OAAO,CAAC,SAAS,CAAmD;IACpE,OAAO,CAAC,YAAY,CAAC,CAAe;IAEpC,wCAAwC;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAU;IACvD,qEAAqE;IACrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAU;gBAE3C,MAAM,EAAE,sBAAsB;IA+C1C;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI9E;;OAEG;IAEH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,SAAS;IAIjE;;OAEG;IACG,KAAK,CAAC,MAAM,EAAE,OAAO,EACzB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3B,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAqDnC;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCnE;;;;;OAKG;IACG,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuHxE;;OAEG;IACH,OAAO,CAAC,YAAY;IAcpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAmDrB;;;;;OAKG;YACW,kBAAkB;IAmBhC;;OAEG;YACW,WAAW;IAkBzB;;OAEG;YACW,OAAO;IAkBrB;;OAEG;YACW,QAAQ;IActB;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB;;OAEG;IACH,OAAO,CAAC,YAAY;
|
|
1
|
+
{"version":3,"file":"workflow-executor.d.ts","sourceRoot":"","sources":["../../../../src/src/workflow/executor/workflow-executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -134,10 +134,10 @@ export class WorkflowExecutor {
|
|
|
134
134
|
_tenant: tenant,
|
|
135
135
|
};
|
|
136
136
|
await this.config.backend.createRun(run);
|
|
137
|
-
this.executeAsync(run.id).catch((error) => {
|
|
137
|
+
const settled = this.executeAsync(run.id).catch((error) => {
|
|
138
138
|
logger.error("Workflow failed", { runId: run.id }, error);
|
|
139
139
|
});
|
|
140
|
-
return this.createHandle(run.id);
|
|
140
|
+
return this.createHandle(run.id, settled);
|
|
141
141
|
}
|
|
142
142
|
/**
|
|
143
143
|
* Resume a paused/waiting workflow
|
|
@@ -409,9 +409,10 @@ export class WorkflowExecutor {
|
|
|
409
409
|
/**
|
|
410
410
|
* Create a handle for a workflow run
|
|
411
411
|
*/
|
|
412
|
-
createHandle(runId) {
|
|
412
|
+
createHandle(runId, settled) {
|
|
413
413
|
return {
|
|
414
414
|
runId,
|
|
415
|
+
settled: () => settled,
|
|
415
416
|
status: () => this.config.backend.getRun(runId),
|
|
416
417
|
result: () => this.waitForResult(runId),
|
|
417
418
|
cancel: () => this.cancel(runId),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "veryfront",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.638",
|
|
4
4
|
"description": "The simplest way to build AI-powered apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -358,6 +358,7 @@
|
|
|
358
358
|
"mdast-util-to-string": "4.0.0",
|
|
359
359
|
"react": "19.2.4",
|
|
360
360
|
"react-dom": "19.2.4",
|
|
361
|
+
"redis": "5.11.0",
|
|
361
362
|
"rehype-highlight": "7.0.2",
|
|
362
363
|
"rehype-raw": "7.0.0",
|
|
363
364
|
"rehype-sanitize": "6.0.0",
|