@shivaedev/platform 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +33 -8
- package/dist/server/RedactionPolicy.d.ts +4 -0
- package/dist/server/RedactionPolicy.d.ts.map +1 -0
- package/dist/server/RedactionPolicy.js +4 -0
- package/dist/server/RedactionPolicy.js.map +1 -0
- package/dist/server/appHostHttp.d.ts +3 -3
- package/dist/server/appHostHttp.d.ts.map +1 -1
- package/dist/server/appHostHttp.js +10 -5
- package/dist/server/appHostHttp.js.map +1 -1
- package/dist/server/hostOptions.d.ts +1 -0
- package/dist/server/hostOptions.d.ts.map +1 -1
- package/dist/server/otlpHttpClient.d.ts.map +1 -1
- package/dist/server/otlpHttpClient.js +3 -1
- package/dist/server/otlpHttpClient.js.map +1 -1
- package/dist/server/otlpTracing.d.ts.map +1 -1
- package/dist/server/otlpTracing.js +4 -1
- package/dist/server/otlpTracing.js.map +1 -1
- package/dist/server/redactingDiagnostics.d.ts +5 -0
- package/dist/server/redactingDiagnostics.d.ts.map +1 -0
- package/dist/server/redactingDiagnostics.js +25 -0
- package/dist/server/redactingDiagnostics.js.map +1 -0
- package/dist/server/redactingRpcSerialization.d.ts +4 -0
- package/dist/server/redactingRpcSerialization.d.ts.map +1 -0
- package/dist/server/redactingRpcSerialization.js +74 -0
- package/dist/server/redactingRpcSerialization.js.map +1 -0
- package/dist/server/redactingTracer.d.ts +4 -0
- package/dist/server/redactingTracer.d.ts.map +1 -0
- package/dist/server/redactingTracer.js +32 -0
- package/dist/server/redactingTracer.js.map +1 -0
- package/dist/server/rpc-server/local.d.ts.map +1 -1
- package/dist/server/rpc-server/local.js +10 -2
- package/dist/server/rpc-server/local.js.map +1 -1
- package/dist/server/rpc-server/redact.d.ts +2 -1
- package/dist/server/rpc-server/redact.d.ts.map +1 -1
- package/dist/server/rpc-server/redact.js +26 -18
- package/dist/server/rpc-server/redact.js.map +1 -1
- package/dist/server/rpc-server/redactCause.d.ts +2 -1
- package/dist/server/rpc-server/redactCause.d.ts.map +1 -1
- package/dist/server/rpc-server/redactCause.js +64 -8
- package/dist/server/rpc-server/redactCause.js.map +1 -1
- package/dist/server/rpc-server/sensitive.d.ts +2 -1
- package/dist/server/rpc-server/sensitive.d.ts.map +1 -1
- package/dist/server/rpc-server/sensitive.js +8 -2
- package/dist/server/rpc-server/sensitive.js.map +1 -1
- package/dist/server/rpc-server/tracing.d.ts +1 -1
- package/dist/server/rpc-server/tracing.d.ts.map +1 -1
- package/dist/server/rpc-server/tracing.js +9 -3
- package/dist/server/rpc-server/tracing.js.map +1 -1
- package/dist/server/safeOtlpSerialization.d.ts +2 -1
- package/dist/server/safeOtlpSerialization.d.ts.map +1 -1
- package/dist/server/safeOtlpSerialization.js +32 -21
- package/dist/server/safeOtlpSerialization.js.map +1 -1
- package/dist/server/schemaSensitiveKeys.d.ts +5 -0
- package/dist/server/schemaSensitiveKeys.d.ts.map +1 -0
- package/dist/server/schemaSensitiveKeys.js +143 -0
- package/dist/server/schemaSensitiveKeys.js.map +1 -0
- package/package.json +5 -5
- package/src/server/RedactionPolicy.ts +4 -0
- package/src/server/appHostHttp.ts +12 -5
- package/src/server/hostOptions.ts +1 -0
- package/src/server/otlpHttpClient.ts +3 -1
- package/src/server/otlpTracing.ts +4 -1
- package/src/server/redactingDiagnostics.ts +33 -0
- package/src/server/redactingRpcSerialization.ts +85 -0
- package/src/server/redactingTracer.ts +37 -0
- package/src/server/rpc-server/local.ts +11 -2
- package/src/server/rpc-server/redact.ts +26 -18
- package/src/server/rpc-server/redactCause.ts +73 -9
- package/src/server/rpc-server/sensitive.ts +8 -2
- package/src/server/rpc-server/tracing.ts +9 -4
- package/src/server/safeOtlpSerialization.ts +44 -34
- package/src/server/schemaSensitiveKeys.ts +148 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.js","sourceRoot":"","sources":["../../../src/server/rpc-server/tracing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"tracing.js","sourceRoot":"","sources":["../../../src/server/rpc-server/tracing.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Layer } from "effect";
|
|
2
2
|
import { OtlpSerialization } from "effect/observability";
|
|
3
|
-
|
|
3
|
+
import { type SensitiveKey } from "#server/rpc-server/sensitive.ts";
|
|
4
|
+
export declare function redactOtlpText(value: string, key?: string, sensitive?: SensitiveKey): string;
|
|
4
5
|
export declare const safeOtlpSerialization: Layer.Layer<OtlpSerialization.OtlpSerialization, never, OtlpSerialization.OtlpSerialization>;
|
|
5
6
|
//# sourceMappingURL=safeOtlpSerialization.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safeOtlpSerialization.d.ts","sourceRoot":"","sources":["../../src/server/safeOtlpSerialization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"safeOtlpSerialization.d.ts","sourceRoot":"","sources":["../../src/server/safeOtlpSerialization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,EAAwC,KAAK,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAK1G,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAK,EAAE,SAAS,GAAE,YAA6B,UAE/F;AAkDD,eAAO,MAAM,qBAAqB,8FAUjC,CAAC"}
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import { Effect, Layer } from "effect";
|
|
2
2
|
import { OtlpSerialization } from "effect/observability";
|
|
3
|
+
import { RedactionPolicy } from "#server/RedactionPolicy.ts";
|
|
3
4
|
import { redactOtlpUrl } from "#server/redactOtlpUrl.ts";
|
|
4
5
|
import { isSensitiveKey, REDACTED, redactText } from "#server/rpc-server/sensitive.ts";
|
|
5
|
-
function sensitive
|
|
6
|
-
return
|
|
6
|
+
function otlpSensitive(sensitive) {
|
|
7
|
+
return (key) => sensitive(key) || ["db.user", "db.user.name", "db.connection_string"].includes(key.toLowerCase());
|
|
7
8
|
}
|
|
8
|
-
export function redactOtlpText(value, key = "") {
|
|
9
|
-
return redactText(redactOtlpUrl(value, key), sensitive);
|
|
9
|
+
export function redactOtlpText(value, key = "", sensitive = isSensitiveKey) {
|
|
10
|
+
return redactText(redactOtlpUrl(value, key), otlpSensitive(sensitive));
|
|
10
11
|
}
|
|
11
|
-
function attributeValue(value, key) {
|
|
12
|
+
function attributeValue(value, key, sensitive) {
|
|
12
13
|
return {
|
|
13
14
|
...value,
|
|
14
|
-
...(typeof value.stringValue === "string" ? { stringValue: redactOtlpText(value.stringValue, key) } : {}),
|
|
15
|
-
...(value.arrayValue ? { arrayValue: { values: value.arrayValue.values.map((item) => attributeValue(item, key)) } } : {}),
|
|
16
|
-
...(value.kvlistValue ? { kvlistValue: { values: attributes(value.kvlistValue.values) } } : {}),
|
|
15
|
+
...(typeof value.stringValue === "string" ? { stringValue: redactOtlpText(value.stringValue, key, sensitive) } : {}),
|
|
16
|
+
...(value.arrayValue ? { arrayValue: { values: value.arrayValue.values.map((item) => attributeValue(item, key, sensitive)) } } : {}),
|
|
17
|
+
...(value.kvlistValue ? { kvlistValue: { values: attributes(value.kvlistValue.values, sensitive) } } : {}),
|
|
17
18
|
};
|
|
18
19
|
}
|
|
19
|
-
function attributes(values) {
|
|
20
|
+
function attributes(values, sensitive) {
|
|
20
21
|
return values.map(({ key, value }) => ({
|
|
21
22
|
key,
|
|
22
|
-
value: sensitive(key) ? { stringValue: REDACTED } : attributeValue(value, key),
|
|
23
|
+
value: sensitive(key) ? { stringValue: REDACTED } : attributeValue(value, key, sensitive),
|
|
23
24
|
}));
|
|
24
25
|
}
|
|
25
26
|
function spanName(span) {
|
|
@@ -32,25 +33,35 @@ function spanName(span) {
|
|
|
32
33
|
}
|
|
33
34
|
return span.name;
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
function redactTraces(data, sensitive) {
|
|
37
|
+
function text(value) {
|
|
38
|
+
return redactOtlpText(value, "", sensitive);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
38
41
|
...data,
|
|
39
42
|
resourceSpans: data.resourceSpans.map((resource) => ({
|
|
40
43
|
...resource,
|
|
41
|
-
resource: { ...resource.resource, attributes: attributes(resource.resource.attributes) },
|
|
44
|
+
resource: { ...resource.resource, attributes: attributes(resource.resource.attributes, sensitive) },
|
|
42
45
|
scopeSpans: resource.scopeSpans.map((scope) => ({
|
|
43
46
|
...scope,
|
|
44
47
|
spans: scope.spans.map((span) => ({
|
|
45
48
|
...span,
|
|
46
|
-
attributes: attributes(span.attributes),
|
|
47
|
-
events: span.events.map((event) => ({ ...event, attributes: attributes(event.attributes), name:
|
|
48
|
-
links: span.links.map((link) => ({ ...link, attributes: attributes(link.attributes) })),
|
|
49
|
-
name:
|
|
50
|
-
status: { ...span.status, ...(span.status.message === undefined ? {} : { message:
|
|
49
|
+
attributes: attributes(span.attributes, sensitive),
|
|
50
|
+
events: span.events.map((event) => ({ ...event, attributes: attributes(event.attributes, sensitive), name: text(event.name) })),
|
|
51
|
+
links: span.links.map((link) => ({ ...link, attributes: attributes(link.attributes, sensitive) })),
|
|
52
|
+
name: text(spanName(span)),
|
|
53
|
+
status: { ...span.status, ...(span.status.message === undefined ? {} : { message: text(span.status.message) }) },
|
|
51
54
|
})),
|
|
52
55
|
})),
|
|
53
56
|
})),
|
|
54
|
-
}
|
|
55
|
-
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export const safeOtlpSerialization = Layer.effect(OtlpSerialization.OtlpSerialization, Effect.gen(function* () {
|
|
60
|
+
const serialization = yield* OtlpSerialization.OtlpSerialization;
|
|
61
|
+
const sensitive = otlpSensitive(yield* RedactionPolicy);
|
|
62
|
+
return OtlpSerialization.OtlpSerialization.of({
|
|
63
|
+
...serialization,
|
|
64
|
+
traces: (data) => serialization.traces(redactTraces(data, sensitive)),
|
|
65
|
+
});
|
|
66
|
+
}));
|
|
56
67
|
//# sourceMappingURL=safeOtlpSerialization.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safeOtlpSerialization.js","sourceRoot":"","sources":["../../src/server/safeOtlpSerialization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"safeOtlpSerialization.js","sourceRoot":"","sources":["../../src/server/safeOtlpSerialization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Rpc, type RpcGroup } from "effect/rpc";
|
|
2
|
+
export declare function schemaSensitiveKeys<R extends Rpc.Any>(group: RpcGroup.RpcGroup<R>, extra?: readonly string[]): ((key: string) => boolean) & {
|
|
3
|
+
maskFailure: (tag: string | undefined, reason: "Fail" | "Die") => boolean;
|
|
4
|
+
};
|
|
5
|
+
//# sourceMappingURL=schemaSensitiveKeys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaSensitiveKeys.d.ts","sourceRoot":"","sources":["../../src/server/schemaSensitiveKeys.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AA0GhD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,MAAM,EAAO,UAoCrF,MAAM;uBACb,MAAM,GAAG,SAAS,UAAU,MAAM,GAAG,KAAK;EAG9D"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Predicate } from "effect";
|
|
2
|
+
import { Rpc } from "effect/rpc";
|
|
3
|
+
import { isSensitiveKey } from "#server/rpc-server/sensitive.ts";
|
|
4
|
+
function children(ast) {
|
|
5
|
+
switch (ast._tag) {
|
|
6
|
+
case "Objects":
|
|
7
|
+
return [...ast.propertySignatures.map((property) => property.type), ...ast.indexSignatures.flatMap((index) => [index.parameter, index.type])];
|
|
8
|
+
case "Arrays":
|
|
9
|
+
return [...ast.elements, ...ast.rest];
|
|
10
|
+
case "Union":
|
|
11
|
+
return ast.types;
|
|
12
|
+
case "Declaration":
|
|
13
|
+
return ast.typeParameters;
|
|
14
|
+
case "Suspend":
|
|
15
|
+
return [ast.thunk()];
|
|
16
|
+
default:
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function sensitiveCheck(check) {
|
|
21
|
+
return check.annotations?.sensitive === true || (check._tag === "FilterGroup" && check.checks.some(sensitiveCheck));
|
|
22
|
+
}
|
|
23
|
+
function marked(ast, seen = new Set()) {
|
|
24
|
+
if (seen.has(ast)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
seen.add(ast);
|
|
28
|
+
if (ast.annotations?.sensitive === true
|
|
29
|
+
|| ast.context?.annotations?.sensitive === true
|
|
30
|
+
|| ast.checks?.some(sensitiveCheck)
|
|
31
|
+
|| (Predicate.hasProperty(ast.annotations?.representation, "id") && ast.annotations.representation.id === "effect/schema/Redacted")) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
const nested = ast._tag === "Objects" ? ast.indexSignatures.map((index) => index.type) : children(ast);
|
|
35
|
+
return (ast.encoding?.some((link) => marked(link.to, seen)) ?? false) || nested.some((type) => marked(type, seen));
|
|
36
|
+
}
|
|
37
|
+
function containsSensitive(ast, keys) {
|
|
38
|
+
return (marked(ast)
|
|
39
|
+
|| propertiesOf(ast).some((property) => typeof property.name === "string" && (keys.has(property.name) || isSensitiveKey(property.name))));
|
|
40
|
+
}
|
|
41
|
+
function collectEncodedKeys(ast, keys) {
|
|
42
|
+
let source = ast;
|
|
43
|
+
let sensitive = false;
|
|
44
|
+
for (const link of ast.encoding ?? []) {
|
|
45
|
+
sensitive ||= containsSensitive(source, keys);
|
|
46
|
+
if (sensitive) {
|
|
47
|
+
for (const property of propertiesOf(link.to)) {
|
|
48
|
+
if (typeof property.name === "string") {
|
|
49
|
+
keys.add(property.name);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
source = link.to;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function fixedOutput(ast) {
|
|
57
|
+
if (ast._tag === "Union") {
|
|
58
|
+
return ast.types.every(fixedOutput);
|
|
59
|
+
}
|
|
60
|
+
return ast._tag === "Objects" && ast.indexSignatures.length === 0;
|
|
61
|
+
}
|
|
62
|
+
function maskedValue(ast, keys, seen = new Set()) {
|
|
63
|
+
if (seen.has(ast)) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
seen.add(ast);
|
|
67
|
+
if (marked(ast)) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
let source = ast;
|
|
71
|
+
let sensitive = false;
|
|
72
|
+
for (const link of ast.encoding ?? []) {
|
|
73
|
+
sensitive ||= containsSensitive(source, keys);
|
|
74
|
+
if (sensitive && !fixedOutput(link.to)) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
source = link.to;
|
|
78
|
+
}
|
|
79
|
+
const nested = ast._tag === "Objects" ? ast.indexSignatures.map((index) => index.type) : children(ast);
|
|
80
|
+
return nested.some((type) => maskedValue(type, keys, seen));
|
|
81
|
+
}
|
|
82
|
+
function collect(ast, nodes, encodings = true) {
|
|
83
|
+
if (nodes.has(ast)) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
nodes.add(ast);
|
|
87
|
+
for (const child of [...children(ast), ...(encodings ? (ast.encoding?.map((link) => link.to) ?? []) : [])]) {
|
|
88
|
+
collect(child, nodes, encodings);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function propertiesOf(ast) {
|
|
92
|
+
const nodes = new Set();
|
|
93
|
+
collect(ast, nodes, false);
|
|
94
|
+
return [...nodes].flatMap((node) => (node._tag === "Objects" ? node.propertySignatures : []));
|
|
95
|
+
}
|
|
96
|
+
function collectFieldKeys(properties, keys, sensitive) {
|
|
97
|
+
for (const property of properties) {
|
|
98
|
+
if (typeof property.name === "string" && sensitive(property.type)) {
|
|
99
|
+
keys.add(property.name);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export function schemaSensitiveKeys(group, extra = []) {
|
|
104
|
+
const keys = new Set(extra);
|
|
105
|
+
const nodes = new Set();
|
|
106
|
+
const requests = [];
|
|
107
|
+
for (const rpc of group.requests.values()) {
|
|
108
|
+
if (Rpc.isRpc(rpc)) {
|
|
109
|
+
requests.push(rpc);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
for (const rpc of requests) {
|
|
113
|
+
const schemas = [
|
|
114
|
+
rpc.payloadSchema,
|
|
115
|
+
rpc.successSchema,
|
|
116
|
+
rpc.errorSchema,
|
|
117
|
+
rpc.defectSchema,
|
|
118
|
+
...[...rpc.middlewares].map((m) => m.error),
|
|
119
|
+
];
|
|
120
|
+
for (const schema of schemas) {
|
|
121
|
+
collect(schema.ast, nodes);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const properties = [...nodes].flatMap((ast) => (ast._tag === "Objects" ? ast.propertySignatures : []));
|
|
125
|
+
collectFieldKeys(properties, keys, marked);
|
|
126
|
+
let previousSize;
|
|
127
|
+
do {
|
|
128
|
+
previousSize = keys.size;
|
|
129
|
+
collectFieldKeys(properties, keys, (ast) => maskedValue(ast, keys));
|
|
130
|
+
for (const ast of nodes) {
|
|
131
|
+
collectEncodedKeys(ast, keys);
|
|
132
|
+
}
|
|
133
|
+
} while (keys.size !== previousSize);
|
|
134
|
+
const roots = requests.map((rpc) => ({
|
|
135
|
+
die: maskedValue(rpc.defectSchema.ast, keys),
|
|
136
|
+
fail: [rpc.errorSchema, ...[...rpc.middlewares].map((m) => m.error)].some((schema) => maskedValue(schema.ast, keys)),
|
|
137
|
+
tag: rpc._tag,
|
|
138
|
+
}));
|
|
139
|
+
return Object.assign((key) => keys.has(key) || isSensitiveKey(key), {
|
|
140
|
+
maskFailure: (tag, reason) => roots.some((root) => (tag === undefined || tag === root.tag) && (reason === "Fail" ? root.fail : root.die)),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=schemaSensitiveKeys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaSensitiveKeys.js","sourceRoot":"","sources":["../../src/server/schemaSensitiveKeys.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/platform",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"description": "Opinionated Effect application infrastructure for ShivaeDev services",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/platform#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@shivaedev/effect-contract": "0.6.0",
|
|
44
|
-
"@shivaedev/effect-sql": "0.
|
|
44
|
+
"@shivaedev/effect-sql": "0.8.0",
|
|
45
45
|
"@shivaedev/types": "0.2.1"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"@prisma-next/sql-orm-client": "0.16.0",
|
|
56
56
|
"@prisma-next/target-postgres": "0.16.0",
|
|
57
57
|
"@shivaedev/effect-prisma": "0.10.2",
|
|
58
|
-
"@shivaedev/effect-test-sql": "0.
|
|
58
|
+
"@shivaedev/effect-test-sql": "0.7.1",
|
|
59
59
|
"@shivaedev/effect-trpc": "0.8.2",
|
|
60
|
-
"@shivaedev/quality": "0.28.
|
|
61
|
-
"@shivaedev/test-story": "0.
|
|
60
|
+
"@shivaedev/quality": "0.28.2",
|
|
61
|
+
"@shivaedev/test-story": "0.13.0",
|
|
62
62
|
"@trpc/client": "11.19.0",
|
|
63
63
|
"@trpc/server": "11.19.0",
|
|
64
64
|
"@types/node": "24.19.2",
|
|
@@ -12,10 +12,14 @@ import { hostChanges } from "#server/hostChanges.ts";
|
|
|
12
12
|
import type { HostOptions, HostPolicy } from "#server/hostOptions.ts";
|
|
13
13
|
import type { MigrationOptions } from "#server/MigrationOptions.ts";
|
|
14
14
|
import { otlpTracing } from "#server/otlpTracing.ts";
|
|
15
|
+
import { RedactionPolicy } from "#server/RedactionPolicy.ts";
|
|
16
|
+
import { redactingDiagnostics } from "#server/redactingDiagnostics.ts";
|
|
17
|
+
import { redactingRpcSerialization } from "#server/redactingRpcSerialization.ts";
|
|
15
18
|
import { localRpcGuard } from "#server/rpc-server/local.ts";
|
|
16
19
|
import { authenticatedLayer, maybeAuthenticatedLayer, type SessionShape } from "#server/rpc-server/session.ts";
|
|
17
20
|
import { requestTracingLayer } from "#server/rpc-server/tracing.ts";
|
|
18
21
|
import { TrustedProxy } from "#server/rpc-server/trustedProxy.ts";
|
|
22
|
+
import { schemaSensitiveKeys } from "#server/schemaSensitiveKeys.ts";
|
|
19
23
|
import { tracedGroup } from "#server/tracedGroup.ts";
|
|
20
24
|
export function appHostHttp<
|
|
21
25
|
TRpcs extends Rpc.Any,
|
|
@@ -30,6 +34,7 @@ export function appHostHttp<
|
|
|
30
34
|
options: HostOptions<TRpcs, THandlers, THandlerError, THandlerRequirements, TServices, TServiceError, TServiceRequirements> & HostPolicy<TSession>,
|
|
31
35
|
changesService: typeof AppChanges,
|
|
32
36
|
) {
|
|
37
|
+
const sensitive = schemaSensitiveKeys(options.group, options.config?.sensitiveKeys);
|
|
33
38
|
return Layer.unwrap(
|
|
34
39
|
Effect.gen(function* () {
|
|
35
40
|
const maxBodySize = options.config?.maxBodySize ?? (yield* Config.Int("MAX_BODY_SIZE").pipe(Config.withDefault(1024 * 1024)));
|
|
@@ -45,12 +50,14 @@ export function appHostHttp<
|
|
|
45
50
|
}
|
|
46
51
|
const middleware: Layer.Layer<RequestTracing> | Layer.Layer<Authenticated | MaybeAuthenticated | RequestTracing> =
|
|
47
52
|
options.policy === "loopback"
|
|
48
|
-
? requestTracingLayer()
|
|
49
|
-
: Layer.mergeAll(authenticatedLayer(options.sessions), maybeAuthenticatedLayer(options.sessions), requestTracingLayer());
|
|
53
|
+
? requestTracingLayer({ sensitive })
|
|
54
|
+
: Layer.mergeAll(authenticatedLayer(options.sessions), maybeAuthenticatedLayer(options.sessions), requestTracingLayer({ sensitive }));
|
|
50
55
|
const routes = HttpRouter.use((router) =>
|
|
51
56
|
Effect.gen(function* () {
|
|
52
|
-
const wire = yield* RpcSerialization.RpcSerialization;
|
|
53
|
-
const handler = yield* RpcServer.toHttpEffect(tracedGroup(options.group))
|
|
57
|
+
const wire = redactingRpcSerialization(yield* RpcSerialization.RpcSerialization, sensitive, sensitive.maskFailure);
|
|
58
|
+
const handler = yield* RpcServer.toHttpEffect(tracedGroup(options.group)).pipe(
|
|
59
|
+
Effect.provideService(RpcSerialization.RpcSerialization, wire),
|
|
60
|
+
);
|
|
54
61
|
const guarded = localRpcGuard(handler, trustedProxy);
|
|
55
62
|
yield* router.add("POST", options.rpcPath ?? "/rpc", (request) =>
|
|
56
63
|
guarded.pipe(
|
|
@@ -88,7 +95,7 @@ export function appHostHttp<
|
|
|
88
95
|
Layer.provide(NodeServices.layer),
|
|
89
96
|
);
|
|
90
97
|
}),
|
|
91
|
-
).pipe(Layer.provide(otlpTracing));
|
|
98
|
+
).pipe(Layer.provide(redactingDiagnostics(sensitive)), Layer.provide(otlpTracing), Layer.provide(Layer.succeed(RedactionPolicy, sensitive)));
|
|
92
99
|
}
|
|
93
100
|
|
|
94
101
|
export function migratedHost<
|
|
@@ -11,6 +11,7 @@ export type HostOptions<TRpcs extends Rpc.Any, THandlers, THandlerError, THandle
|
|
|
11
11
|
readonly host?: string;
|
|
12
12
|
readonly trustedProxy?: string;
|
|
13
13
|
readonly maxBodySize?: number;
|
|
14
|
+
readonly sensitiveKeys?: readonly string[];
|
|
14
15
|
readonly disablePreemptiveShutdown?: boolean;
|
|
15
16
|
};
|
|
16
17
|
readonly group: RpcGroup.RpcGroup<TRpcs>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Effect, Layer } from "effect";
|
|
2
2
|
import { FetchHttpClient, HttpClient, HttpClientError, type HttpClientRequest } from "effect/http";
|
|
3
|
+
import { RedactionPolicy } from "#server/RedactionPolicy.ts";
|
|
3
4
|
import { redactOtlpText } from "#server/safeOtlpSerialization.ts";
|
|
4
5
|
|
|
5
6
|
function timeoutError(request: HttpClientRequest.HttpClientRequest) {
|
|
@@ -13,6 +14,7 @@ export function otlpHttpClient(timeout = 10_000) {
|
|
|
13
14
|
HttpClient.HttpClient,
|
|
14
15
|
Effect.gen(function* () {
|
|
15
16
|
const client = yield* HttpClient.HttpClient;
|
|
17
|
+
const sensitive = yield* RedactionPolicy;
|
|
16
18
|
let warned = false;
|
|
17
19
|
function warnOnce(diagnostic: Effect.Effect<Record<string, unknown>>) {
|
|
18
20
|
return Effect.suspend(() => {
|
|
@@ -41,7 +43,7 @@ export function otlpHttpClient(timeout = 10_000) {
|
|
|
41
43
|
return warnOnce(
|
|
42
44
|
response.text.pipe(
|
|
43
45
|
Effect.orElseSucceed(() => "Unable to read collector response"),
|
|
44
|
-
Effect.map((body) => ({ "otlp.response": redactOtlpText(body), "otlp.status": response.status })),
|
|
46
|
+
Effect.map((body) => ({ "otlp.response": redactOtlpText(body, "", sensitive), "otlp.status": response.status })),
|
|
45
47
|
),
|
|
46
48
|
);
|
|
47
49
|
}),
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Config, Effect, Layer, Schema } from "effect";
|
|
2
2
|
import { OtlpSerialization, OtlpTracer } from "effect/observability";
|
|
3
3
|
import { otlpHttpClient } from "#server/otlpHttpClient.ts";
|
|
4
|
+
import { RedactionPolicy } from "#server/RedactionPolicy.ts";
|
|
5
|
+
import { redactingTracer } from "#server/redactingTracer.ts";
|
|
4
6
|
import { safeOtlpSerialization } from "#server/safeOtlpSerialization.ts";
|
|
5
7
|
|
|
6
8
|
export const otlpTracing: Layer.Layer<never, Config.ConfigError> = Layer.unwrap(
|
|
@@ -41,7 +43,7 @@ export const otlpTracing: Layer.Layer<never, Config.ConfigError> = Layer.unwrap(
|
|
|
41
43
|
const exportInterval = yield* Config.Int("OTEL_BSP_SCHEDULE_DELAY").pipe(Config.withDefault(5000));
|
|
42
44
|
const maxBatchSize = yield* Config.Int("OTEL_BSP_MAX_EXPORT_BATCH_SIZE").pipe(Config.withDefault(1000));
|
|
43
45
|
const exportTimeout = yield* Config.Int("OTEL_BSP_EXPORT_TIMEOUT").pipe(Config.withDefault(3000));
|
|
44
|
-
|
|
46
|
+
const tracer = OtlpTracer.layer({
|
|
45
47
|
exportInterval,
|
|
46
48
|
headers,
|
|
47
49
|
maxBatchSize,
|
|
@@ -54,5 +56,6 @@ export const otlpTracing: Layer.Layer<never, Config.ConfigError> = Layer.unwrap(
|
|
|
54
56
|
),
|
|
55
57
|
Layer.provide(otlpHttpClient(requestTimeout)),
|
|
56
58
|
);
|
|
59
|
+
return redactingTracer(yield* RedactionPolicy).pipe(Layer.provideMerge(tracer));
|
|
57
60
|
}),
|
|
58
61
|
);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Context, Effect, ErrorReporter, Layer, Logger, References } from "effect";
|
|
2
|
+
import { redact } from "#server/rpc-server/redact.ts";
|
|
3
|
+
import { redactDiagnosticCause, redactingErrorReporter } from "#server/rpc-server/redactCause.ts";
|
|
4
|
+
import type { SensitiveKey } from "#server/rpc-server/sensitive.ts";
|
|
5
|
+
|
|
6
|
+
export function redactRecord(values: Readonly<Record<string, unknown>>, sensitive: SensitiveKey): Record<string, unknown> {
|
|
7
|
+
return Object.fromEntries(Object.entries(values).map(([key, value]) => [key, sensitive(key) ? "<redacted>" : redact(value, sensitive)]));
|
|
8
|
+
}
|
|
9
|
+
export function redactingDiagnostics(sensitive: SensitiveKey) {
|
|
10
|
+
return Layer.effectContext(
|
|
11
|
+
Effect.gen(function* () {
|
|
12
|
+
const loggers = yield* Logger.CurrentLoggers;
|
|
13
|
+
const reporters = yield* ErrorReporter.CurrentErrorReporters;
|
|
14
|
+
const safeLoggers = new Set(
|
|
15
|
+
[...loggers].map((logger) =>
|
|
16
|
+
Logger.make((options) => {
|
|
17
|
+
const context = options.fiber.context;
|
|
18
|
+
const annotations = redactRecord(options.fiber.getRef(References.CurrentLogAnnotations), sensitive);
|
|
19
|
+
options.fiber.setContext(Context.add(context, References.CurrentLogAnnotations, annotations));
|
|
20
|
+
try {
|
|
21
|
+
return logger.log({ ...options, cause: redactDiagnosticCause(options.cause, sensitive), message: redact(options.message, sensitive) });
|
|
22
|
+
} finally {
|
|
23
|
+
options.fiber.setContext(context);
|
|
24
|
+
}
|
|
25
|
+
}),
|
|
26
|
+
),
|
|
27
|
+
);
|
|
28
|
+
return Context.make(Logger.CurrentLoggers, safeLoggers).pipe(
|
|
29
|
+
Context.add(ErrorReporter.CurrentErrorReporters, new Set([...reporters].map((reporter) => redactingErrorReporter(reporter, sensitive)))),
|
|
30
|
+
);
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Predicate } from "effect";
|
|
2
|
+
import type { RpcSerialization } from "effect/rpc";
|
|
3
|
+
import { redactWire } from "#server/rpc-server/redact.ts";
|
|
4
|
+
import { REDACTED, type SensitiveKey } from "#server/rpc-server/sensitive.ts";
|
|
5
|
+
|
|
6
|
+
function isRequestId(value: unknown): value is string | number {
|
|
7
|
+
return typeof value === "string" || typeof value === "number";
|
|
8
|
+
}
|
|
9
|
+
export function redactingRpcSerialization(
|
|
10
|
+
wire: RpcSerialization.RpcSerialization["Service"],
|
|
11
|
+
sensitive: SensitiveKey,
|
|
12
|
+
maskFailure: (tag: string | undefined, reason: "Fail" | "Die") => boolean = () => false,
|
|
13
|
+
): typeof wire {
|
|
14
|
+
function reason(value: unknown, tag: string | undefined): unknown {
|
|
15
|
+
const redacted = redactWire(value, sensitive);
|
|
16
|
+
if (Predicate.isObjectOrArray(redacted)) {
|
|
17
|
+
if (Predicate.isTagged(value, "Fail") && maskFailure(tag, "Fail")) {
|
|
18
|
+
return { ...redacted, _tag: "Fail", error: REDACTED };
|
|
19
|
+
}
|
|
20
|
+
if (Predicate.isTagged(value, "Die") && maskFailure(tag, "Die")) {
|
|
21
|
+
return { ...redacted, _tag: "Die", defect: REDACTED };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (
|
|
25
|
+
(Predicate.isTagged(value, "Fail") || Predicate.isTagged(value, "Die") || Predicate.isTagged(value, "Interrupt"))
|
|
26
|
+
&& Predicate.isObjectOrArray(redacted)
|
|
27
|
+
) {
|
|
28
|
+
return { ...redacted, _tag: value._tag };
|
|
29
|
+
}
|
|
30
|
+
return redacted;
|
|
31
|
+
}
|
|
32
|
+
function exit(value: unknown, tag: string | undefined): unknown {
|
|
33
|
+
if (Predicate.isTagged(value, "Failure") && Predicate.hasProperty(value, "cause")) {
|
|
34
|
+
const cause = Array.isArray(value.cause) ? value.cause.map((item) => reason(item, tag)) : redactWire(value.cause, sensitive);
|
|
35
|
+
return { ...value, cause };
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
...wire,
|
|
41
|
+
makeUnsafe: () => {
|
|
42
|
+
const parser = wire.makeUnsafe();
|
|
43
|
+
const requests = new Map<string | number, string>();
|
|
44
|
+
function response(value: unknown): unknown {
|
|
45
|
+
if (Array.isArray(value)) {
|
|
46
|
+
return value.map(response);
|
|
47
|
+
}
|
|
48
|
+
if (Predicate.isTagged(value, "Defect") && Predicate.hasProperty(value, "defect")) {
|
|
49
|
+
return { ...value, defect: maskFailure(undefined, "Die") ? REDACTED : redactWire(value.defect, sensitive) };
|
|
50
|
+
}
|
|
51
|
+
if (
|
|
52
|
+
Predicate.isTagged(value, "Exit")
|
|
53
|
+
&& Predicate.hasProperty(value, "requestId")
|
|
54
|
+
&& isRequestId(value.requestId)
|
|
55
|
+
&& Predicate.hasProperty(value, "exit")
|
|
56
|
+
) {
|
|
57
|
+
const tag = requests.get(value.requestId);
|
|
58
|
+
requests.delete(value.requestId);
|
|
59
|
+
return { ...value, exit: exit(value.exit, tag) };
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
...parser,
|
|
65
|
+
decode: (data) => {
|
|
66
|
+
const decoded = parser.decode(data);
|
|
67
|
+
for (const request of decoded) {
|
|
68
|
+
if (
|
|
69
|
+
Predicate.isTagged(request, "Request")
|
|
70
|
+
&& Predicate.hasProperty(request, "id")
|
|
71
|
+
&& isRequestId(request.id)
|
|
72
|
+
&& Predicate.hasProperty(request, "tag")
|
|
73
|
+
&& typeof request.tag === "string"
|
|
74
|
+
&& !requests.has(request.id)
|
|
75
|
+
) {
|
|
76
|
+
requests.set(request.id, request.tag);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return decoded;
|
|
80
|
+
},
|
|
81
|
+
encode: (value) => parser.encode(response(value)),
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Effect, Exit, Layer, Tracer } from "effect";
|
|
2
|
+
import { redactRecord } from "#server/redactingDiagnostics.ts";
|
|
3
|
+
import { redact } from "#server/rpc-server/redact.ts";
|
|
4
|
+
import { redactDiagnosticCause } from "#server/rpc-server/redactCause.ts";
|
|
5
|
+
import { REDACTED, type SensitiveKey } from "#server/rpc-server/sensitive.ts";
|
|
6
|
+
|
|
7
|
+
function redactLinks(values: readonly Tracer.SpanLink[], sensitive: SensitiveKey) {
|
|
8
|
+
return values.map((link) => ({ ...link, attributes: redactRecord(link.attributes, sensitive) }));
|
|
9
|
+
}
|
|
10
|
+
function redactSpan(span: Tracer.Span, sensitive: SensitiveKey) {
|
|
11
|
+
const end = span.end.bind(span);
|
|
12
|
+
const attribute = span.attribute.bind(span);
|
|
13
|
+
const event = span.event.bind(span);
|
|
14
|
+
const addLinks = span.addLinks.bind(span);
|
|
15
|
+
return Object.assign(span, {
|
|
16
|
+
addLinks: (values: readonly Tracer.SpanLink[]) => addLinks(redactLinks(values, sensitive)),
|
|
17
|
+
attribute: (key: string, value: unknown) => attribute(key, sensitive(key) ? REDACTED : redact(value, sensitive)),
|
|
18
|
+
end: (time: bigint, exit: Exit.Exit<unknown, unknown>) => {
|
|
19
|
+
for (const [key, value] of span.attributes) {
|
|
20
|
+
attribute(key, sensitive(key) ? REDACTED : redact(value, sensitive));
|
|
21
|
+
}
|
|
22
|
+
end(time, Exit.isFailure(exit) ? Exit.failCause(redactDiagnosticCause(exit.cause, sensitive)) : exit);
|
|
23
|
+
},
|
|
24
|
+
event: (name: string, time: bigint, attributes?: Record<string, unknown>) => event(name, time, attributes && redactRecord(attributes, sensitive)),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export function redactingTracer(sensitive: SensitiveKey) {
|
|
28
|
+
return Layer.effect(
|
|
29
|
+
Tracer.Tracer,
|
|
30
|
+
Effect.map(Tracer.Tracer, (tracer) =>
|
|
31
|
+
Tracer.make({
|
|
32
|
+
...tracer,
|
|
33
|
+
span: (options) => redactSpan(tracer.span({ ...options, links: redactLinks(options.links, sensitive) }), sensitive),
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect, Option } from "effect";
|
|
2
|
-
import { HttpServerRequest, HttpServerResponse } from "effect/http";
|
|
2
|
+
import { HttpServerRequest, HttpServerResponse, HttpTraceContext } from "effect/http";
|
|
3
3
|
import { RpcSerialization } from "effect/rpc";
|
|
4
4
|
import { proxyAddresses, proxyMatches, proxyRanges } from "./trustedProxy.ts";
|
|
5
5
|
|
|
@@ -72,7 +72,16 @@ export function localRpcGuard<E, R>(effect: Effect.Effect<HttpServerResponse.Htt
|
|
|
72
72
|
const local = loopbackHost(request.headers.host) && Option.exists(request.remoteAddress, loopbackAddress);
|
|
73
73
|
const contentType = request.headers["content-type"]?.split(";")[0]?.trim().toLowerCase();
|
|
74
74
|
return ((local && sameOrigin(request)) || proxyOrigin(request, isTrustedProxy)) && contentType === serialization.contentType
|
|
75
|
-
? yield* effect
|
|
75
|
+
? yield* continueHttpTrace(effect, request)
|
|
76
76
|
: HttpServerResponse.text("Local same-origin requests only", { status: 403 });
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
|
+
|
|
80
|
+
const continueHttpTrace = Effect.fnUntraced(function* <A, E, R>(effect: Effect.Effect<A, E, R>, request: HttpServerRequest.HttpServerRequest) {
|
|
81
|
+
const incoming = HttpTraceContext.w3c(request.headers);
|
|
82
|
+
if (Option.isNone(incoming)) {
|
|
83
|
+
return yield* effect;
|
|
84
|
+
}
|
|
85
|
+
const parent = Option.getOrElse(yield* Effect.option(Effect.currentParentSpan), () => incoming.value);
|
|
86
|
+
return yield* Effect.withParentSpan(effect, parent);
|
|
87
|
+
});
|