@memberjunction/server 5.38.0 → 5.39.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.
- package/README.md +67 -0
- package/dist/apolloServer/index.d.ts +0 -8
- package/dist/apolloServer/index.d.ts.map +1 -1
- package/dist/apolloServer/index.js +61 -0
- package/dist/apolloServer/index.js.map +1 -1
- package/dist/config.d.ts +68 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +24 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +2 -21
- package/dist/context.js.map +1 -1
- package/dist/generated/generated.d.ts +75 -0
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +314 -1
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.d.ts +51 -0
- package/dist/generic/FireAndForgetHeartbeat.d.ts.map +1 -0
- package/dist/generic/FireAndForgetHeartbeat.js +44 -0
- package/dist/generic/FireAndForgetHeartbeat.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +120 -2
- package/dist/index.js.map +1 -1
- package/dist/logging/NoLog.d.ts +50 -0
- package/dist/logging/NoLog.d.ts.map +1 -0
- package/dist/logging/NoLog.js +80 -0
- package/dist/logging/NoLog.js.map +1 -0
- package/dist/logging/bootAudit.d.ts +43 -0
- package/dist/logging/bootAudit.d.ts.map +1 -0
- package/dist/logging/bootAudit.js +83 -0
- package/dist/logging/bootAudit.js.map +1 -0
- package/dist/logging/boundaryLogPayload.d.ts +18 -0
- package/dist/logging/boundaryLogPayload.d.ts.map +1 -0
- package/dist/logging/boundaryLogPayload.js +18 -0
- package/dist/logging/boundaryLogPayload.js.map +1 -0
- package/dist/logging/secretRedactor.d.ts +23 -0
- package/dist/logging/secretRedactor.d.ts.map +1 -0
- package/dist/logging/secretRedactor.js +53 -0
- package/dist/logging/secretRedactor.js.map +1 -0
- package/dist/logging/shortenForLog.d.ts +8 -0
- package/dist/logging/shortenForLog.d.ts.map +1 -0
- package/dist/logging/shortenForLog.js +21 -0
- package/dist/logging/shortenForLog.js.map +1 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts +22 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -0
- package/dist/logging/variablesLoggingMiddleware.js +127 -0
- package/dist/logging/variablesLoggingMiddleware.js.map +1 -0
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +8 -4
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +259 -2
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +1276 -117
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/IntegrationProgressResolver.d.ts +90 -0
- package/dist/resolvers/IntegrationProgressResolver.d.ts.map +1 -0
- package/dist/resolvers/IntegrationProgressResolver.js +196 -0
- package/dist/resolvers/IntegrationProgressResolver.js.map +1 -0
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +19 -14
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +26 -5
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTestResolver.js +12 -2
- package/dist/resolvers/RunTestResolver.js.map +1 -1
- package/dist/resolvers/SearchEntitiesResolver.d.ts +46 -0
- package/dist/resolvers/SearchEntitiesResolver.d.ts.map +1 -0
- package/dist/resolvers/SearchEntitiesResolver.js +216 -0
- package/dist/resolvers/SearchEntitiesResolver.js.map +1 -0
- package/dist/resolvers/VectorizeEntityResolver.d.ts.map +1 -1
- package/dist/resolvers/VectorizeEntityResolver.js +14 -1
- package/dist/resolvers/VectorizeEntityResolver.js.map +1 -1
- package/dist/services/ScheduledJobsService.d.ts.map +1 -1
- package/dist/services/ScheduledJobsService.js +14 -2
- package/dist/services/ScheduledJobsService.js.map +1 -1
- package/package.json +75 -74
- package/src/__tests__/NoLog.test.ts +76 -0
- package/src/__tests__/bootAudit.test.ts +188 -0
- package/src/__tests__/boundaryLogPayload.test.ts +31 -0
- package/src/__tests__/getDataTokenRedaction.test.ts +84 -0
- package/src/__tests__/secretRedactor.test.ts +163 -0
- package/src/__tests__/subscriptionRedaction.test.ts +217 -0
- package/src/apolloServer/index.ts +58 -0
- package/src/config.ts +27 -0
- package/src/context.ts +2 -19
- package/src/generated/generated.ts +239 -1
- package/src/generic/FireAndForgetHeartbeat.ts +85 -0
- package/src/generic/__tests__/FireAndForgetHeartbeat.test.ts +99 -0
- package/src/index.ts +137 -2
- package/src/logging/NoLog.ts +88 -0
- package/src/logging/bootAudit.ts +117 -0
- package/src/logging/boundaryLogPayload.ts +19 -0
- package/src/logging/secretRedactor.ts +82 -0
- package/src/logging/shortenForLog.ts +17 -0
- package/src/logging/variablesLoggingMiddleware.ts +191 -0
- package/src/resolvers/GetDataResolver.ts +9 -5
- package/src/resolvers/IntegrationDiscoveryResolver.ts +1111 -120
- package/src/resolvers/IntegrationProgressResolver.ts +220 -0
- package/src/resolvers/MCPResolver.ts +18 -14
- package/src/resolvers/RunAIAgentResolver.ts +28 -5
- package/src/resolvers/RunTestResolver.ts +14 -2
- package/src/resolvers/SearchEntitiesResolver.ts +173 -0
- package/src/resolvers/VectorizeEntityResolver.ts +14 -1
- package/src/resolvers/__tests__/IntegrationProgressResolver.test.ts +170 -0
- package/src/services/ScheduledJobsService.ts +15 -2
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
/**
|
|
3
|
+
* Reflect-metadata key for `@NoLog` marks. A single symbol covers both parameter-level
|
|
4
|
+
* marks (stored against `(target, propertyKey)` pairs) and field-level marks (stored
|
|
5
|
+
* against the input class prototype).
|
|
6
|
+
*/
|
|
7
|
+
const NO_LOG_PARAM_KEY = Symbol('mj:NoLog:param');
|
|
8
|
+
const NO_LOG_FIELD_KEY = Symbol('mj:NoLog:field');
|
|
9
|
+
/**
|
|
10
|
+
* `@NoLog` — marks a resolver argument or input-type field as never-loggable.
|
|
11
|
+
*
|
|
12
|
+
* Two modes, distinguished by decorator arity at runtime:
|
|
13
|
+
*
|
|
14
|
+
* **Parameter** — applied to an `@Arg(...)` parameter on a resolver method:
|
|
15
|
+
* ```ts
|
|
16
|
+
* @Mutation(() => Boolean)
|
|
17
|
+
* async VoiceTestHubSpotCredential(
|
|
18
|
+
* @Arg('accessToken') @NoLog accessToken: string,
|
|
19
|
+
* @Ctx() ctx: AppContext,
|
|
20
|
+
* ): Promise<boolean> { ... }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* **Property** — applied to a `@Field()` on an `@InputType` class:
|
|
24
|
+
* ```ts
|
|
25
|
+
* @InputType()
|
|
26
|
+
* export class GetDataInputType {
|
|
27
|
+
* @Field(() => String) @NoLog Token: string;
|
|
28
|
+
* @Field(() => [String]) Queries: string[];
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* The variables-logging middleware reads these marks at runtime via
|
|
33
|
+
* `hasNoLogParameter` / `getNoLogFields` and replaces the marked value (or whole arg)
|
|
34
|
+
* with `"<redacted>"` before emitting the variables block. Metadata-covered fields
|
|
35
|
+
* (entity columns with `EntityFieldInfo.Encrypt=true`) do not need `@NoLog` — applying
|
|
36
|
+
* it is harmless but redundant. Use `@NoLog` for arguments that the redactor cannot
|
|
37
|
+
* identify via metadata: custom-resolver parameters, MCP tool args, fields on input
|
|
38
|
+
* types that don't map to a known entity.
|
|
39
|
+
*/
|
|
40
|
+
export function NoLog(target, propertyKey, parameterIndex) {
|
|
41
|
+
// Parameter-decorator path: (target, propertyKey, parameterIndex)
|
|
42
|
+
if (typeof parameterIndex === 'number' && propertyKey !== undefined) {
|
|
43
|
+
const existing = Reflect.getOwnMetadata(NO_LOG_PARAM_KEY, target, propertyKey) ?? new Set();
|
|
44
|
+
existing.add(parameterIndex);
|
|
45
|
+
Reflect.defineMetadata(NO_LOG_PARAM_KEY, existing, target, propertyKey);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Property-decorator path: (target, propertyKey)
|
|
49
|
+
if (propertyKey !== undefined) {
|
|
50
|
+
const existing = Reflect.getOwnMetadata(NO_LOG_FIELD_KEY, target) ?? new Set();
|
|
51
|
+
existing.add(String(propertyKey));
|
|
52
|
+
Reflect.defineMetadata(NO_LOG_FIELD_KEY, existing, target);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns true if `@NoLog` was applied to `methodName`'s argument at `parameterIndex`
|
|
58
|
+
* on the given resolver class prototype. False otherwise.
|
|
59
|
+
*
|
|
60
|
+
* Pass the resolver class itself (e.g. `MyResolver`) — the function reads from the
|
|
61
|
+
* prototype internally to match how type-graphql stores resolver metadata.
|
|
62
|
+
*/
|
|
63
|
+
export function hasNoLogParameter(resolverClass, methodName, parameterIndex) {
|
|
64
|
+
const target = resolverClass.prototype;
|
|
65
|
+
const marks = Reflect.getMetadata(NO_LOG_PARAM_KEY, target, methodName);
|
|
66
|
+
return marks !== undefined && marks.has(parameterIndex);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Returns the set of field names decorated `@NoLog` on the given input class. Empty set
|
|
70
|
+
* if none were marked.
|
|
71
|
+
*
|
|
72
|
+
* Pass the input class itself (e.g. `GetDataInputType`) — the function reads from the
|
|
73
|
+
* prototype internally.
|
|
74
|
+
*/
|
|
75
|
+
export function getNoLogFields(inputTypeClass) {
|
|
76
|
+
const target = inputTypeClass.prototype;
|
|
77
|
+
const marks = Reflect.getMetadata(NO_LOG_FIELD_KEY, target);
|
|
78
|
+
return marks ?? new Set();
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=NoLog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoLog.js","sourceRoot":"","sources":["../../src/logging/NoLog.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAClD,MAAM,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,KAAK,CAAC,MAAc,EAAE,WAA6B,EAAE,cAAuB;IAC1F,kEAAkE;IAClE,IAAI,OAAO,cAAc,KAAK,QAAQ,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QACpE,MAAM,QAAQ,GAAI,OAAO,CAAC,cAAc,CAAC,gBAAgB,EAAE,MAAM,EAAE,WAAW,CAA6B,IAAI,IAAI,GAAG,EAAU,CAAC;QACjI,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC7B,OAAO,CAAC,cAAc,CAAC,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;QACxE,OAAO;IACT,CAAC;IAED,iDAAiD;IACjD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAI,OAAO,CAAC,cAAc,CAAC,gBAAgB,EAAE,MAAM,CAA6B,IAAI,IAAI,GAAG,EAAU,CAAC;QACpH,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;QAClC,OAAO,CAAC,cAAc,CAAC,gBAAgB,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC3D,OAAO;IACT,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,aAAuB,EACvB,UAAkB,EAClB,cAAsB;IAEtB,MAAM,MAAM,GAAG,aAAa,CAAC,SAAmB,CAAC;IACjD,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,gBAAgB,EAAE,MAAM,EAAE,UAAU,CAA4B,CAAC;IACnG,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,cAAwB;IACrD,MAAM,MAAM,GAAG,cAAc,CAAC,SAAmB,CAAC;IAClD,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,gBAAgB,EAAE,MAAM,CAA4B,CAAC;IACvF,OAAO,KAAK,IAAI,IAAI,GAAG,EAAU,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural shape of an `@Arg` parameter as seen from outside type-graphql's internals.
|
|
3
|
+
* Used by the audit walker. Mirrors the subset of `ArgParamMetadata` we need.
|
|
4
|
+
*/
|
|
5
|
+
export type AuditArgParam = {
|
|
6
|
+
kind: 'arg';
|
|
7
|
+
index: number;
|
|
8
|
+
name: string;
|
|
9
|
+
target: Function;
|
|
10
|
+
methodName: string;
|
|
11
|
+
getType: () => unknown;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Structural shape of a resolver metadata entry from outside type-graphql's internals.
|
|
15
|
+
* Includes `@Query`, `@Mutation`, `@Subscription` entries.
|
|
16
|
+
*/
|
|
17
|
+
export type AuditResolver = {
|
|
18
|
+
target: Function;
|
|
19
|
+
methodName: string;
|
|
20
|
+
params?: ReadonlyArray<{
|
|
21
|
+
kind: string;
|
|
22
|
+
index: number;
|
|
23
|
+
} & Partial<AuditArgParam>>;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Scans every `@Query` / `@Mutation` / `@Subscription` for `@Arg`s that are neither
|
|
27
|
+
* metadata-bound (input type matching `Create<X>Input` / `Update<X>Input`) nor `@NoLog`-marked.
|
|
28
|
+
* Emits one warning per such arg.
|
|
29
|
+
*
|
|
30
|
+
* Gated on `loggingSettings.graphql.logVariables=true` — runs zero work in default config.
|
|
31
|
+
* In verbose mode, the audit is a diagnostic for the operator who chose to turn on
|
|
32
|
+
* variables logging, naming gaps that will leak plaintext while the flag is active.
|
|
33
|
+
*
|
|
34
|
+
* Never throws. Boot does not fail on a missed `@NoLog`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function auditResolversForUndecoratedArgs(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Internal helper exported for test injection. Takes a list of resolver metadata directly,
|
|
39
|
+
* skipping the global `getMetadataStorage()` lookup. The boot-time scan uses this after
|
|
40
|
+
* pulling from the global storage; tests pass in a synthetic fixture.
|
|
41
|
+
*/
|
|
42
|
+
export declare function auditResolverList(resolvers: ReadonlyArray<AuditResolver>): void;
|
|
43
|
+
//# sourceMappingURL=bootAudit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootAudit.d.ts","sourceRoot":"","sources":["../../src/logging/bootAudit.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,OAAO,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,QAAQ,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;CAClF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,gCAAgC,IAAI,IAAI,CAevD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,IAAI,CAI/E"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { getMetadataStorage } from 'type-graphql';
|
|
2
|
+
import { configInfo } from '../config.js';
|
|
3
|
+
import { hasNoLogParameter } from './NoLog.js';
|
|
4
|
+
// Delete is included alongside Create/Update so codegen DeleteMJ*Input resolvers count as
|
|
5
|
+
// metadata-bound and don't flood the audit with false positives (their args are PK + Options
|
|
6
|
+
// only — no encrypted values by construction). Must stay in sync with the redactor's
|
|
7
|
+
// INPUT_TYPE_REGEX in secretRedactor.ts. See docs/adr/0001-graphql-variables-logging-tiered-by-verbose.md.
|
|
8
|
+
const INPUT_TYPE_REGEX = /^(Create|Update|Delete).+Input$/;
|
|
9
|
+
/**
|
|
10
|
+
* Scans every `@Query` / `@Mutation` / `@Subscription` for `@Arg`s that are neither
|
|
11
|
+
* metadata-bound (input type matching `Create<X>Input` / `Update<X>Input`) nor `@NoLog`-marked.
|
|
12
|
+
* Emits one warning per such arg.
|
|
13
|
+
*
|
|
14
|
+
* Gated on `loggingSettings.graphql.logVariables=true` — runs zero work in default config.
|
|
15
|
+
* In verbose mode, the audit is a diagnostic for the operator who chose to turn on
|
|
16
|
+
* variables logging, naming gaps that will leak plaintext while the flag is active.
|
|
17
|
+
*
|
|
18
|
+
* Never throws. Boot does not fail on a missed `@NoLog`.
|
|
19
|
+
*/
|
|
20
|
+
export function auditResolversForUndecoratedArgs() {
|
|
21
|
+
if (!configInfo.loggingSettings.graphql.logVariables) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const storage = getMetadataStorage();
|
|
25
|
+
auditResolverList([
|
|
26
|
+
...storage.queries,
|
|
27
|
+
...storage.mutations,
|
|
28
|
+
...storage.subscriptions,
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Internal helper exported for test injection. Takes a list of resolver metadata directly,
|
|
33
|
+
* skipping the global `getMetadataStorage()` lookup. The boot-time scan uses this after
|
|
34
|
+
* pulling from the global storage; tests pass in a synthetic fixture.
|
|
35
|
+
*/
|
|
36
|
+
export function auditResolverList(resolvers) {
|
|
37
|
+
for (const resolver of resolvers) {
|
|
38
|
+
auditResolver(resolver);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function auditResolver(resolver) {
|
|
42
|
+
for (const param of resolver.params ?? []) {
|
|
43
|
+
if (param.kind !== 'arg') {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
auditArg(resolver, param);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function auditArg(resolver, argParam) {
|
|
50
|
+
const typeName = readArgTypeName(argParam);
|
|
51
|
+
if (typeName && INPUT_TYPE_REGEX.test(typeName)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (hasNoLogParameter(resolver.target, resolver.methodName, argParam.index)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const resolverName = `${resolver.target.name}.${resolver.methodName}`;
|
|
58
|
+
console.warn(`[mj:NoLog audit] Custom resolver ${resolverName} takes argument '${argParam.name}' ` +
|
|
59
|
+
`(type ${typeName ?? 'unknown'}) which is not marked @NoLog. Verify this argument does ` +
|
|
60
|
+
`not carry sensitive material; if it does, apply @NoLog. Variables for this resolver will ` +
|
|
61
|
+
`be logged in plaintext while logVariables=true is active.`);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Reads the declared input type name from an `@Arg` parameter's `getType()` thunk.
|
|
65
|
+
* Returns the class/scalar name when the thunk resolves to a class or named scalar; otherwise
|
|
66
|
+
* returns `undefined` (e.g. for array literals or complex generics we don't unwrap).
|
|
67
|
+
*/
|
|
68
|
+
function readArgTypeName(argParam) {
|
|
69
|
+
try {
|
|
70
|
+
const type = argParam.getType();
|
|
71
|
+
if (typeof type === 'function') {
|
|
72
|
+
return type.name;
|
|
73
|
+
}
|
|
74
|
+
if (type && typeof type === 'object' && 'name' in type && typeof type.name === 'string') {
|
|
75
|
+
return type.name;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=bootAudit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootAudit.js","sourceRoot":"","sources":["../../src/logging/bootAudit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,0FAA0F;AAC1F,6FAA6F;AAC7F,qFAAqF;AACrF,2GAA2G;AAC3G,MAAM,gBAAgB,GAAG,iCAAiC,CAAC;AAyB3D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gCAAgC;IAC9C,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QACrD,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,kBAAkB,EAIjC,CAAC;IACF,iBAAiB,CAAC;QAChB,GAAG,OAAO,CAAC,OAAO;QAClB,GAAG,OAAO,CAAC,SAAS;QACpB,GAAG,OAAO,CAAC,aAAa;KACzB,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAuC;IACvE,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,QAAuB;IAC5C,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QAC1C,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACzB,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,QAAQ,EAAE,KAAsB,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,QAAuB,EAAE,QAAuB;IAChE,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,QAAQ,IAAI,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChD,OAAO;IACT,CAAC;IACD,IAAI,iBAAiB,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5E,OAAO;IACT,CAAC;IACD,MAAM,YAAY,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;IACtE,OAAO,CAAC,IAAI,CACV,oCAAoC,YAAY,oBAAoB,QAAQ,CAAC,IAAI,IAAI;QACrF,SAAS,QAAQ,IAAI,SAAS,0DAA0D;QACxF,2FAA2F;QAC3F,2DAA2D,CAC5D,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,QAAuB;IAC9C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QAChC,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;YAC/B,OAAQ,IAA0B,CAAC,IAAI,CAAC;QAC1C,CAAC;QACD,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,IAAI,IAAI,OAAQ,IAA0B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC/G,OAAQ,IAAyB,CAAC,IAAI,CAAC;QACzC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the always-on GraphQL boundary log payload: operation name ONLY.
|
|
3
|
+
*
|
|
4
|
+
* Variable VALUES are never emitted here, in any configuration — this is the load-bearing
|
|
5
|
+
* fix for the #2638 secret leak. Verbose variables logging (MJ_LOG_GRAPHQL_VARIABLES=true)
|
|
6
|
+
* is the job of `variablesLoggingMiddleware`, which emits per-root-resolver, fully-emitted
|
|
7
|
+
* values with `Encrypt=true` fields masked.
|
|
8
|
+
*
|
|
9
|
+
* Pure function, no MJ-server import surface, so the "no `variables` key in the boundary
|
|
10
|
+
* line" property is testable in isolation without booting the request-context dependency
|
|
11
|
+
* chain.
|
|
12
|
+
*
|
|
13
|
+
* See docs/adr/0001-graphql-variables-logging-tiered-by-verbose.md.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildBoundaryLogPayload(operationName: string | undefined): {
|
|
16
|
+
operationName: string | undefined;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=boundaryLogPayload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundaryLogPayload.d.ts","sourceRoot":"","sources":["../../src/logging/boundaryLogPayload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,GAAG,SAAS,GAChC;IAAE,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAEvC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the always-on GraphQL boundary log payload: operation name ONLY.
|
|
3
|
+
*
|
|
4
|
+
* Variable VALUES are never emitted here, in any configuration — this is the load-bearing
|
|
5
|
+
* fix for the #2638 secret leak. Verbose variables logging (MJ_LOG_GRAPHQL_VARIABLES=true)
|
|
6
|
+
* is the job of `variablesLoggingMiddleware`, which emits per-root-resolver, fully-emitted
|
|
7
|
+
* values with `Encrypt=true` fields masked.
|
|
8
|
+
*
|
|
9
|
+
* Pure function, no MJ-server import surface, so the "no `variables` key in the boundary
|
|
10
|
+
* line" property is testable in isolation without booting the request-context dependency
|
|
11
|
+
* chain.
|
|
12
|
+
*
|
|
13
|
+
* See docs/adr/0001-graphql-variables-logging-tiered-by-verbose.md.
|
|
14
|
+
*/
|
|
15
|
+
export function buildBoundaryLogPayload(operationName) {
|
|
16
|
+
return { operationName };
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=boundaryLogPayload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundaryLogPayload.js","sourceRoot":"","sources":["../../src/logging/boundaryLogPayload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,uBAAuB,CACrC,aAAiC;IAEjC,OAAO,EAAE,aAAa,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IMetadataProvider } from '@memberjunction/core';
|
|
2
|
+
/**
|
|
3
|
+
* Input to the redactor. Built per `@Arg` per resolver call by the variables-logging middleware.
|
|
4
|
+
*
|
|
5
|
+
* - `inputTypeName` is the GraphQL input type name from the schema (e.g. `"CreateMJCredentialInput"`),
|
|
6
|
+
* derived from `info.parentType.getFields()[info.fieldName].args[i].type` — NOT from any
|
|
7
|
+
* `args[i].constructor.name`, because type-graphql v2.0.0-beta.3 passes raw plain-object args
|
|
8
|
+
* to middleware (conversion to typed instances happens after the middleware chain unwinds).
|
|
9
|
+
* - `provider` is the per-request metadata provider (`context.providers[0].provider`).
|
|
10
|
+
* - `noLogParameter` indicates the `@Arg` itself was decorated `@NoLog` at the parameter level.
|
|
11
|
+
* - `noLogFields` lists field names that were decorated `@NoLog` at the `@Field()` level on the
|
|
12
|
+
* input class. The redactor honors both `EntityFieldInfo.Encrypt=true` (metadata-driven) and
|
|
13
|
+
* this set (decorator-driven) when walking top-level keys.
|
|
14
|
+
*/
|
|
15
|
+
export type RedactionContext = {
|
|
16
|
+
inputTypeName: string;
|
|
17
|
+
rawValue: unknown;
|
|
18
|
+
provider: IMetadataProvider;
|
|
19
|
+
noLogParameter: boolean;
|
|
20
|
+
noLogFields: ReadonlySet<string>;
|
|
21
|
+
};
|
|
22
|
+
export declare function redactArg(ctx: RedactionContext): unknown;
|
|
23
|
+
//# sourceMappingURL=secretRedactor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secretRedactor.d.ts","sourceRoot":"","sources":["../../src/logging/secretRedactor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAG9D;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAClC,CAAC;AAaF,wBAAgB,SAAS,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CA4CxD"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { shortenForLog } from './shortenForLog.js';
|
|
2
|
+
// Delete is included so DeleteMJ*Input resolvers resolve to their entity (yielding an empty
|
|
3
|
+
// or value-free encrypted-field walk) instead of falling to the fail-open shortenForLog path —
|
|
4
|
+
// keeps the boot audit quiet on them. Security is identical either way: Delete inputs carry
|
|
5
|
+
// PK + Options only, no encrypted values. Must stay in sync with bootAudit.ts's INPUT_TYPE_REGEX.
|
|
6
|
+
const INPUT_TYPE_REGEX = /^(Create|Update|Delete)(?<name>.+)Input$/;
|
|
7
|
+
// Assumes EntityFieldInfo.Name === GraphQLFieldName for input-type fields.
|
|
8
|
+
// True today for all codegen output (323 Create*Input + 323 Update*Input).
|
|
9
|
+
// type-graphql allows @Field({ name: 'overrideName' }) to rename fields at the
|
|
10
|
+
// GraphQL layer; MJ codegen does not use this. A future maintainer renaming an
|
|
11
|
+
// encrypted field at the GraphQL layer would silently miss redaction.
|
|
12
|
+
export function redactArg(ctx) {
|
|
13
|
+
if (ctx.noLogParameter) {
|
|
14
|
+
return '<redacted>';
|
|
15
|
+
}
|
|
16
|
+
if (ctx.provider.Entities.length === 0) {
|
|
17
|
+
return '<metadata-not-ready>';
|
|
18
|
+
}
|
|
19
|
+
// Determine the encrypted-field set from entity metadata IF this input maps to a known entity.
|
|
20
|
+
// Custom / non-CRUD inputs (e.g. GetDataInput) have no entity binding — that's fine; field-level
|
|
21
|
+
// @NoLog still applies below. The entity path only adds metadata-driven encrypted-field names.
|
|
22
|
+
let encryptedFieldNames = EMPTY_SET;
|
|
23
|
+
const match = INPUT_TYPE_REGEX.exec(ctx.inputTypeName);
|
|
24
|
+
if (match?.groups?.name) {
|
|
25
|
+
const entity = ctx.provider.Entities.find((e) => e.ClassName === match.groups.name);
|
|
26
|
+
if (entity) {
|
|
27
|
+
encryptedFieldNames = new Set(entity.EncryptedFields.map((f) => f.Name));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Walk top-level keys whenever we have BOTH a redaction source (encrypted fields or @NoLog fields)
|
|
31
|
+
// AND a plain-object value. This honors field-level @NoLog even on non-entity-bound inputs — the
|
|
32
|
+
// exact case @NoLog exists for (custom resolvers, e.g. GetDataInputType.Token). Without a redaction
|
|
33
|
+
// source, or for non-object values, fall through to shortenForLog as before.
|
|
34
|
+
const canWalk = (encryptedFieldNames.size > 0 || ctx.noLogFields.size > 0) &&
|
|
35
|
+
ctx.rawValue !== null &&
|
|
36
|
+
typeof ctx.rawValue === 'object' &&
|
|
37
|
+
!Array.isArray(ctx.rawValue);
|
|
38
|
+
if (!canWalk) {
|
|
39
|
+
return shortenForLog(ctx.rawValue);
|
|
40
|
+
}
|
|
41
|
+
const result = {};
|
|
42
|
+
for (const [key, value] of Object.entries(ctx.rawValue)) {
|
|
43
|
+
if (encryptedFieldNames.has(key) || ctx.noLogFields.has(key)) {
|
|
44
|
+
result[key] = '<redacted>';
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
result[key] = shortenForLog(value);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
const EMPTY_SET = new Set();
|
|
53
|
+
//# sourceMappingURL=secretRedactor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secretRedactor.js","sourceRoot":"","sources":["../../src/logging/secretRedactor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAuBnD,4FAA4F;AAC5F,+FAA+F;AAC/F,4FAA4F;AAC5F,kGAAkG;AAClG,MAAM,gBAAgB,GAAG,0CAA0C,CAAC;AAEpE,2EAA2E;AAC3E,2EAA2E;AAC3E,+EAA+E;AAC/E,+EAA+E;AAC/E,sEAAsE;AACtE,MAAM,UAAU,SAAS,CAAC,GAAqB;IAC7C,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;QACvB,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvC,OAAO,sBAAsB,CAAC;IAChC,CAAC;IAED,+FAA+F;IAC/F,iGAAiG;IACjG,+FAA+F;IAC/F,IAAI,mBAAmB,GAAwB,SAAS,CAAC;IACzD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACvD,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,MAAO,CAAC,IAAI,CAAC,CAAC;QACrF,IAAI,MAAM,EAAE,CAAC;YACX,mBAAmB,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED,mGAAmG;IACnG,iGAAiG;IACjG,oGAAoG;IACpG,6EAA6E;IAC7E,MAAM,OAAO,GACX,CAAC,mBAAmB,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC;QAC1D,GAAG,CAAC,QAAQ,KAAK,IAAI;QACrB,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ;QAChC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAE/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,QAAmC,CAAC,EAAE,CAAC;QACnF,IAAI,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7D,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,SAAS,GAAwB,IAAI,GAAG,EAAU,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders a value for one-line console logging without Node's `[Object]` truncation.
|
|
3
|
+
* Arrays keep their structure; non-array objects collapse to JSON, truncated at `maxLen`.
|
|
4
|
+
* Objects whose JSON exceeds `maxLen` and contain nested structure are recursed into so
|
|
5
|
+
* outer keys remain visible.
|
|
6
|
+
*/
|
|
7
|
+
export declare function shortenForLog(value: unknown, maxLen?: number): unknown;
|
|
8
|
+
//# sourceMappingURL=shortenForLog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shortenForLog.d.ts","sourceRoot":"","sources":["../../src/logging/shortenForLog.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,SAAM,GAAG,OAAO,CAUnE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders a value for one-line console logging without Node's `[Object]` truncation.
|
|
3
|
+
* Arrays keep their structure; non-array objects collapse to JSON, truncated at `maxLen`.
|
|
4
|
+
* Objects whose JSON exceeds `maxLen` and contain nested structure are recursed into so
|
|
5
|
+
* outer keys remain visible.
|
|
6
|
+
*/
|
|
7
|
+
export function shortenForLog(value, maxLen = 300) {
|
|
8
|
+
if (value === null || typeof value !== 'object')
|
|
9
|
+
return value;
|
|
10
|
+
if (Array.isArray(value))
|
|
11
|
+
return value.map((v) => shortenForLog(v, maxLen));
|
|
12
|
+
const json = JSON.stringify(value);
|
|
13
|
+
if (json.length <= maxLen)
|
|
14
|
+
return json;
|
|
15
|
+
const result = {};
|
|
16
|
+
for (const [k, v] of Object.entries(value)) {
|
|
17
|
+
result[k] = shortenForLog(v, maxLen);
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=shortenForLog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shortenForLog.js","sourceRoot":"","sources":["../../src/logging/shortenForLog.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,MAAM,GAAG,GAAG;IACxD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM;QAAE,OAAO,IAAI,CAAC;IACvC,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;QACtE,MAAM,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { MiddlewareFn } from 'type-graphql';
|
|
2
|
+
import type { AppContext } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Variables-logging middleware. Default-off; gated on `loggingSettings.graphql.logVariables`.
|
|
5
|
+
*
|
|
6
|
+
* NOTE: this middleware is NOT the primary leak defense. The primary defense is the removal
|
|
7
|
+
* of the `variables` field from the always-on log line in `context.ts`. This middleware
|
|
8
|
+
* provides an opt-in, redacted verbose-echo path for developers debugging locally.
|
|
9
|
+
*
|
|
10
|
+
* When enabled, fires once per root resolver call (skips field resolvers via
|
|
11
|
+
* `info.path.prev === undefined`). For each `@Arg`:
|
|
12
|
+
* - Derives the GraphQL input type name from the schema (NOT from `args[i].constructor.name`,
|
|
13
|
+
* because type-graphql v2.0.0-beta.3 passes raw plain-object args to middleware).
|
|
14
|
+
* - Looks up `@NoLog` marks (parameter-level on the resolver, field-level on the input class).
|
|
15
|
+
* - Delegates redaction to `redactArg`.
|
|
16
|
+
*
|
|
17
|
+
* Emits a single `console.dir` line with shape `{ operation, args }`. Note: the key names
|
|
18
|
+
* differ from the always-on log line (`operationName` vs `operation`, `variables` vs `args`)
|
|
19
|
+
* — operators with log-grep automation should update their patterns.
|
|
20
|
+
*/
|
|
21
|
+
export declare const variablesLoggingMiddleware: MiddlewareFn<AppContext>;
|
|
22
|
+
//# sourceMappingURL=variablesLoggingMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variablesLoggingMiddleware.d.ts","sourceRoot":"","sources":["../../src/logging/variablesLoggingMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAKjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA2E9C;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,0BAA0B,EAAE,YAAY,CAAC,UAAU,CAsE/D,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { getMetadataStorage } from 'type-graphql';
|
|
2
|
+
import { getNamedType } from 'graphql';
|
|
3
|
+
import { configInfo } from '../config.js';
|
|
4
|
+
import { redactArg } from './secretRedactor.js';
|
|
5
|
+
import { hasNoLogParameter, getNoLogFields } from './NoLog.js';
|
|
6
|
+
let resolverLookup;
|
|
7
|
+
function getResolverLookup() {
|
|
8
|
+
if (resolverLookup !== undefined) {
|
|
9
|
+
return resolverLookup;
|
|
10
|
+
}
|
|
11
|
+
const storage = getMetadataStorage();
|
|
12
|
+
const lookup = new Map();
|
|
13
|
+
const collect = (entries) => {
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
lookup.set(entry.schemaName, {
|
|
16
|
+
target: entry.target,
|
|
17
|
+
methodName: entry.methodName,
|
|
18
|
+
params: entry.params ?? [],
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
collect(storage.queries);
|
|
23
|
+
collect(storage.mutations);
|
|
24
|
+
collect(storage.subscriptions);
|
|
25
|
+
resolverLookup = lookup;
|
|
26
|
+
return lookup;
|
|
27
|
+
}
|
|
28
|
+
function findInputClass(typeName) {
|
|
29
|
+
const storage = getMetadataStorage();
|
|
30
|
+
const found = storage.inputTypes.find((t) => t.name === typeName);
|
|
31
|
+
return found?.target;
|
|
32
|
+
}
|
|
33
|
+
/** Type guard for `MinimalArgParamMeta`. */
|
|
34
|
+
function isArgParam(p) {
|
|
35
|
+
return p.kind === 'arg';
|
|
36
|
+
}
|
|
37
|
+
const warnedResolverSignatures = new Set();
|
|
38
|
+
/**
|
|
39
|
+
* Variables-logging middleware. Default-off; gated on `loggingSettings.graphql.logVariables`.
|
|
40
|
+
*
|
|
41
|
+
* NOTE: this middleware is NOT the primary leak defense. The primary defense is the removal
|
|
42
|
+
* of the `variables` field from the always-on log line in `context.ts`. This middleware
|
|
43
|
+
* provides an opt-in, redacted verbose-echo path for developers debugging locally.
|
|
44
|
+
*
|
|
45
|
+
* When enabled, fires once per root resolver call (skips field resolvers via
|
|
46
|
+
* `info.path.prev === undefined`). For each `@Arg`:
|
|
47
|
+
* - Derives the GraphQL input type name from the schema (NOT from `args[i].constructor.name`,
|
|
48
|
+
* because type-graphql v2.0.0-beta.3 passes raw plain-object args to middleware).
|
|
49
|
+
* - Looks up `@NoLog` marks (parameter-level on the resolver, field-level on the input class).
|
|
50
|
+
* - Delegates redaction to `redactArg`.
|
|
51
|
+
*
|
|
52
|
+
* Emits a single `console.dir` line with shape `{ operation, args }`. Note: the key names
|
|
53
|
+
* differ from the always-on log line (`operationName` vs `operation`, `variables` vs `args`)
|
|
54
|
+
* — operators with log-grep automation should update their patterns.
|
|
55
|
+
*/
|
|
56
|
+
export const variablesLoggingMiddleware = async (action, next) => {
|
|
57
|
+
// Field resolvers (info.path.prev !== undefined) are skipped — only root @Query/@Mutation/@Subscription.
|
|
58
|
+
if (action.info.path.prev !== undefined) {
|
|
59
|
+
return next();
|
|
60
|
+
}
|
|
61
|
+
// Hot-path zero-cost short-circuit when the flag is off.
|
|
62
|
+
if (!configInfo.loggingSettings.graphql.logVariables) {
|
|
63
|
+
return next();
|
|
64
|
+
}
|
|
65
|
+
const provider = action.context.providers?.[0]?.provider;
|
|
66
|
+
if (!provider) {
|
|
67
|
+
return next();
|
|
68
|
+
}
|
|
69
|
+
const fieldDef = action.info.parentType.getFields()[action.info.fieldName];
|
|
70
|
+
if (!fieldDef) {
|
|
71
|
+
return next();
|
|
72
|
+
}
|
|
73
|
+
const resolverEntry = getResolverLookup().get(action.info.fieldName);
|
|
74
|
+
const argParams = (resolverEntry?.params ?? []).filter(isArgParam);
|
|
75
|
+
const redactedArgs = {};
|
|
76
|
+
let hasUndecoratedCustomArg = false;
|
|
77
|
+
for (const argDef of fieldDef.args) {
|
|
78
|
+
const inputTypeName = getNamedType(argDef.type).name;
|
|
79
|
+
const rawValue = action.args[argDef.name];
|
|
80
|
+
const paramMeta = argParams.find((p) => p.name === argDef.name);
|
|
81
|
+
const noLogParameter = paramMeta && resolverEntry
|
|
82
|
+
? hasNoLogParameter(resolverEntry.target, resolverEntry.methodName, paramMeta.index)
|
|
83
|
+
: false;
|
|
84
|
+
const inputClass = findInputClass(inputTypeName);
|
|
85
|
+
const noLogFields = inputClass ? getNoLogFields(inputClass) : new Set();
|
|
86
|
+
redactedArgs[argDef.name] = redactArg({
|
|
87
|
+
inputTypeName,
|
|
88
|
+
rawValue,
|
|
89
|
+
provider,
|
|
90
|
+
noLogParameter,
|
|
91
|
+
noLogFields,
|
|
92
|
+
});
|
|
93
|
+
if (!noLogParameter && isCustomArg(inputTypeName, noLogFields, provider)) {
|
|
94
|
+
hasUndecoratedCustomArg = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// eslint-disable-next-line no-console
|
|
98
|
+
console.dir({ operation: action.info.fieldName, args: redactedArgs }, { depth: null, breakLength: 200 });
|
|
99
|
+
if (hasUndecoratedCustomArg && resolverEntry) {
|
|
100
|
+
const signature = `${resolverEntry.target.name}.${resolverEntry.methodName}`;
|
|
101
|
+
if (!warnedResolverSignatures.has(signature)) {
|
|
102
|
+
warnedResolverSignatures.add(signature);
|
|
103
|
+
console.warn(`[mj:NoLog] Resolver ${signature} has un-decorated, non-metadata-bound argument(s). ` +
|
|
104
|
+
`Variables for this resolver were logged in plaintext while logVariables=true is active. ` +
|
|
105
|
+
`Apply @NoLog to sensitive arguments to suppress this.`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return next();
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Heuristic: an arg is "custom" (i.e. needs `@NoLog` discipline because metadata can't redact it)
|
|
112
|
+
* when its GraphQL input type is not a known `Create<X>Input` / `Update<X>Input` for an entity
|
|
113
|
+
* in the provider, AND no field-level `@NoLog` marks are present on the input class.
|
|
114
|
+
*/
|
|
115
|
+
function isCustomArg(inputTypeName, noLogFields, provider) {
|
|
116
|
+
if (noLogFields.size > 0) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
const match = /^(Create|Update)(?<name>.+)Input$/.exec(inputTypeName);
|
|
120
|
+
if (!match || !match.groups?.name) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
const className = match.groups.name;
|
|
124
|
+
const found = provider.Entities.find((e) => e.ClassName === className);
|
|
125
|
+
return !found;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=variablesLoggingMiddleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variablesLoggingMiddleware.js","sourceRoot":"","sources":["../../src/logging/variablesLoggingMiddleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GetDataResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/GetDataResolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"GetDataResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/GetDataResolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAWzC,qBACa,gBAAgB;IAGzB,KAAK,EAAE,MAAM,CAAC;IAGd,OAAO,EAAE,MAAM,EAAE,CAAC;CACrB;AAGD,qBACa,iBAAiB;IAE1B,OAAO,EAAE,OAAO,CAAC;IAGjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAGlB,aAAa,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAEjC;;OAEG;IAEH,OAAO,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CAC9B;AAED,qBACa,sBAAsB;IAE/B,OAAO,EAAE,OAAO,CAAC;IAGjB,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,OAAO,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAED,qBACa,sBAAsB;IAE/B,EAAE,EAAE,MAAM,CAAC;IAGX,IAAI,EAAE,MAAM,CAAC;IAGb,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,UAAU,EAAE,MAAM,CAAC;IAGnB,QAAQ,EAAE,MAAM,CAAC;IAGjB,SAAS,EAAE,MAAM,CAAC;IAGlB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,MAAM,EAAE,2BAA2B,EAAE,CAAC;CACzC;AAED,qBACa,2BAA2B;IAEpC,EAAE,EAAE,MAAM,CAAC;IAGX,IAAI,EAAE,MAAM,CAAC;IAGb,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,IAAI,EAAE,MAAM,CAAC;IAGb,UAAU,EAAE,OAAO,CAAC;IAGpB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,eAAe;IACxB;;;;OAIG;IAGG,OAAO,CACyB,KAAK,EAAE,gBAAgB,EACtD,OAAO,EAAE,UAAU,GACvB,OAAO,CAAC,iBAAiB,CAAC;IAqGvB,cAAc,CACb,OAAO,EAAE,UAAU,GACvB,OAAO,CAAC,sBAAsB,CAAC;CAsCrC;AAGD,qBAAa,WAAW;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,IAAI,CAAC;IACb,UAAU,EAAE,GAAG,CAAC;CACnB;AACD;;;;GAIG;AACH,qBAAa,kBAAkB;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB;;OAEG;IACH,gBAAgB,EAAE,GAAG,CAAC;IACtB,SAAS,EAAE,WAAW,EAAE,CAAC;CAC5B;AAGD,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,GAAE,MAA+B,EAAE,gBAAgB,CAAC,EAAE,GAAG,GAAG,kBAAkB,CAezI;AACD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,QAQ9C;AACD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,WAExC;AACD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,WAMzC;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,QAW5D"}
|
|
@@ -11,9 +11,10 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
11
11
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
12
|
};
|
|
13
13
|
import { Arg, Ctx, Field, InputType, ObjectType, Query } from 'type-graphql';
|
|
14
|
-
import { LogError, LogStatus } from '@memberjunction/core';
|
|
14
|
+
import { LogError, LogStatus, LogStatusEx } from '@memberjunction/core';
|
|
15
15
|
import { QueryCompositionEngine } from '@memberjunction/generic-database-provider';
|
|
16
16
|
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
|
|
17
|
+
import { NoLog } from '../logging/NoLog.js';
|
|
17
18
|
import { v4 as uuidv4 } from 'uuid';
|
|
18
19
|
import { GetReadOnlyDataSource, GetReadOnlyProvider } from '../util.js';
|
|
19
20
|
import { getDbType } from '../index.js';
|
|
@@ -23,6 +24,7 @@ let GetDataInputType = class GetDataInputType {
|
|
|
23
24
|
};
|
|
24
25
|
__decorate([
|
|
25
26
|
Field(() => String),
|
|
27
|
+
NoLog,
|
|
26
28
|
__metadata("design:type", String)
|
|
27
29
|
], GetDataInputType.prototype, "Token", void 0);
|
|
28
30
|
__decorate([
|
|
@@ -158,9 +160,11 @@ export class GetDataResolver {
|
|
|
158
160
|
*/
|
|
159
161
|
async GetData(input, context) {
|
|
160
162
|
try {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
163
|
+
LogStatusEx({
|
|
164
|
+
message: `GetDataResolver.GetData() ---- IMPORTANT - temporarily using the same connection as rest of the server, we need to separately create a READ ONLY CONNECTION and pass that in the AppContext so we can use that special connection here to ensure we are using a lower privileged connection for this operation to prevent mutation from being possible.`,
|
|
165
|
+
verboseOnly: true,
|
|
166
|
+
});
|
|
167
|
+
LogStatus(`GetData invoked: ${input.Queries.length} queries`);
|
|
164
168
|
// validate the token
|
|
165
169
|
if (!isTokenValid(input.Token)) {
|
|
166
170
|
throw new Error(`Token ${input.Token} is not valid or has expired`);
|